typeanalysisfamilyphorpiexconfidencehighcreated2026-06-14updated2026-06-14malware-familyloaderpemsvcc2defense-evasion
SHA-256: f67e429d359aa88c0101af1c086ca42f18955b6e8ee799d88a095bdbc4e6fccc

phorpiex: f67e429d — Thin MSVC9 downloader, 13→14→peinf→xmr→xmrget chain, earliest May 2026 build

Executive Summary

10 KB MSVC9 PE32 downloader dropped by the Phorpiex crimeware campaign. Compiled 2026-05-21 23:03:35 UTC — the earliest known build in the May 2026 campaign window, predating all previously analysed siblings by ~7 hours. No packing, no obfuscation, honest main() entry. Downloads five payloads sequentially from a hardcoded Russian IP via dual WinInet/URLMon fetch paths. Gates execution with an OS build-number check (RtlGetVersion), an x64 architecture check (%SYSTEMDRIVE%\Program Files (x86)), and a dual-marker filesystem gate (d3333333333333333333.txt and f3f3f3d3d.txt in %appdata%). Spawns each dropped payload via ShellExecuteW and scrubs Zone.Identifier ADS. Static-only analysis — no CAPE Windows guest available.

What It Is

Field Value
SHA-256 f67e429d359aa88c0101af1c086ca42f18955b6e8ee799d88a095bdbc4e6fccc
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-21 23:03:35 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 2ffc3203, 6b8527a7, 025f5798, and 32f29422 — same C2 IP (178.16.54.109), same toolchain, same dual-download logic, same Zone.Identifier scrub. Deltas: (1) earliest build timestamp in the corpus; (2) five payload URLs instead of three or four; (3) two distinct filesystem marker gates instead of one; (4) both RtlGetVersion build gating and x64 Program-Files arch check present together.

How It Works

  1. Entry delaymain sleeps 2000 ms, then pushes URLs sequentially to fcn.004010a8 ^[r2:main].
  2. Payload chain — Five hardcoded URLs fetched in order:
    • http://178.16.54.109/13.exe ^[r2:strings]
    • http://178.16.54.109/14.exe ^[r2:strings]
    • http://178.16.54.109/peinf.exe ^[r2:strings]
    • http://178.16.54.109/xmr.exe ^[r2:strings]
    • http://178.16.54.109/xmrget.exe ^[r2:strings]
  3. Dual-path download — Primary path uses WinInet (InternetOpenW with Chrome/128 UA → InternetOpenUrlWInternetReadFileWriteFileCreateFileW). If that fails, sleeps a random interval (rand() % 0xea60 * 5 ms), regenerates a random filename, and retries via URLDownloadToFileW ^[r2:fcn.004010a8] ^[pefile.txt:278-302]. See wininet-urlmon-dual-download.
  4. Dual-marker gatingfcn.004012fb expands %appdata% and checks/creates d3333333333333333333.txt ^[ghidra:FUN_004010a8] ^[ghidra:strings:0x00402270]. fcn.00401370 performs the identical check against f3f3f3d3d.txt ^[ghidra:strings:0x004022b8]. Both functions return 1 if the file already exists (skip) and 0 if newly created (proceed). This is the first observed sibling with two distinct marker files. See marker-file-mutex-gating.
  5. OS build gatingfcn.00401435 loads ntdll.dll, resolves RtlGetVersion, and returns true only if dwBuildNumber >= 0x55f0 (22000 = Windows 11 / Server 2022) ^[r2:fcn.00401435] ^[strings.txt:10]. See rtlgversion-build-gating.
  6. x64 architecture gatingfcn.004013e5 expands %SYSTEMDRIVE%, formats %s\Program Files (x86), and calls PathFileExistsW ^[r2:fcn.004013e5]. Returns true only on x64 Windows. See x64-arch-check-progfiles-x86.
  7. Execution — Each successfully downloaded file is spawned via ShellExecuteW with verb open ^[r2:section..text] ^[pefile.txt:353].
  8. ADS scrub — After writing the file, the dropper constructs %s:Zone.Identifier and deletes it via DeleteFileW ^[r2:fcn.004010a8] ^[r2:strings]. See zone-identifier-deletion.
  9. Random filename%TEMP%\<rand><rand>.exe, seeded with GetTickCount and formatted via _snwprintf ^[r2:fcn.004010a8] ^[strings.txt:12].

Decompiled Behavior

main (0x004014b3) — honest C runtime entry. Sleeps 2000 ms, then orchestrates five sequential download attempts. Each attempt: push URL → call fcn.004010a8 → on success the downloader internally calls section..text (ShellExecuteW) to spawn the payload.

fcn.004010a8 (Downloader/Executor) — the workhorse. Allocates a 0x1630-byte stack buffer. Expands %TEMP%, seeds srand(GetTickCount()), generates %s\%d%d.exe, opens a WinInet session with the hardcoded Chrome/128 User-Agent, fetches the URL in 4096-byte chunks, writes to disk, closes handles, scrubs Zone.Identifier, then spawns via ShellExecuteW("open", ...). If the WinInet path fails, falls back to URLDownloadToFileW after a random sleep and filename regeneration. Returns a boolean in al indicating spawn success ^[ghidra:FUN_004010a8].

fcn.004012fb (Marker Gate — d333...) — expands %appdata%, calls CreateFileW on the marker path. If INVALID_HANDLE_VALUE (file exists), returns 1. If file is created, returns 0. The marker filename d3333333333333333333.txt is referenced at .rdata:0x00402270.

fcn.00401370 (Marker Gate — f3f3...) — identical code pattern to fcn.004012fb but references f3f3f3d3d.txt at .rdata:0x004022b8. The two gates may be called at different branches in main to create a two-stage execution barrier.

fcn.004013e5 (x64 Arch Check) — expands %SYSTEMDRIVE%, formats %s\Program Files (x86) via wsprintfW, and calls PathFileExistsW. Returns boolean. This gates payload execution to x64 hosts only.

fcn.00401435 (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: /13.exe, /14.exe, /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 ^[r2:strings]
  • No domains, no cookies, no POST body.

Interesting Tidbits

  • This is the earliest build in the Phorpiex May 2026 downloader campaign window. All previously analysed siblings (32f29422, 2ffc3203, 025f5798, 6b8527a7) were compiled on 2026-05-22 between 06:19 and 16:56 UTC. This sample predates them by ~7–18 hours, suggesting it may be a test build or the initial campaign seed.
  • Payload names 13.exe and 14.exe have not been observed in any other corpus sibling. The progression appears to be: 13/14 (this sample) → 15 (6b8527a7/025f) → peinf (2ffc3203) → grab (32f29422). Active C2 payload rotation within a 24-hour window.
  • IsDebuggerPresent is imported ^[pefile.txt:331] but not invoked in any decompiled function; residual from MSVCRT startup or unused anti-debug template.
  • QueryPerformanceCounter imported but unused in the main flow ^[pefile.txt:312]; possible anti-emulation residue.
  • Chrome/128 UA is current as of May 2026, indicating active builder maintenance.
  • The binary embeds a standard VS_VERSIONINFO manifest requesting asInvoker execution level ^[pefile.txt:356-394].
  • Two distinct marker files (d333... and f3f3...) suggest the builder was reconfigured between this sample and later siblings, or the author intended a two-stage gate.

How To Mess With It (Homelab Replication)

Toolchain: Visual C++ 2008 (MSVC 9.0), x86, static link to MSVCR90 (/MT).

Working snippet: Compile a WinInet primary + URLMon fallback downloader with cl.exe /O2 /MT. 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 DeleteFileW on %s:Zone.Identifier. Add RtlGetVersion build-number check and PathFileExistsW on %SYSTEMDRIVE%\Program Files (x86) for the full fingerprint.

Verification: Build should be ~10 KB with 5 sections and MSVC 9.0 linker version.

Deployable Signatures

YARA Rule

rule Phorpiex_ThinMSVC9_Downloader_May2026_13_14_Chain {
    meta:
        description = "Phorpiex thin MSVC9 downloader — 13/14/peinf/xmr/xmrget chain, earliest build"
        author = "PacketPursuit"
        date = "2026-06-14"
        hash = "f67e429d359aa88c0101af1c086ca42f18955b6e8ee799d88a095bdbc4e6fccc"
    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/13.exe" ascii wide
        $url2 = "http://178.16.54.109/14.exe" ascii wide
        $url3 = "http://178.16.54.109/peinf.exe" ascii wide
        $url4 = "http://178.16.54.109/xmr.exe" ascii wide
        $url5 = "http://178.16.54.109/xmrget.exe" ascii wide
        $zone = "%s:Zone.Identifier" ascii wide
        $temp_pattern = "%s\\%d%d.exe" ascii wide
        $marker1 = "d3333333333333333333.txt" ascii wide
        $marker2 = "f3f3f3d3d.txt" ascii wide
        $rtl = "RtlGetVersion" ascii wide
        $progfiles = "%s\\Program Files (x86)" 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
        pe.imports("SHLWAPI.dll", "PathFileExistsW") and
        3 of ($url*) and $zone and ($marker1 or $marker2)
}

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 f67e429d359aa88c0101af1c086ca42f18955b6e8ee799d88a095bdbc4e6fccc Outer dropper
IP 178.16.54.109 C2 / payload host
URL http://178.16.54.109/13.exe First-stage payload (new name)
URL http://178.16.54.109/14.exe Second-stage payload (new name)
URL http://178.16.54.109/peinf.exe Third-stage payload
URL http://178.16.54.109/xmr.exe Fourth-stage payload
URL http://178.16.54.109/xmrget.exe Fifth-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 (existing)
Marker file %appdata%\f3f3f3d3d.txt Filesystem mutex (new)
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:section..text]
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.00401435]
Defense Evasion T1497.001 — Virtualization/Sandbox Evasion: System Checks PathFileExistsW on Program Files (x86) ^[r2:fcn.004013e5]
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.00401435]
Discovery T1082 — System Information Discovery PathFileExistsW arch check ^[r2:fcn.004013e5]

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
  • x64-arch-check-progfiles-x86 — technique page for x64 architecture gate
  • zone-identifier-deletion — technique page for ADS scrub
  • Sibling analysis: 2ffc320332ff30d80c0a1da728aa59db136438338409cf01a96b71e488d21b67
  • Sibling analysis: 6b8527a7f761e8a5489b81ea8a79cbbbd9c09485b9b5d7c28cd892ef66599339
  • Sibling analysis: 025f57988953e3d23e1657a9af5610887e57c5390a82f73b4b2b99c30eef3b70
  • Sibling analysis: 32f29422435896b7a09888a1bb42e622004fbb11d4cad2f6d6613c97ee94823f

Provenance

Analysis derived from:

  • file.txt — file(1) output
  • pefile.txt — pefile/PE-bear header dump
  • exiftool.json — ExifTool PE metadata
  • rabin2-info.txt — radare2 binary summary
  • strings.txt — raw ASCII/Unicode strings
  • binwalk.txt — embedded artifact scan
  • yara.txt — YARA match output
  • r2 decompile — radare2 pseudo-C (pdg) of main, fcn.004010a8, fcn.004012fb, fcn.00401370, fcn.004013e5, fcn.00401435, section..text
  • ghidra decompile — Ghidra pseudo-C of FUN_004010a8 and string xref search
  • metadata.json — OpenCTI artifact labels

Report generated 2026-06-14. Static-only; no CAPE detonation available.