Honeypot capture
nsminer
The static pipeline recovered 50 command-and-control (C2) endpoints across 19 distinct hosts from a 3 528 005-byte archive captured by a honeypot sensor network, along with the operator’s Monero wallet and the codec protecting the configuration channel. No independent second toolchain confirmed any of those values: the configuration stays bzip2-compressed inside the NSIS overlay, and the analysis container carried no NSIS-extraction tooling to open it, so every C2 indicator below is marked unverified. The sample was loaded as data throughout; no recovered endpoint was contacted or resolved.
The file is a ZIP container with two independent members. The main one is a Nullsoft (NSIS 2.46) self-extracting installer, internally named “NsMiner”: a CryptoNight (Monero) mining dropper — a program that writes another program to disk and runs it — with a worm component. On execution it copies itself into %APPDATA%\NsMiner, drops two VMProtect-packed miners and a pools.txt pool list, persists through HKLM and HKCU Run keys, two scheduled tasks named “UAC” and a Startup shortcut, disables sleep and hibernate through powercfg so the machine keeps mining, and beacons over plaintext HTTP to nine rotating .ru hosts for live pool configuration. The three commands it understands are configuration-fetch URIs — /test.html, /stat.html, /text.html — requested from whichever of the nine hosts a pseudo-random index picks; there is no RAT or backdoor command dispatch. The second member, information.vbe, a Script-Encoded VBScript re-decoded during this analysis, is an independent downloader that fetches hxxp://www[.]testswork[.]ru/tmp2[.]exe to %TEMP%\tmp2.exe, clears the mark of the web and runs it.
The NSIS install script
A 325-entry NSIS install script drives the behaviour, and the stock NSIS interpreter runs it from ExecuteCodeSegment at file offset 0x401434 in the unpacked self-extracting installer. Every configuration-driven action dispatches from that one address, so every capability in Table 1 carries the same evidence anchor and is separated only by the script entry it runs.
The script installs and relaunches the sample at entry[000]–[029], drops the miners and pools.txt at entry[030]–[035], sets up persistence at entry[036]–[041], assembles the configuration hostname at entry[061]–[078], issues the HTTP GET through the bundled inetc.dll at entry[087], substitution-decodes and selects a configuration at entry[090]–[119], launches the miner at entry[132], and then enters a 60-second beacon loop that closes at entry[305] Goto 42. Two further branches sit off that path: SMB self-propagation at entry[304], and a repack routine at entry[183]–[215] that rebuilds the installer with a bundled makensis.exe.
Two things keep the sample’s constants out of a plain strings pass. The configuration is bzip2-compressed inside the NSIS overlay at file offset 0x17200, so a plain strings pass over the sample finds no hostname. On top of that compression, the script fragments its own constants: C2 hostnames and the miner command line are cut from delimiter-packed stem lists at runtime by a character loop at entry[061], so no endpoint exists whole anywhere in the file. The pipeline also logs decoy fingerprint writes — 19 StrCpy writes of a build-machine fingerprint into $R0 at entry[002]–[020], overwritten before the value is ever used — as a second anti-analysis technique alongside the fragmentation.
Table 1: Six capabilities, all dispatched from the same interpreter address Capabilities recovered from the NSIS script by the static pipeline, with the MITRE ATT&CK technique, the script entry carrying the evidence, and the pipeline’s own confidence score. ⚠️ marks a value that the independent second toolchain could not confirm.
| Capability | ATT&CK | Evidence (entry) | Conf | Verified |
|---|---|---|---|---|
| Plaintext-HTTP configuration C2 | T1071.001 | entry[087] CallPlugin inetc get | 0.90 | ⚠️ |
| Resource hijacking — cryptomining | T1496 | entry[132] miner launch | 0.90 | ⚠️ |
| Registry Run-key persistence | T1547.001 | entry[036]/[040] | 0.90 | ⚠️ |
| Scheduled-task persistence | T1053.005 | entry[037]/[038] schtasks “UAC” | 0.90 | ⚠️ |
| Lateral movement over SMB shares | T1021.002 | entry[304] net use/xcopy worm | 0.80 | ⚠️ |
| Defense evasion — string fragmentation | T1027 | entry[061] + char loop | 0.85 | ⚠️ |
Plaintext HTTP and a keyless substitution
Nine hosts serve configuration over port 80 — stafftest[.]ru as primary, with hrtests[.]ru, profetest[.]ru, testpsy[.]ru, pstests[.]ru, qptest[.]ru, prtests[.]ru, jobtests[.]ru and iqtesti[.]ru as fallbacks — each at confidence 0.90 and each marked unverified. Each is fetched at all three URIs, giving the 27 URL rows in iocs.csv. The three URIs carry different roles: /test.html receives and applies the miner configuration, /stat.html is a status and telemetry beacon, and /text.html is the repack and spread channel — though c2_profile.json describes the same three as architecture-specific payloads the loader selects between. One of the nine hosts, pstests[.]ru, appears in one other analysed capture, which the correlation phase records as evidence of a wider campaign.
The script reaches WinINet through the bundled inetc.dll get export. The request is a GET with no body and no TLS, and it carries the invariant User-Agent NSIS_Inetc (Mozilla). The pipeline records the transport at confidence 0.90, unverified.
The response body carries one layer of obfuscation, a self-inverse substitution over the 49-character alphabet lifted from entry[090]:
" [,.:?&%=@!1234567890/qwertyuiopasdfghjklzxcvbnm "
For each ciphertext character, plain[i] = alphabet[len-i] on the 1-based alphabet index; anything outside the alphabet passes through. The substitution has no key, and protocol_spec.md §4 gives the offline-decoding recipe. rabin2 -I reports crypto false, and an r2 /ck constant search finds no AES, RC4 or ChaCha.
The dissector decodes one /test.html response and recovers the set of at least 20 miner command lines the operator is distributing, along with the operator’s Monero wallet 4Ahxep5d8sdfVfN4XGPTQyUSpLm7gKqYvgqGzxf5raLLZAHQ7dn2oBzYdFCB3M3Gfz74CJQAs7DSMiNFvD1ykAbgSiAzCd4. The $8 selector is derived from a temp-file timestamp at runtime, so static analysis cannot determine which of those configurations a given victim applies; the dissector reports every offered configuration and the pick for every possible selector value.
The pools come from pools.txt, a dropped list of 13 stratum endpoints, and a hardcoded fallback: mine[.]moneropool[.]com on 3333 (the fallback), 8080 and 3336; xmr[.]hashinvest[.]net on 443 and 5555; monero[.]crypto-pool[.]fr on 3333; monerohash[.]com on 5555; mine[.]xmr[.]unipool[.]pro on 3333 and 80; xmr[.]prohash[.]net on 5555; xmr[.]miner[.]center on 2777; pool[.]minexmr[.]com and cryptonotepool[.]org[.]uk on 7777; mro[.]poolto[.]be on 3000 — all at confidence 0.80–0.85 and unverified for the same reason as the configuration hosts.
Three tools reproduce the channel — c2_dissect.py to decode a capture, c2_client.py to impersonate the sample, and c2_emulator.py to stand up a fake C2 — and validate_protocol.py passes 2 of 2 test vectors along with a constant-input check and a client round-trip. The report attaches a standing caution to them:
The
reproduction/tools are live-C2 code. They touch the network only with an explicit--target/--listen. Run them only in an isolated lane.
Host artifacts and spread
%APPDATA% writes and the HKCU Run key need no elevation, while the HKLM Run default value and schtasks /RL HIGHEST succeed only when elevated, with failure treated as non-fatal.
Table 2: The artifacts an infected host carries
Host indicators quoted from iocs.csv, all at confidence 0.85–0.90 and unverified.
| Kind | Value | Context |
|---|---|---|
| directory | %APPDATA%\NsMiner | install directory ($R9) |
| file | %APPDATA%\NsMiner\IMG001.exe | installed self copy |
| file | %APPDATA%\NsMiner\NsCpuCNMiner32.exe / …64.exe | dropped 32-bit and 64-bit CryptoNight miners |
| file | %APPDATA%\NsMiner\pools.txt | dropped stratum pool list (13 endpoints) |
| registry | HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run (default value) → %APPDATA%\NsMiner\[self] | persistence |
| registry | HKCU\Software\Microsoft\Windows\CurrentVersion\Run → %APPDATA%\NsMiner\[self] | persistence |
| service | schtasks "UAC" (ONLOGON, RL HIGHEST) | two tasks, persistence |
| file | %STARTMENU%\Programs\Startup\Run.lnk → %APPDATA%\NsMiner\[self] | persistence shortcut |
| process_name | NsCpuCNMiner32[.]exe / NsCpuCNMiner64[.]exe | miner process names, also taskkill’d on update |
The report tells defenders to hunt for %APPDATA%\NsMiner\, the task named “UAC” and the Run-key values across the estate, and to block the nine .ru configuration hosts and www[.]testswork[.]ru.
Two branches carry the sample beyond the infected host. The repack routine at entry[183]–[215] recompiles a fresh NSIS installer with a bundled makensis.exe, so the propagated copy differs from 7126b9932dc0cdfe751340edfa7c4a14b69262eb1afd0530e6d1fdb2e25986dd and detection keyed to this file’s hash will not match it. The second branch spreads over SMB: entry[304] enumerates hosts with net view and arp, mounts admin and user shares with a small credential list, and copies itself into Startup folders across the LAN. Whether either branch fires on this particular build is gated by $R7/$R8 state set at runtime, which static analysis cannot determine. The report advises treating SMB-reachable neighbours of an infected host as exposed.
Why the second toolchain confirmed nothing
The independent second toolchain (phase 9) confirmed no C2 value at all, and every C2 indicator in the report therefore carries the unverified mark. The static pipeline’s extractor recovers every endpoint, the wallet and the User-Agent byte-for-byte from the raw file, and its dissector round-trips its test vectors. Configuration extraction recovered one C2 endpoint as structured configuration, VM[.]rU, against the 50 endpoints of the static recovery.
Nothing in the report is observed behaviour, so timing, retries and any post-execution activity are outside what it can show, and whether the recovered infrastructure is still live is unknown.
The payloads that were not opened
The VMProtect-packed miners file_00.bin and file_01.bin (entry 0x0064f455) remain to be unpacked, as do the candidate embedded ZIP at offset 0x35d0d3, file_06.bin — tftp.exe, an FTP brute-forcer and site infector — and the next generation the repack branch would build. The pipeline did not fetch the tmp2.exe payload behind the hxxp://www[.]testswork[.]ru downloader, because fetching payloads is forbidden in this lane.
- Family
- nsminer
- First seen
- September 18, 2026
- Vector
- Runs as a cryptominer/dropper; the entry vector is not established by static analysis
- Format
- 3445 KB x86 Zip archive data (contains a Nullsoft PE SFX installer + a Script-Encoded VBScript)
- VirusTotal
- 55/75 engines: trojan.cugn/nsis
- Tags
- archive · cryptominer · dropper · wininet · worm · x86
- Sample
- By request. Email [email protected]
SHA-256
-
7126b9932dc0cdfe751340edfa7c4a14b69262eb1afd0530e6d1fdb2e25986ddas captured -
d9901b16a93aad709947524379d572a7a7bf8e2741e27a1112c95977d4a6ea8cunpacked payload
Analysis performed using an automatic malware analysis pipeline using Binary Ninja