Back to reports
highStealer

PhantomStealer: 25 Samples From an Automated Builder, a 5-Layer Kill Chain, and a Burned Telegram Bot Targeting Maritime and Industrial Sectors

PublishedMarch 12, 2026
Threat Actors:ProfileAssessment
stealerasyncratquasarratagentteslaphishingsocial-engineeringc2supply-chainspearphishing

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.js
  • RF-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.

AttributeSample 1 (Industrial)Sample 2 (Maritime)
File NameRF-PUB802 Spare Parts Requisition.xlsx.jsPDA Query - 180397-03-010-26 Port Agency Appointment.js
SHA-256ffc7a508...7560d0c08f0093...1609
Size4,640,410 bytes4,604,727 bytes
First Seen2026-03-10 09:51:31 UTC2026-03-09 15:30:02 UTC
Reporterpr0xylifeJames_inthe_box
OriginDenmarkUnited 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:

  1. Extract a base64-encoded PowerShell payload from the string table (index [554] in Sample 1)
  2. Write it to C:\Temp\ps_[random].ps1
  3. Execute with powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NoLogo
  4. Drop a .lnk shortcut named "SystemUpdate" in the Startup folder
  5. Write a registry Run key under HKLM\Software\Microsoft\Windows\CurrentVersion\Run
  6. 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.

SampleXOR 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.

AttributeSample 1 DLLSample 2 DLL
SHA-256e5e8ec1e...0e88b3351c5c15bb...1028f74
Size47,104 bytes46,592 bytes
Framework.NET 4.5.1.NET 4.5.1
Copyright20262026

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:

DateSamplesTypeNotes
Feb 261EXEEarliest known (ANY.RUN sandbox)
Mar 621EXEBulk upload to MalwareBazaar (reporter: adrian__luca)
Mar 82JSAdditional dropper variants
Mar 91JSMaritime theme (PDA Query)
Mar 101JSIndustrial 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 DecisionAssessment
Telegram C2 (no server to track)Smart
Per-sample unique crypto keysSmart
5-layer execution chainSmart
Sandbox/VM detection checksStandard
Bot token exposed via sandbox analysisBurned
Chat ID 5229075943 now permanent IOCBurned
"Copyright 2026" in PE metadataCareless
Consistent DEV.dll / SHOOT() namingWeak -- strong clustering signal
Shared imphash across all EXE payloadsWeak -- 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:

VendorDetectionNotes
Triagephantom_stealer (10/10)Best classification
KasperskyMultiple detections (14+)Trojan-PSW.MSIL.Stealerium, Trojan-Downloader.Script.Generic
ReversingLabsByteCode-MSIL.Trojan.Redlinestealer (70.83%)Misattributed as RedLine
IntezerKeyBase (malicious)Code overlap detection
VMRayPhantomStealer (malicious)Correct family ID
ANY.RUNMalicious activityTags: phantom, stealer, crypto-regex, evasion
FileScan-IOLIKELY_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

TacticTechniqueIDImplementation
Initial AccessSpearphishing AttachmentT1566.001JS file with social engineering filename
ExecutionJavaScriptT1059.007WScript execution of .js dropper
ExecutionPowerShellT1059.001Bypass/Hidden execution flags
ExecutionMalicious FileT1204.002Double-extension .xlsx.js trick
PersistenceRegistry Run KeysT1547.001HKLM Run key
PersistenceShortcut ModificationT1547.009Startup folder .lnk
Defense EvasionDeobfuscate/DecodeT1140Multi-stage XOR, Base64, AES
Defense EvasionObfuscated FilesT1027JS string table, Fody packer
Defense EvasionProcess InjectionT1055SetThreadContext into Aspnet_compiler.exe
Defense EvasionReflective Code LoadingT1620Assembly::Load() in-memory
Defense EvasionDouble File ExtensionT1036.007.xlsx.js masquerading
Defense EvasionSandbox EvasionT1497Username/computer name checks, ReDoS
Credential AccessBrowser CredentialsT1555.003Chrome, Firefox, Edge, Opera, Brave
Credential AccessEmail Client CredentialsT1555.005Outlook profile access
CollectionData from Local SystemT1005Wallets, WiFi passwords, system info
DiscoveryProcess DiscoveryT1057WMI Win32_Process enumeration
DiscoverySystem Information DiscoveryT1082Processor, registry enumeration
ExfiltrationExfiltration Over Web ServiceT1567Telegram 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
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;
)

Immediate (24-48 hours)

  • Block Telegram Bot API calls containing bot ID 8593007332 and chat ID 5229075943 at the network perimeter
  • Search email gateways for .xlsx.js and .js attachments from the past 14 days, especially with maritime or procurement themes
  • Hunt for Aspnet_compiler.exe processes with unusual parent processes -- if the parent is not MSBuild or Visual Studio, investigate
  • Check HKLM\Software\Microsoft\Windows\CurrentVersion\Run for entries you do not recognize
  • Search endpoints for C:\Temp\ps_*.ps1 files

Short-term (1-2 weeks)

  • Deploy the YARA and Suricata rules above to endpoint and network detection platforms
  • Block .js file execution via Windows Script Host (wscript.exe / cscript.exe) if not business-required -- most organizations do not need it
  • Submit the EXE imphash f34d5f2d4577ed6d9ceec516c1f5a744 to your EDR vendor for retrospective scanning
  • Review Startup folder contents across enterprise endpoints for SystemUpdate.lnk or System 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.org outbound from non-browser processes is worth evaluating

References


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

Share