I found out that searches in urlscan can be made with regexes so I went hunting something special and got rewarded with a multistage loader for an infostealer. The following sections show, how I looked at the sample and found out step after step what the true intention of this sample is.
As already mentioned I went searching for some interesting files
page.url.keyword:/.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(:[0-9]+)?\/.*\.(msi|zip|rar|lnk|scr|exe|sh|ps1|js|txt)/ AND NOT page.title.keyword:/.*(404|not found|403|forbidden).*/ AND stats.dataLength:>0 AND NOT stats.dataLength:[170000 TO 193000]

Downloaded the file which is meant for “sarahh” called ENCRYPTED.ps1 (sha256: a4f76092ea71e5b746ad33d7264bc2b649780a53c7c5b593079b27e4d3e0966c), I took this one as I expected it to hold most information, as it was the biggest. It’s visible, that there is multiple files in different directories. I didn’t look at the other ENCRYPTED.ps1 payloads nor at the js file (sha256: e4531cf40f8742c8d3433267b921a79409439c62d60648fed5682c3b4e643cdd) as it’s heavily obfuscated and I prefer quick-wins over deobfuscation struggles if I can choose.
After an look at the code of the file under investigation it was clear real fast, that this is not going to be the end of my evening ๐ . It holds a payload (as I was hoping for) which is encrypted and run directly on executiuon. I extracted the payload with a little decryption (AES) script, everything was hardcoded in the original code so it was not a big deal. The resulting output is yet another powershell script (sha256: e29a7d60a1683cfbf810324b90d65edf87399f593b613a7edd933f574830d905).
Inside this script there is a base64-encoded dll, which I easily extracted using cyberchef and the download functionality. The resulting .dll is directly loaded at runtime and called, first without a parameter and then with a big execution payload (2.4mb bytes, payload, more to that later after we looked at the assembly which is loaded).
The following code is a 1:1 copy from the resulting dll and shows how the payload is called.
# Execute the assembly method
$executionResult = Invoke-ManagedAssembly
-RawAssemblyBytes $decodedAssemblyBytes
-TargetTypeName 'MAFFIA.ProcessHollowing'
-TargetMethodName 'Execute'
-MethodArguments $invocationParameters
The execution payload is initially empty but the target-process is already defined statically. It is C:\Windows\Microsoft.NET\Framework\v4.0.30319\Aspnet_compiler.exe. This is the target process, which is hollowed (and injected), more to that in the next section.
The ProcessHollowing functionality
I looked at the dll first to see how it is looking. It was obfuscated so I gave de4dot a try which made it a bit better. The problem with these dynamic loadings of such libraries is that the initial class and member name has to be known beforehand and therefore can’t be obfuscated. Funnily enough that the attacker, in this case, uses SUCH an obvious name…

I looked at the function which is called from the powershell script (see above). It calls MAFFIA.ProcessHollowing.Execute()-function. So I went to see, what this function does:
- Once the payload is given to the function (after a first loop and 5 sec waiting)
- The process identified above (
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Aspnet_compiler.exe) is created in suspended state. (CREATE_SUSPENDED– flag) - Sections of the aspnet_compiler.exe legitimate binary are unmapped (
NtUnmapViewOfSection) - Memory regarding the size of the payload is allocated in the suspended process (
AllocateMemory) - The payload is written into the allocated region. (
WriteProcessMemory) - Process base address is set to match the binary injected.
- ThreadContext is set to the modified values
- Process is resumed. (
ResumeThread)
After initial hesitation about the payload, I found out it’s not encrypted and the strange execution flow in the binary is just caused by the obfuscation. So if you see a byte-array starting with 77,90,144,0 -> its an MZ-header
I made a small helper script, which converts me the bytes into a file:
payload = [<the bytes identified>]
# Write bytes to file
output_file = "payload.bin"
with open(output_file, 'wb') as f:
f.write(bytes(payload))
print(f"\n[+] Payload written to: {output_file}")
print(f"[+] File size: {len(payload)} bytes")
So we end up with hopefully the finally payload which we’re looking at now.
Final Payload
The final payload is now residing on disk as payload.bin (sha256: 904a3d70be9fccbd1d04cdc90d20e430351f16696d3ba2e14400f31f2437c133). This time, the program is not obfuscated at all and reveals all it’s details in cleartext. I checked it first again, as usual with Malcat. This already gave me indicators of several stealers. Also the string listing shows a lot of stealer related strings, aswell as a quiet some AntiAnalysis strings. So I was interested in what it holds for me.
The Config Class
The config class often holds a wealth of information, such as C2 urls, api endpoints or messenger URLs to deliver the stolen information to. It is not different in this sample but there is one problem, the strings for these information are encrypted. But fortunately there is a fitting method which guides us directly to the decryption of the values (StringsCrypt.DecryptConfig() ):

The decryption does AES decryption and my helper claude created a small script in 10 seconds to decrypt everything. Unfortunately, a lot of the strings are useless, because the CheckBox (which is a hardcoded value in the code) is not set and the strings don’t decrypt to anything.
The Smtp details seem to be in use though and so I’ll add them to the IOC section at the end of this post.
Another easy win is the mutex it creates, to check if it’s running already, this value is hardcoded in the config and I also added it in the IOC section.
The Functionality
As already mentioned, the payload we’re looking at is an infostealer. If we’re believing malcats’ attribution, it’s PhantomStealer. I don’t know anything about this stealer so I let it stand like this. More important is, what this stealer can do. It holds functionality to:
- Steal browser information
- Steal crypto Wallet information
- Typed texts (Keylogger capabilities) transmission
- Take screenshots
- Inject additional payloads into selected processes
- Read the clipboard
- Send data to Telegram, Discord, FTP and SMTP
- Inject Shellcode via Heavens Gate Injection technique (implemented but not used in this sample)
- Inject Shellcode or DLL with standard injection ways.
In the anti analysis functionality it checks following domains for certain indicators (which I don’t mention all here as it’s a ton):
- Usernames (140 distinct)
- PC names (110 distinct)
- GPUs (80 distinct)
- Running processes (VmRemoteGuest.exe and Sysmon64.exe)
- Services (6 different)
- IP’s (200 from all over the globe)
- Machine GUIDs
- Checks for sleep tick drifts caused by virtualization
Last but not least, there is also persistence functionality. This holds some more indicators. The actual binaries name is extracted from the running binary. This is then combined with C:\Users\<username>\AppData\Roaming and added to the run key of the registry hive (SOFTWARE\Microsoft\Windows\CurrentVersion\Run)
IOCs
| Type | Value |
| Smtp Server | mail.polywin.co.in |
| Smtp Port | 587 |
| Smtp Sender | az@polywin.co.in |
| Smtp Password | office2026Usd$ |
| Smtp Receiver | office@infroyale.com |
| Mutex | PHTKFN2EQRWVHV8VC14M |
Take care and keep on hunting!
R4ruk
