2ffc320332ff30d80c0a1da728aa59db136438338409cf01a96b71e488d21b67phorpiex: 2ffc3203 — Thin MSVC9 downloader sibling, peinf→xmr→xmrget chain, May 2026
Executive Summary
10 KB MSVC9 PE32 downloader dropped by the Phorpiex crimeware campaign. No packing, no obfuscation, honest main() entry. Downloads three payloads sequentially from a hardcoded Russian IP via dual WinInet/URLMon fetch paths, gates execution with an OS build-number check and a filesystem marker file, spawns each dropped payload via ShellExecuteW, and scrubs the Zone.Identifier ADS. Static-only analysis — no CAPE Windows guest available.
What It Is
| Field | Value |
|---|---|
| SHA-256 | 2ffc320332ff30d80c0a1da728aa59db136438338409cf01a96b71e488d21b67 |
| Size | 10 240 bytes ^[file.txt] |
| Type | PE32 executable (GUI) Intel 80386, 5 sections ^[file.txt] |
| Linker | MSVC 9.0 (Visual C++ 2008) ^[pefile.txt:45] ^[rabin2-info.txt:17] |
| Compiled | 2026-05-22 07:45:34 UTC ^[pefile.txt:34] ^[exiftool.json:15] |
| Signed | No ^[rabin2-info.txt:27] |
| Packed | No ^[rabin2-info.txt:23] ^[binwalk.txt] |
| Family | phorpiex (OpenCTI label dropped-by-phorpiex) ^[metadata.json:7] |
Confirmed campaign sibling to 6b8527a7 and 025f5798 — same C2 IP (178.16.54.109), same build day, same dual-download logic, same marker filename (d3333333333333333333.txt), same toolchain fingerprint. Delta: payload name rotation (peinf.exe instead of 15.exe observed in 6b8527a7).
How It Works
- Entry delay —
mainsleeps 2000 ms, then calls the downloader workerfcn.004010a8with the first URL ^[r2:main]. - Payload chain — Three hardcoded URLs fetched in order:
http://178.16.54.109/peinf.exe^[strings.txt:83]http://178.16.54.109/xmr.exe^[strings.txt:82]http://178.16.54.109/xmrget.exe^[strings.txt:81]
- Dual-path download — Primary path uses WinInet (
InternetOpenWwith Chrome/128 UA →InternetOpenUrlW→InternetReadFile→WriteFile→CreateFileW). If that fails, sleeps a random interval, regenerates a random filename, and retries viaURLDownloadToFileW^[r2:fcn.004010a8] ^[pefile.txt:278-302]. See wininet-urlmon-dual-download. - Marker-file gating —
fcn.004012fbexpands%appdata%and checks/createsd3333333333333333333.txtas a filesystem mutex ^[strings.txt:91] ^[r2:fcn.004012fb]. Prevents redundant payload execution on subsequent runs. See marker-file-mutex-gating. - OS build gating —
fcn.004013c0loadsntdll.dll, resolvesRtlGetVersion, and returns true only ifdwBuildNumber >= 0x55f0(22000 = Windows 11 / Server 2022). If the check fails, the payload branch is skipped ^[r2:fcn.004013c0] ^[strings.txt:89]. See rtlgversion-build-gating. - Execution — Each successfully downloaded file is spawned via
ShellExecuteWwith verbopen^[r2:fcn.004010a8] ^[strings.txt:90]. - ADS scrub — After writing the file, the dropper constructs
%s:Zone.Identifierand deletes it viaDeleteFileWto remove the "Downloaded from Internet" mark ^[r2:fcn.004010a8] ^[strings.txt:85]. See zone-identifier-deletion. - Random filename —
%TEMP%\<rand><rand>.exe, seeded withGetTickCountand formatted via_snwprintf^[r2:fcn.004010a8] ^[strings.txt:86].
Decompiled Behavior
main (0x0040143e) — honest C runtime entry. Sleeps, then orchestrates three sequential download attempts. Each attempt: push URL → call fcn.004010a8 → if success, call fcn.004012fb (marker gate). If marker gate returns true, proceeds to next URL; otherwise exits.
fcn.004010a8 (Downloader/Executor) — the workhorse. Allocates a 0x1630-byte stack buffer via fcn.004014b0 (stack probe). Expands %TEMP%, seeds srand(GetTickCount()), generates %s\%d%d.exe, opens a WinInet session with the hardcoded Chrome/128 User-Agent string, fetches the URL in 4096-byte chunks (InternetReadFile), writes to disk (CreateFileW / WriteFile), closes handles, scrubs Zone.Identifier, then spawns the file via ShellExecuteW("open", ...). If any step fails, falls back to URLDownloadToFileW after sleeping rand() % 0xea60 milliseconds and regenerating the filename.
fcn.004012fb (Marker Gate) — expands %appdata%, then calls CreateFileW on the path. If the call returns INVALID_HANDLE_VALUE (file already exists), returns 1 (gate open / skip). If the call succeeds (file created), returns 0 (proceed). This is the inverse of a typical mutex check but serves the same purpose: preventing redundant execution.
fcn.004013c0 (OS Build Check) — loads ntdll.dll via GetModuleHandleW, resolves RtlGetVersion via GetProcAddress, fills an OSVERSIONINFOEXW struct (size 0x114), and validates dwBuildNumber >= 0x55f0 (22000). Returns boolean.
C2 Infrastructure
- IP:
178.16.54.109— Russia, Saint Petersburg, ASN 48666 (Beget LLC) - Paths:
/peinf.exe,/xmr.exe,/xmrget.exe - Protocol: HTTP (cleartext), no TLS, no DNS resolution
- 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^[strings.txt:84] - No domains, no cookies, no POST body.
Interesting Tidbits
IsDebuggerPresentis imported ^[pefile.txt:331] but not invoked in any decompiled function; likely residual from the MSVCRT startup or an unused anti-debug template.QueryPerformanceCounterimported but unused in the main flow ^[pefile.txt:312]; possible anti-emulation residue from a shared builder stub.- Chrome/128 UA is current as of May 2026, suggesting the builder is actively maintained.
- Payload name
peinf.exeis a rotation from15.exeobserved in sibling6b8527a7; C2 infrastructure is otherwise identical. - No persistence mechanism in the outer binary — the downloader relies on dropped payloads to install their own persistence.
- The binary has a standard VS_VERSIONINFO manifest requesting
asInvokerexecution level ^[pefile.txt:356-394].
How To Mess With It (Homelab Replication)
Toolchain: Visual C++ 2008 (MSVC 9.0), x86, static link to MSVCR90 (/MT).
Working snippet (WinInet primary + URLMon fallback):
Compile with cl.exe /O2 /MT downloader.cpp using the VC9 toolset. Use InternetOpenW, InternetOpenUrlW, InternetReadFile, WriteFile, ShellExecuteW, and URLDownloadToFileW. Expand %TEMP% via ExpandEnvironmentStringsW, seed srand(GetTickCount()), generate %TEMP%\%d%d.exe, and spawn with verb open. Add a DeleteFileW call on %s:Zone.Identifier to replicate the full fingerprint.
Verification: If capa signatures were installed, the reproducer should hit download file and execute shell command.
Deployable Signatures
YARA Rule
rule Phorpiex_ThinMSVC9_Downloader_May2026 {
meta:
description = "Phorpiex thin MSVC9 downloader — peinf/xmr/xmrget variant"
author = "PacketPursuit"
date = "2026-06-10"
hash = "2ffc320332ff30d80c0a1da728aa59db136438338409cf01a96b71e488d21b67"
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" ascii wide
$url1 = "http://178.16.54.109/peinf.exe" ascii wide
$url2 = "http://178.16.54.109/xmr.exe" ascii wide
$url3 = "http://178.16.54.109/xmrget.exe" ascii wide
$zone = "%s:Zone.Identifier" ascii wide
$temp_pattern = "%s\\%d%d.exe" ascii wide
$marker = "d3333333333333333333.txt" ascii wide
$rtl = "RtlGetVersion" ascii wide
condition:
uint16(0) == 0x5A4D and
uint32(uint32(0x3C)) == 0x4550 and
pe.linker_version.major == 9 and
pe.imports("WININET.dll", "InternetOpenW") and
pe.imports("urlmon.dll", "URLDownloadToFileW") and
pe.imports("SHELL32.dll", "ShellExecuteW") and
3 of ($url*) and $zone and $marker
}
Behavioral Hunt Query (KQL/Splunk pseudo-code)
(process_name="*.exe" AND parent_process_name="*.exe")
| where command_line LIKE "%TEMP%\%.exe"
| where dns_query="178.16.54.109" OR url LIKE "http://178.16.54.109/%"
| stats count by host, user, process_name, command_line
IOC List
| Type | Value | Note |
|---|---|---|
| SHA-256 | 2ffc320332ff30d80c0a1da728aa59db136438338409cf01a96b71e488d21b67 |
Outer dropper |
| IP | 178.16.54.109 |
C2 / payload host |
| URL | http://178.16.54.109/peinf.exe |
First-stage payload |
| URL | http://178.16.54.109/xmr.exe |
Second-stage payload |
| URL | http://178.16.54.109/xmrget.exe |
Third-stage payload |
| User-Agent | Mozilla/5.0 ... Chrome/128.0.0.0 Safari/537.36 |
Hardcoded WinInet UA |
| Marker file | %appdata%\d3333333333333333333.txt |
Filesystem mutex |
| Temp file | %TEMP%\<rand><rand>.exe |
Staged payload name |
Detection Signatures (ATT&CK Mapping)
| Tactic | Technique | Evidence |
|---|---|---|
| Initial Access | T1204.002 — User Execution: Malicious File | Spam-distributed PE ^[metadata.json] |
| Execution | T1059.003 — Windows Command Shell | ShellExecuteW with verb open ^[r2:fcn.004010a8] |
| Defense Evasion | T1070.004 — File Deletion | DeleteFileW on Zone.Identifier ^[r2:fcn.004010a8] |
| Defense Evasion | T1497.001 — Virtualization/Sandbox Evasion: System Checks | RtlGetVersion build-number gating ^[r2:fcn.004013c0] |
| Defense Evasion | T1055 — Process Injection (inferred) | InterlockedExchange / InterlockedCompareExchange imported ^[pefile.txt:313] — not observed in decompiled path; may be used by dropped payload |
| Command and Control | T1105 — Ingress Tool Transfer | WinInet + URLMon dual download ^[r2:fcn.004010a8] |
| Discovery | T1082 — System Information Discovery | RtlGetVersion OS build check ^[r2:fcn.004013c0] |
References
- phorpiex — umbrella entity page for campaign
- wininet-urlmon-dual-download — technique page for dual-path fetch pattern
- marker-file-mutex-gating — technique page for filesystem mutex
- rtlgversion-build-gating — technique page for OS build-number gate
- zone-identifier-deletion — technique page for ADS scrub
- Sibling analysis:
6b8527a7f761e8a5489b81ea8a79cbbbd9c09485b9b5d7c28cd892ef66599339 - Sibling analysis:
025f57988953e3d23e1657a9af5610887e57c5390a82f73b4b2b99c30eef3b70
Provenance
Analysis derived from:
file.txt— file(1) outputpefile.txt— pefile/PE-bear header dumpexiftool.json— ExifTool PE metadatarabin2-info.txt— radare2 binary summarystrings.txt— raw ASCII/Unicode stringsbinwalk.txt— embedded artifact scanr2 decompile— radare2 pseudo-C (pdg) ofmain,fcn.004010a8,fcn.004012fb,fcn.004013c0metadata.json— OpenCTI artifact labels
Report generated 2026-06-10. Static-only; no CAPE detonation available.