Two Miners, No Wallet: The Toolkit's Deliberately Missing Money Trail
The Toolkit โ Part 2
Classification: HIGH ยท Confidence: HIGH (first-party sample analysis)
Part 1 established what the honeypot's largest family really is โ a modular Go host-takeover platform, unified with the credential-backdoor toolkit by one build hash โ and left one question open, marked as an honest gap: where does the mining point? The preset fields named a pool address, a pool user, a pool password, but carried no values. This letter chases that money trail, and the chase produces three findings, one of them a correction of my own Part 1 analysis. The toolkit mines two different ways depending on the hardware it lands on; the specific pool and wallet are deliberately absent from the binary by design, not by oversight; and the same compromised nodes that spread the Raspberry Worm are spreading this toolkit too. The money trail, it turns out, is missing on purpose โ and its absence is itself the finding.
Two miners, one toolkit
The preset system of Part 1 has exactly two members, and they are not two settings for one miner โ they are two entirely different miners, and the choice between them is a choice about hardware. Alongside the current_preset_xmrig_* fields Part 1 found sit a parallel set: current_preset_nbminer_poolAddr, nbminer_poolUser, nbminer_poolPass, nbminer_algo, nbminer_enabled. XMRig and NBMiner are the two presets, and the pairing is deliberate and telling.
XMRig, from Part 1, is the dominant open-source CPU miner, built for Monero's RandomX algorithm โ the right tool for the vast population of CPU-only devices the honeypot's whole threat market fights over. NBMiner is a GPU miner โ a well-known closed-source mining program built for graphics cards and the GPU-friendly algorithms (Ethash and its relatives, KawPow, and others) that are worthless on a CPU but lucrative on hardware with a real GPU. An operator who bundles both is not hedging; they are building a toolkit that mines whatever the host it lands on can profitably mine. Land on a stripped Raspberry Pi or a headless VPS โ CPU only โ and the toolkit runs XMRig against Monero. Land on a machine with a graphics card โ a gaming rig, a workstation, a GPU server โ and it switches to NBMiner and the far richer GPU coins. The preset architecture of Part 1 is revealed here as a hardware-adaptive mining strategy: one agent that fingerprints the host and picks the miner that will earn the most from that specific silicon.
This is a materially more sophisticated operation than a plain XMRig campaign. A single-miner operator leaves money on the table every time they compromise a host whose hardware their miner cannot exploit; this toolkit leaves none, because it carries a miner for both worlds and chooses at runtime. Combined with the credential-harvest and SSH-trust-theft propagation of Part 1, the picture sharpens: this is not a miner that sometimes does other things. It is a host-monetisation platform that extracts the maximum from each host โ its GPU if it has one, its CPU if it does not, its credentials always, and its trust relationships to reach the next one.
The economics of not missing a GPU
The dual-miner design is worth reading in economic terms, because the gap it closes is enormous. To a mining operation, not all compromised hosts are remotely equal. A stolen CPU core grinds out Monero at a rate measured in a handful of hashes per second; a stolen GPU โ even a mid-range consumer graphics card โ mines GPU-friendly coins at a rate that can be thousands of times higher, and a machine with several cards, a rendering workstation or a gaming rig or a mislaid GPU server, is worth more to a miner than a whole botnet of Raspberry Pis. The single most valuable outcome a mining intruder can have is landing on a GPU, and the single most wasteful is landing on one and being unable to use it.
A CPU-only miner โ the plain XMRig campaign this investigation first assumed it was chasing โ throws away every GPU it ever compromises, running its CPU miner on a graphics workstation and capturing a rounding error while the actual money-making hardware sits idle beside it. The toolkit's nbminer preset exists precisely to not do that. NBMiner is built for the Ethash-family and KawPow-class algorithms that only a GPU can mine profitably, and its presence means the toolkit fingerprints the hardware and captures the upside: CPU host, run XMRig on Monero for the modest, universal baseline; GPU host, switch to NBMiner and the high-value coins, and turn a lucky compromise into real revenue. The design implies the agent inspects the host for a usable GPU before choosing โ a small piece of reconnaissance that separates the amateur miner, who mines the same way everywhere and squanders its best catches, from this operator, who mines each host the most profitable way its silicon allows. In a market where the median stolen device is nearly worthless, the money is in the rare valuable host, and the dual-miner toolkit is built to not waste the rare valuable host.
The wallet isn't in the binary โ and that is the design
Now the money trail itself, and the reason Part 1 could not find it. Every field that would name the destination โ xmrig_poolAddr, xmrig_poolUser (which for a Monero miner is the wallet), nbminer_poolAddr, nbminer_poolUser โ exists in the binary as a named, empty configuration slot. The struct fields are there; the values are not. The pool and the wallet are not compiled into the executable at all.
This is not a failure of the analysis; it is a feature of the toolkit, and an operationally significant one. The values are populated at deploy time, from configuration the agent fetches over its HTTP/2 channel after it lands โ the binary ships as an empty vessel and is told, per deployment, which pool to mine to and which wallet to credit. That design buys the operator three things a hardcoded pool never could. It defeats static analysis: no amount of examining the binary reveals the destination, because the destination isn't in it. It makes the pool and wallet freely rotatable: the operator can change pools the moment one is reported and shut down, or rotate wallets to frustrate blockchain tracking, without rebuilding or redistributing a single binary โ the same disposable executable simply fetches new config. And it keeps the money server-side, where the operator controls it, rather than baked into thousands of copies scattered across victims and honeypots.
The lesson is the mirror of Part 1's eba3282b571c finding, and it completes it. There, the durable thing an operator could not cheaply change โ the build hash โ was the correlator that reassembled the campaign. Here, the deliberately disposable thing โ the pool and wallet โ is externalised precisely so it can be changed cheaply and often. The operator sorted their own artifacts into durable and disposable and built accordingly: the code identity is fixed and unavoidable, so it becomes a fingerprint; the money destination is a liability if fixed, so it is externalised into rotatable config. A defender inherits the consequence. The pool and wallet, the IOCs a miner writeup most wants, are the ones this toolkit is specifically built to deny โ not hidden, but absent, held on a server this static analysis cannot reach. That the money trail is missing is not a gap in the investigation. It is a documented property of the malware.
Config is the real payload
Step back from this one toolkit and the empty-preset design is a specific instance of the direction professional malware has moved, and it reframes what a "sample" even is. For a hardcoded worm like the Raspberry Worm, the binary is the operation โ its C2, its credential, its behaviour, all baked in, all recoverable by reading it. For this toolkit, the binary is a delivery shell, and the operation lives in the configuration it fetches after landing. The sample a honeypot captures is no longer the whole malware; it is the runtime of the malware, waiting to be told what to be. The real payload โ which coin, which pool, which wallet, perhaps which capabilities to enable at all โ arrives separately, from a server, and is never written to disk in a form a honeypot retains.
This is the model that commercial command-and-control frameworks pioneered and that criminal tooling has steadily adopted: separate the implant from the tasking, ship a generic agent, and drive it with server-side configuration and commands. Its consequence for defence is a shift in where the useful indicators live. The static IOCs a defender traditionally extracts โ the domain, the pool, the wallet โ migrate out of the binary and onto infrastructure the defender cannot see, leaving the binary itself an empty, rotatable shell whose only durable marks are the ones the operator could not externalise: its code identity (the eba3282b571c build hash of Part 1), its capability structure (the preset fields, the PAM hooks, the SSH client), and its behaviour once running. Hunting this toolkit by its pool or wallet is hunting the one part of it designed to move; hunting it by its build hash and its capability fingerprint is hunting the part that cannot. The whole of this two-letter analysis has, without quite intending to, been a demonstration of that pivot: everything solid found about this operator โ the unified codebase, the dual-miner ambition, the trust-theft spread โ came from the durable shell, and everything that stayed out of reach โ the coins, the pools, the wallets โ was the disposable config. The toolkit sorts its world into fixed and fluid, and a defender must learn to hold onto the fixed.
A correction, made in the open
Forensic honesty requires correcting one's own record when the evidence turns, and Part 1 contains a small over-read I can now fix from closer analysis. Part 1 listed, among the toolkit's command-and-control hints, the strings bucket.bp and bucket.mp, and suggested they implied "cloud-storage-hosted configuration." On closer inspection that reading is wrong. Those fragments are not cloud-storage bucket names; they are Go runtime internals โ pieces of the Go garbage collector's error strings (bad use of bucket.bp, bad use of bucket.mp, referring to the runtime's internal hash-map bucket pointers), sliced out of the binary's concatenated string table by the extraction. They are present in every Go binary of this vintage and mean nothing about this toolkit's C2.
The correction does not change Part 1's conclusions โ the toolkit's runtime-config C2 is established by the empty preset slots and the embedded HTTP/2 stack, not by those fragments โ but the specific "cloud bucket" inference was unsupported, and it is retracted here. The self-IP check to ip.seeip.org remains real and first-party. I record the correction plainly because a series that has spent twenty-odd letters insisting on the difference between what the evidence supports and what it merely suggests cannot exempt its own prior claims from that standard. Go-runtime string fragments are a known trap in analysing statically-linked Go malware โ the binary is full of internal strings that look like indicators and are not โ and this is one I walked into and am walking back out of.
The same nodes that spread the worm spread the toolkit
Where the money trail is absent, the distribution trail is not, and it produces the letter's third finding. The honeypot records the source addresses that delivered the toolkit's primary agent, and resolving them reproduces, almost exactly, the profile of the Raspberry Worm's brood from that series' fifth letter: a majority of compromised residential and telecom devices across the Global South and Asia โ SK Broadband (Korea), Taiwan Mobile, MTN Nigeria, Viettel (Vietnam), Airtel (India), China Mobile, Libyan telecoms, Bangladeshi and Pakistani and Indonesian ISPs โ and a minority of rented hosting โ Contabo, Performive, Private Layer, Cloud Host, a small Bangladeshi host appearing three times.
And within that hosting minority sit two addresses this investigation has met before, by name. 159.65.148.158 โ the DigitalOcean host that was the Raspberry Worm's single heaviest spreader, with over two thousand honeypot hits โ is here, delivering the Go toolkit. So is 102.220.160.172, a VPS Dedicated LLC address, from the same block family the Recidivists series subnet-banned and the worm's brood included. The exact same compromised and rented nodes that spread a crude bash worm are also spreading a sophisticated Go platform.
The right reading of this is careful, and it matters. It does not mean the worm and the toolkit share an operator โ they demonstrably do not, being different languages, different code, different everything. It means these particular nodes are promiscuous distribution amplifiers: heavily-compromised or abuse-tolerant hosts that spread whatever payload passes through them, worm and toolkit and miner alike, because that is what a high-volume infected relay or a bulletproof-rented spreader does. 159.65.148.158 is not the worm's node or the toolkit's node; it is a spreader, and it carries both. This is the same lesson the crossroads letter drew about supply-side convergence, now sharpened to the level of the individual host: the demand side of the compromised-Linux economy is genuinely diverse โ different operators, different tools, different monetisation โ but the distribution surface converges onto a shared set of compromised relays and rented amplifiers that carry everyone's cargo indiscriminately. Follow the money and each operator diverges; follow the delivery trucks and they share a depot.
The super-spreader
The node 159.65.148.158 deserves its own paragraph, because it is the clearest specimen of the shared-depot model and it recurs across this entire body of work. It is a DigitalOcean host that has struck this single honeypot over two thousand times โ a volume that marks it not as a victim conscript but as a dedicated, heavily-used distribution machine โ and across those strikes it has delivered the Raspberry Worm, this Go toolkit, and, by the promiscuous nature of what it is, presumably a good deal more. It is a super-spreader: one rented or deeply-compromised box that a wide range of unrelated operators use, or that a wide range of malware routes through, to push payloads at the internet at scale.
Super-spreaders are why the distribution surface converges even though the operators do not. A market with hundreds of distinct operators does not build hundreds of distinct delivery networks; it leans, disproportionately, on a small number of high-throughput relays โ the abuse-tolerant VPS, the compromised server with good bandwidth, the rented box on a network that ignores complaints โ and those few nodes end up carrying a share of the total traffic far out of proportion to their number. One 159.65.148.158 delivers for many. That concentration is, quietly, a defensive opportunity the money trail's absence denies: while the wallets scatter and hide, the delivery pools onto a countable set of super-spreaders, and a single such node banned or taken down cuts off not one operator but the slice of many operators' campaigns that flowed through it. The Recidivists series banned exactly these nodes for exactly this reason. Seen through the toolkit, that banning takes on a second meaning: cutting a super-spreader does not stop the operator who wrote the malware, but it severs one of the shared trucks that delivers it โ and the trucks, unlike the wallets, are few, loud, and already on the list.
What holds, and what is bounded
What holds, first-party: the toolkit carries two miner presets โ xmrig (CPU) and nbminer (GPU) โ each with its own pool-address, pool-user, pool-password, and algorithm fields, all read directly from the binary; those fields are empty configuration slots, not populated values; and the primary agent's delivery IPs resolve to a residential/telecom-majority distribution surface that includes the same 159.65.148.158 (DigitalOcean) and 102.220.160.172 (VPS Dedicated LLC) nodes documented spreading the Raspberry Worm.
What is bounded: that nbminer is a GPU miner and xmrig a CPU/Monero miner is established from the well-known public identity of those two programs, not re-derived here; the specific coins, pools, and wallets the toolkit mines to are runtime configuration not present in the static binary and were not obtained โ the honest and, this letter argues, designed-in limit of static analysis against this toolkit. The distribution IPs are the honeypot's delivery observations for one primary sample, a representative slice rather than the toolkit's full distribution.
What is not claimed: shared operation between this toolkit and the Raspberry Worm, or with the Whisper/Nexus fleets. The shared distribution nodes (159.65.148.158, 102.220.160.172) are shared amplifiers, not shared authorship; the toolkit's operator remains the pseudonymous Go author of Part 1, correlated to their own builds by the eba3282b571c hash and to nothing else.
Core IOCs
- Dual-miner presets:
current_preset_xmrig_*(CPU / Monero / RandomX) andcurrent_preset_nbminer_*(GPU) โ pool-address, pool-user (wallet), pool-password, algorithm, enabled flags for each; all empty in the binary (deploy-time config). - Money-trail design: pool and wallet externalised to runtime config fetched over the embedded HTTP/2 channel; not statically extractable โ rotatable, takedown-resilient, analysis-resistant by design.
- Self-IP check:
https://ip.seeip.org/(retained; real). - Distribution surface (primary agent): residential/telecom majority (SK Broadband, Taiwan Mobile, MTN Nigeria, Viettel, Airtel, China Mobile, Libyan/Bangladeshi/Pakistani/Indonesian ISPs) + hosting minority (Contabo, Performive, Private Layer, Cloud Host) โ including
159.65.148.158(DigitalOcean) and102.220.160.172(VPS Dedicated LLC), the same nodes documented spreading the Raspberry Worm. - Correction to Part 1:
bucket.bp/bucket.mpare Go-runtime internal strings, not cloud-storage C2 โ retracted.
Cross-references
- TI-2026-090A โ One Binary, Many Masks: the modular Go toolkit whose money trail this letter chases, and whose
bucket.*reading it corrects. - TI-2026-087E โ The Dispossessed: the worm brood's distribution profile this toolkit's delivery surface reproduces, down to the shared
159.65.148.158and VPS Dedicated LLC nodes. - TI-2026-087J โ The Crossroads: the supply-side-convergence finding this letter sharpens to the level of the individual shared spreader.
The investigation went looking for a wallet and found a design decision. The toolkit mines two ways to miss no hardware, and points its mining at a destination it deliberately keeps off the binary and on a server โ sorting, like a careful operator, the fingerprint it cannot avoid from the money trail it must protect. What a defender can hold onto is the durable half: the build hash that names the code, the dual-miner presets that name the ambition, and the shared depot of compromised trucks that deliver it. What the operator kept for themselves is the half that pays โ held server-side, rotatable, and, for now, out of reach. Not every investigation ends with the money. This one ends with the reason it doesn't.