PhantomStealer: 25 Samples From an Automated Builder, a 5-Layer Kill Chain, and a Burned Telegram Bot Targeting Maritime and Industrial Sectors
TL;DR: PhantomStealer is a C#/.NET infostealer campaign active since at least February 26, 2026, distributing 25 tracked samples via an automated builder that stamps each payload with unique XOR keys, PE GUIDs, and obfuscated class names while maintaining an identical framework skeleton. The campaign targets maritime shipping and industrial supply chain organizations through social-engineered JavaScript droppers disguised as port agency appointments and spare parts requisitions. A five-layer execution chain -- JS dropper, PowerShell with rotational XOR decryption, .NET reflection loading, process hollowing into Aspnet_compiler.exe -- delivers the final stealer, which exfiltrates browser credentials, crypto wallets, Outlook profiles, and WiFi passwords to a Telegram bot. We extracted the bot token and chat ID from sandbox telemetry. The bot is now dead. The chat ID is forever.
The Lures: Port Appointments and Spare Parts
Two JavaScript files showed up on MalwareBazaar within 18 hours of each other on March 9-10, reported by two of the most prolific malware hunters in the community -- James_inthe_box and pr0xylife. On the surface, they look like routine business documents:
PDA Query - 180397-03-010-26 Port Agency Appointment.jsRF-PUB802 Spare Parts Requisition.xlsx.js
The first is a PDA query -- a Proforma Disbursement Account document used in maritime shipping to estimate port call costs. If you work in a port agency, a shipping line, or a freight forwarder, this is something you open without thinking twice. The second uses an RF-PUB document code that evokes defense and government procurement nomenclature, paired with the classic double-extension trick: .xlsx.js. On any Windows machine with default settings, the .js extension is hidden, and the file looks like an Excel spreadsheet.
These are not generic lures. Someone picked filenames that would pass the smell test in specific industries.
| Attribute | Sample 1 (Industrial) | Sample 2 (Maritime) |
|---|---|---|
| File Name | RF-PUB802 Spare Parts Requisition.xlsx.js | PDA Query - 180397-03-010-26 Port Agency Appointment.js |
| SHA-256 | ffc7a508...7560d0 | c08f0093...1609 |
| Size | 4,640,410 bytes | 4,604,727 bytes |
| First Seen | 2026-03-10 09:51:31 UTC | 2026-03-09 15:30:02 UTC |
| Reporter | pr0xylife | James_inthe_box |
| Origin | Denmark | United States |
Denmark and the US. Two major maritime nations. Coincidence? Probably not.
Inside the Dropper: 747 Strings and a State Machine
Both JS droppers clock in at roughly 4.4 MB each -- enormous for a JavaScript file. The bulk of that size is an obfuscation framework built around a string lookup table. Sample 1 uses an array called HO with 747 entries. Sample 2 uses a different variable name but the same structure. Accessor functions J and K dereference the table by hex index, and Windows API strings are fragmented across multiple array entries to defeat static signature matching.
The control flow is wrapped in a switch-case state machine -- while(true) { switch(k0[k1++]) -- that makes linear analysis painful. There is an anti-debugging check using a catastrophic backtracking regex ((((.+)+)+)) designed to hang regex-based sandboxes, and a WMI anti-sandbox query hitting winmgmts:\\.\root\cimv2 to look for Win32_Process artifacts.
When the dropper decides it is not being watched, the actual execution is straightforward:
- Extract a base64-encoded PowerShell payload from the string table (index
[554]in Sample 1) - Write it to
C:\Temp\ps_[random].ps1 - Execute with
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NoLogo - Drop a
.lnkshortcut named "SystemUpdate" in the Startup folder - Write a registry Run key under
HKLM\Software\Microsoft\Windows\CurrentVersion\Run - Set up a WMI process termination monitor to re-execute if the payload dies
That is layers 1 and 2 of persistence before the stealer even loads.
The Five-Layer Kill Chain
This is where PhantomStealer gets interesting. Most commodity stealers use two or three stages. This campaign uses five, and each layer serves a distinct evasion purpose:
[1] JS DROPPER [2] POWERSHELL [3] ROTATIONAL XOR
.xlsx.js double extension -ExecutionPolicy Bypass 32-byte key per sample
747-entry string table -WindowStyle Hidden Position-dependent rotation
Anti-debug + anti-sandbox Writes to C:\Temp\ Mod 7 state cycle
Base64 decode first
| | |
v v v
[4] .NET REFLECTION [5] PROCESS INJECTION [6] EXFILTRATION
Assembly::Load() in-memory SetThreadContext Telegram Bot API
DEV.DOWN.SHOOT() entry Aspnet_compiler.exe target sendMessage endpoint
AES-encrypted resources WriteProcessMemory hollowing Chat ID 5229075943
GUID-keyed resource lookup Fody packer obfuscation Bot token extracted
Layer 1 (JS) defeats email gateways and web filters. Layer 2 (PowerShell) bypasses script execution policies. Layer 3 (Rotational XOR) defeats static analysis of the encrypted payload. Layer 4 (.NET reflection) keeps the loader entirely in memory -- never touches disk. Layer 5 (process injection) hides inside a legitimate Windows binary. By the time the actual stealer code runs, it is executing inside Aspnet_compiler.exe -- a signed Microsoft .NET compilation tool that no EDR is going to flag by default.
Stage 3: A Custom XOR That Is Slightly Clever
The PowerShell stage does not use standard XOR. It uses what the framework itself calls a "Multi-Stage Rotational XOR Decryption Framework" -- and while the name is grandiose, the algorithm is genuinely a step above the basic repeating-key XOR that dominates commodity malware.
Each sample gets a unique 32-byte key. The decryption works like this:
rotationTracker = 0
for each byte at position i:
keyPos = (i + rotationTracker) % keyLength
plaintext[i] = ciphertext[i] XOR key[keyPos]
rotationTracker = (rotationTracker + key[keyPos]) % 7
The rotationTracker introduces positional dependency -- the key byte used for position i depends on the cumulative value of all previous key bytes used, modulo 7. This creates a 7-state cycle that shifts the key alignment unpredictably. It is not cryptographically strong, but it is enough to break tools that assume simple repeating XOR, and each sample's unique key means you cannot write a single static decryptor.
| Sample | XOR Key (Base64) | XOR Key (Hex) |
|---|---|---|
| 1 (Industrial) | 98ZPm8ouUY39gnhZcAphIyIRsdxHquPKcQjPpsx8JYs= | f7c64f9bca2e518d... |
| 2 (Maritime) | JR8JNwOMbHU6IZOiiATJHG+h/8yLrJSLgYR1qkr3nIg= | 251f0937038c6c75... |
Different keys. Same algorithm. Same framework structure. This is the fingerprint of an automated builder.
Stage 4: DEV.dll and the GUID-Keyed Resource System
After XOR decryption, the PowerShell stage loads a .NET DLL via [System.Reflection.Assembly]::Load() and calls the static method DEV.DOWN.SHOOT(). Both analyzed DLLs share the same naming -- DEV.dll, DEV.pdb, DEV.DOWN.SHOOT() entry point -- but have different SHA-256 hashes, different sizes, and different embedded resource encryption keys.
| Attribute | Sample 1 DLL | Sample 2 DLL |
|---|---|---|
| SHA-256 | e5e8ec1e...0e88b335 | 1c5c15bb...1028f74 |
| Size | 47,104 bytes | 46,592 bytes |
| Framework | .NET 4.5.1 | .NET 4.5.1 |
| Copyright | 2026 | 2026 |
The DLLs use AES-encrypted resources keyed by GUID-style identifiers:
{11111-22222-10009-11112}
{11111-22222-20001-00001} / {11111-22222-20001-00002}
{11111-22222-30001-00001} / {11111-22222-30001-00002}
{11111-22222-40001-00001} / {11111-22222-40001-00002}
{11111-22222-50001-00000} / {11111-22222-50001-00001} / {11111-22222-50001-00002}
The sequential numbering pattern (10009, 20001, 30001, 40001, 50001) suggests these are builder-assigned identifiers, not random values. Each GUID maps to an AES-encrypted resource blob containing the next stage payload. The runtime API resolution uses GetDelegateForFunctionPointer to dynamically resolve injection APIs, avoiding static import table analysis.
The "Copyright 2026" metadata is a minor but useful detail -- it pins the compilation timeline to this year and confirms these are fresh builds, not repackaged older payloads.
25 Samples and the Builder Hypothesis
Here is the part that elevates this from "another infostealer" to "a campaign worth tracking."
Between February 26 and March 10, we identified 25 distinct PhantomStealer samples:
| Date | Samples | Type | Notes |
|---|---|---|---|
| Feb 26 | 1 | EXE | Earliest known (ANY.RUN sandbox) |
| Mar 6 | 21 | EXE | Bulk upload to MalwareBazaar (reporter: adrian__luca) |
| Mar 8 | 2 | JS | Additional dropper variants |
| Mar 9 | 1 | JS | Maritime theme (PDA Query) |
| Mar 10 | 1 | JS | Industrial theme (Spare Parts) |
Twenty-one EXE payloads uploaded on a single day by the same reporter. That is not an analyst who stumbled onto one sample and pivoted. That is someone who found a distribution server or a builder output directory.
Every sample we analyzed shows the same pattern: identical framework structure, identical execution chain, identical DEV.dll / DEV.DOWN.SHOOT() naming convention -- but unique XOR keys, unique PE GUIDs, unique obfuscated class names. The shared imphash f34d5f2d4577ed6d9ceec516c1f5a744 across EXE payloads further confirms they were compiled from the same source with the same import table structure.
This is an automated builder. The operator (or their MaaS provider) has a tool that stamps out PhantomStealer payloads with per-sample cryptographic parameters while keeping the execution framework constant. It is the malware equivalent of a factory production line.
What the Stealer Actually Steals
Based on Triage, ANY.RUN, and Kaspersky sandbox behavioral analysis, the final PhantomStealer payload running inside Aspnet_compiler.exe targets:
- Browser credentials -- Chrome, Firefox, Edge, Opera, Brave (saved passwords, cookies, autofill)
- Cryptocurrency wallet extensions -- a "considerable number" of browser extension IDs (per ditekSHen YARA)
- Microsoft Outlook profiles -- both the Office registry path and the Windows registry path
- Wireless network passwords -- via
netsh WLAN profile export - System reconnaissance -- processor info, registry enumeration, external IP lookup via web service
The WiFi password exfiltration is a nice touch. Most stealers skip it. Having a victim's WiFi credentials is useful for physical proximity attacks or for correlating the victim's location with other compromised data.
Telegram C2: Simple, Effective, Burned
PhantomStealer uses Telegram as its sole exfiltration channel. No traditional C2 server. No domain. No IP address to track. Just a Telegram bot.
Bot Token: 8593007332:AAEPMJO3zv4YVgEOImh_tZhHp0aSBYcyt8g
Chat ID: 5229075943
Endpoint: hxxps://api[.]telegram[.]org/bot8593007332:.../sendMessage?chat_id=5229075943
This is a significant OPSEC advantage. There is no server to be taken down by a hosting provider. No domain to be sinkholed. Telegram provides end-to-end infrastructure -- encryption, delivery, availability -- and bot tokens can be rotated in minutes if one gets burned.
The bot token was extracted from Triage sandbox behavioral analysis, and as of March 10, the bot responds with "Logged out." The operator either noticed the exposure and killed the bot, or Telegram shut it down. Either way, the token is dead.
But the chat ID 5229075943 is permanent. That number is tied to the operator's Telegram account. Even if they create a hundred new bots, the chat ID persists. It is the kind of identifier that does not go away, and it is the kind of detail that matters when this operator resurfaces with a new bot token next week.
OPSEC Scorecard
The operator is not sloppy, but they are not elite either:
| OPSEC Decision | Assessment |
|---|---|
| Telegram C2 (no server to track) | Smart |
| Per-sample unique crypto keys | Smart |
| 5-layer execution chain | Smart |
| Sandbox/VM detection checks | Standard |
| Bot token exposed via sandbox analysis | Burned |
Chat ID 5229075943 now permanent IOC | Burned |
| "Copyright 2026" in PE metadata | Careless |
Consistent DEV.dll / SHOOT() naming | Weak -- strong clustering signal |
| Shared imphash across all EXE payloads | Weak -- trivial to pivot on |
The shared .NET crypter/packer ecosystem (Fody packer, same imphash as AsyncRAT/QuasarRAT/AgentTesla families) strongly suggests the operator is a customer of a Malware-as-a-Service crypter, not the developer. They are buying the evasion layers and plugging in their own stealer.
Vendor Detection and Attribution
The security industry is still catching up to PhantomStealer. Detection rates are mixed, and attribution is scattered:
| Vendor | Detection | Notes |
|---|---|---|
| Triage | phantom_stealer (10/10) | Best classification |
| Kaspersky | Multiple detections (14+) | Trojan-PSW.MSIL.Stealerium, Trojan-Downloader.Script.Generic |
| ReversingLabs | ByteCode-MSIL.Trojan.Redlinestealer (70.83%) | Misattributed as RedLine |
| Intezer | KeyBase (malicious) | Code overlap detection |
| VMRay | PhantomStealer (malicious) | Correct family ID |
| ANY.RUN | Malicious activity | Tags: phantom, stealer, crypto-regex, evasion |
| FileScan-IO | LIKELY_MALICIOUS (0.75 confidence) | Low confidence |
The Intezer "KeyBase" and ReversingLabs "RedLine" classifications are worth noting. Code overlap with KeyBase and RedLine does not mean this is those families -- it means PhantomStealer likely reuses code from the same .NET stealer ecosystem. That is consistent with the MaaS model: the builder probably incorporates proven modules from multiple stealer families.
MITRE ATT&CK Mapping
| Tactic | Technique | ID | Implementation |
|---|---|---|---|
| Initial Access | Spearphishing Attachment | T1566.001 | JS file with social engineering filename |
| Execution | JavaScript | T1059.007 | WScript execution of .js dropper |
| Execution | PowerShell | T1059.001 | Bypass/Hidden execution flags |
| Execution | Malicious File | T1204.002 | Double-extension .xlsx.js trick |
| Persistence | Registry Run Keys | T1547.001 | HKLM Run key |
| Persistence | Shortcut Modification | T1547.009 | Startup folder .lnk |
| Defense Evasion | Deobfuscate/Decode | T1140 | Multi-stage XOR, Base64, AES |
| Defense Evasion | Obfuscated Files | T1027 | JS string table, Fody packer |
| Defense Evasion | Process Injection | T1055 | SetThreadContext into Aspnet_compiler.exe |
| Defense Evasion | Reflective Code Loading | T1620 | Assembly::Load() in-memory |
| Defense Evasion | Double File Extension | T1036.007 | .xlsx.js masquerading |
| Defense Evasion | Sandbox Evasion | T1497 | Username/computer name checks, ReDoS |
| Credential Access | Browser Credentials | T1555.003 | Chrome, Firefox, Edge, Opera, Brave |
| Credential Access | Email Client Credentials | T1555.005 | Outlook profile access |
| Collection | Data from Local System | T1005 | Wallets, WiFi passwords, system info |
| Discovery | Process Discovery | T1057 | WMI Win32_Process enumeration |
| Discovery | System Information Discovery | T1082 | Processor, registry enumeration |
| Exfiltration | Exfiltration Over Web Service | T1567 | Telegram Bot API |
Indicators of Compromise
Network Indicators
# Telegram C2 (defanged)
hxxps://api[.]telegram[.]org/bot8593007332:AAEPMJO3zv4YVgEOImh_tZhHp0aSBYcyt8g/sendMessage?chat_id=5229075943
# Telegram Bot ID
8593007332
# Telegram Chat ID (persistent -- tied to operator account)
5229075943
File Indicators -- JS Droppers
# Sample 1: Spare Parts Requisition (Industrial)
SHA-256: ffc7a50822a48a329b1f588d7d3c187ec280e9f5bba155a99f04116b4c7560d0
MD5: 0f2e608555b7294202ec0b67e2791b2e
SHA-1: 6b3ffcce52cef8c942713de40dbc6c7a4b24982d
File: RF-PUB802 Spare Parts Requisition.xlsx.js
# Sample 2: Port Agency Appointment (Maritime)
SHA-256: c08f0093379918437a0f1c18f9236b6f7c3da6d6e63316fec04255891b4e1609
MD5: ecd166ed0df0d25d60c61e1f55f5b5e5
SHA-1: aa8e78f85b9b47e707de560808d92591687375fe
File: PDA Query - 180397-03-010-26 Port Agency Appointment.js
File Indicators -- .NET Loader DLLs (DEV.dll)
SHA-256: e5e8ec1e905a1b53178e8963ee76d9ae075b08bfe890269629e08bbc0e88b335
MD5: e09babffda5a9b36dd163ee7892c2d5e
SHA-256: 1c5c15bbed9b6056298187a2fe7d808d8ecc38db0b17c6b18250f9e521028f74
MD5: b69f46bd7658a4b6f0c2090f342fb0e4
File Indicators -- Related EXE Payloads
SHA-256: b162f3294b0c36fa3a52128e3db74e3ba7da2b1e8abcef7309a5b79033510ae3
SHA-256: b6da3c835e772665e4223368cc4a7a940a114930c68604c789ac2f272fc1a232
SHA-256: 5f7f0c5c9aef6352a28e58882f571f249dfb451daf00a0261d7a7bbb9e551d74
SHA-256: 20319983f849f6cf7be8fae73950649dbb6593cca2282d005091eeaf8b13cc27
SHA-256: e6a56859a1ee8a390634cc2464d32b73b2dbc2119b25373044c26a4da65e9cd7
imphash: f34d5f2d4577ed6d9ceec516c1f5a744
Behavioral Indicators
# Persistence artifacts
Registry: HKLM\Software\Microsoft\Windows\CurrentVersion\Run\
Startup: SystemUpdate.lnk / System Update.lnk
Temp: C:\Temp\ps_[random].ps1
# Process injection target
Aspnet_compiler.exe (with unusual parent process)
# .NET metadata (strong clustering signals)
Assembly: DEV.dll
PDB: DEV.pdb
Entry: DEV.DOWN.SHOOT()
Framework: .NET 4.5.1
Resource keys: {11111-22222-XXXXX-XXXXX} pattern
# PowerShell execution
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NoLogo -File C:\Temp\ps_*.ps1
Detection: YARA Rules
rule PhantomStealer_JS_Dropper {
meta:
author = "Breakglass Intelligence"
description = "PhantomStealer JavaScript dropper with Rotational XOR payload"
date = "2026-03-10"
tlp = "TLP:CLEAR"
reference = "https://intel.breakglass.tech"
strings:
$framework = "Multi-Stage Rotational XOR Decryption Framework" base64
$var_container = "$securecontainer" base64
$var_key = "$encryptionrotational" base64
$func_wscript = "WScript" ascii
$obf_pattern = /var\s+HO\s*=\s*\[/ ascii
$obf_pattern2 = /function\s+[A-Z]\(\)\{var\s+\w{2}\s*=\s*\[/ ascii
$exe_dev = "DEV.DOWN" base64
$exe_shoot = "SHOOT" base64
condition:
filesize > 4MB and filesize < 6MB and
($framework or ($var_container and $var_key)) and
$func_wscript and
any of ($obf_pattern*)
}
rule PhantomStealer_NET_Loader {
meta:
author = "Breakglass Intelligence"
description = "PhantomStealer .NET loader DLL (DEV.dll)"
date = "2026-03-10"
tlp = "TLP:CLEAR"
strings:
$pdb = "DEV.pdb" ascii wide
$ns1 = "DEV.DOWN" ascii wide
$method = "SHOOT" ascii wide
$guid1 = "{11111-22222-10009-11112}" ascii wide
$guid2 = "{11111-22222-20001-00001}" ascii wide
$guid3 = "{11111-22222-50001-00000}" ascii wide
$aes = "AesCryptoServiceProvider" ascii wide
$reflect = "GetDelegateForFunctionPointer" ascii wide
condition:
uint16(0) == 0x5A4D and
filesize < 100KB and
($pdb or $ns1) and
($method or $guid1 or $guid2) and
$aes
}
Detection: Suricata Rules
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"BREAKGLASS PhantomStealer Telegram C2 - Bot Token";
content:"api.telegram.org";
content:"/bot8593007332";
content:"sendMessage";
classtype:trojan-activity;
sid:2026031001; rev:1;
metadata:created_at 2026_03_10;
)
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"BREAKGLASS PhantomStealer Telegram C2 - Chat ID";
content:"api.telegram.org";
content:"/bot";
content:"sendMessage";
content:"chat_id=5229075943";
classtype:trojan-activity;
sid:2026031002; rev:1;
)
Recommended Actions
Immediate (24-48 hours)
- Block Telegram Bot API calls containing bot ID
8593007332and chat ID5229075943at the network perimeter - Search email gateways for
.xlsx.jsand.jsattachments from the past 14 days, especially with maritime or procurement themes - Hunt for
Aspnet_compiler.exeprocesses with unusual parent processes -- if the parent is not MSBuild or Visual Studio, investigate - Check
HKLM\Software\Microsoft\Windows\CurrentVersion\Runfor entries you do not recognize - Search endpoints for
C:\Temp\ps_*.ps1files
Short-term (1-2 weeks)
- Deploy the YARA and Suricata rules above to endpoint and network detection platforms
- Block
.jsfile execution via Windows Script Host (wscript.exe / cscript.exe) if not business-required -- most organizations do not need it - Submit the EXE imphash
f34d5f2d4577ed6d9ceec516c1f5a744to your EDR vendor for retrospective scanning - Review Startup folder contents across enterprise endpoints for
SystemUpdate.lnkorSystem Update.lnk
Medium-term (1-3 months)
- Implement file extension filtering to block double-extension files (
.xlsx.js,.pdf.js,.docx.js) at the email gateway and endpoint level - Consider disabling Windows Script Host entirely via GPO for non-administrative users
- Monitor MalwareBazaar for new PhantomStealer samples via tag tracking -- 25 samples in 12 days means more are coming
- Assess your organization's exposure to Telegram-based C2 exfiltration broadly -- this is a growing trend across multiple malware families, and blanket blocking of
api.telegram.orgoutbound from non-browser processes is worth evaluating
References
- MalwareBazaar: https://bazaar.abuse.ch/sample/ffc7a50822a48a329b1f588d7d3c187ec280e9f5bba155a99f04116b4c7560d0/
- MalwareBazaar: https://bazaar.abuse.ch/sample/c08f0093379918437a0f1c18f9236b6f7c3da6d6e63316fec04255891b4e1609/
- Triage: https://tria.ge/reports/260310-lv61jahz6q/
- Triage: https://tria.ge/reports/260309-sxm4rsfx6s/
- ANY.RUN: https://app.any.run/tasks/bc62f983-8d60-493f-9080-aef8f69924b3
- CERT-PL MWDB: https://mwdb.cert.pl/sample/ffc7a50822a48a329b1f588d7d3c187ec280e9f5bba155a99f04116b4c7560d0/
Published by Breakglass Intelligence. Investigation conducted 2026-03-10. 25 samples tracked. 5-layer execution chain dissected. Telegram bot token extracted and burned. Builder fingerprint identified. Classification: TLP:CLEAR