Honeypot capture

X86 ELF 32-bit LSB executable ddos-bot (59bdafde8769)

C2 verifiedProtocol documented

A honeypot sensor network captured an i386 ELF of 5939362 bytes (5.9 MB), stripped and statically linked. Every finding below comes from static reading of the file; the sample was never executed, and no recovered endpoint was contacted or resolved. Static recovery of its command-and-control channel — the channel an infected machine uses to reach its operator for instructions — produced one endpoint, 77[.]239[.]124[.]201 on tcp/9111. The host and port sit in .data as two plaintext Go string globals (0x85ea9c8→0x83aa880 and 0x85ea9d0→0x8389fbe), concatenated and handed to net.Dial("tcp", …) at 0x82795f9. A sweep of all 1061 .data string headers found no fallback endpoint list.

Both directions of the channel are newline-delimited ASCII with no magic bytes, length prefix, compression or encryption: the bot sends STATS|active|cpu|memtotal|memused|goarch\n and reads operator command lines of the form [verb] [target] [args…]\n. The verbs dispatch 26 of the 34 Botnet/Methods flood routines as goroutines.

A scanner goroutine runs in parallel with the command channel. It generates random public IPv4 addresses and exploits Boa/TOTOLINK-class router web interfaces to install the sample on them. A worm spreads by copying itself to further machines with no user action, and this scanner gives the sample that capability.

This report asserts no family name. The only naming evidence in the binary is the attacker-chosen Go module path Botnet/Bot recorded in .go.buildinfo, which is a build artefact. The same section gives the toolchain: go1.26.0, -tags=netgo, CGO_ENABLED=0, GOARCH=386, GO386=softfloat — a statically linked 32-bit build with no libc dependency, aimed at heterogeneous embedded and IoT Linux.

The plaintext command channel

The bot dials, and on success starts a telemetry goroutine at 0x827cbe0 that beacons every 2 s (0x827cc07), reading /proc/stat and /proc/meminfo through main.getCPUUsage (0x827da00) and main.getMemInfo (0x827dd80) and reporting CPU, memory and GOARCH. On a dropped connection it reconnects after a 5 s backoff (0x8279606), and there is a 120 s connection-lifetime watchdog at 0x82796b0. The beacon carries no jitter.

crypto/tls.Dial exists in the binary at 0x8205b30, but only two of the flood methods reach it and main.main never does. Entropy in .data, a measure of how random the bytes are that is used to spot compression or encryption, measures 3.55, and there is no embedded encrypted configuration; the endpoint is two plaintext string globals. A single sniffed line to or from the endpoint yields, with no key, the victim’s live CPU percentage, total and used memory, architecture and current attack count in the outbound direction, and the operator’s target, method and duration verbatim in the inbound one.

All 29 verbs the dispatcher accepts have handler addresses that resolve to valid function entries; the verb strings and handler entry points come from the length-bucketed comparison chain at 0x827978f–0x827b4a3, which reads lines with a bufio.Scanner and splits them with strings.Fields. The table below lists six of the 29 verbs.

VerbHandlerBehaviour
udp0x8274470Botnet/Methods.UdpFlood
raw-udp0x8271590raw-socket UDP flood
tlsplusbypass0x8273630proxy-laundered TLS flood
STOP0x8269f60cancel all attacks
KILL0x8279e95strip crontab entry, re-exec, delete self, exit
persist0x827ce50re-run persistence

The dispatchable methods span volumetric floods (UDP, TCP, TLS, DNS, HTTPS, OVH and “bypass” variants) and application-layer exhaustion aimed at single services rather than links — Crash at 0x826a160, Freez at 0x826c760, Minecraft at 0x826e3b0, Discord at 0x826a510 — plus game-specific FiveM and Fortnite arms. Eight of the 34 Botnet/Methods entry points have no verb wired to them in the dispatcher, so the attack library is larger than the reachable command set. The numeric argument order after the target (duration, port, thread count, packet size) is fully decoded only for the udp arm, where the default packet size is 1400 bytes (0x578 at 0x827c29f). The client tool emits arguments positionally as the operator supplies them, and the reproduction notes record that neither gap blocks decoding or reproduction of the channel.

main.main.func2 at 0x82816b0 is a second, byte-for-byte parallel STATS frame builder — it references its own copy of the format string at 0x82817da and calls the same main.GetStats at 0x827d970 — with zero code cross-references, and nothing in the static view settles whether it is dead code.

The install and persistence routine

main.AutoStart (0x827ce50) walks a list of install directories — /usr/bin/, then /var/run/, then /data/local/tmp/ (an Android and embedded path), with /tmp/start as the fallback — and probes each one by creating and immediately deleting a zero-length test_write file. Execution requires only user privilege: the systemd, rc.local and /usr/bin routes all need root, and when they fail the binary lands in /tmp and persists through crontab instead.

A successful install leaves the following artefacts on disk, at the file offsets recorded for each behaviour.

KindValueContextOffset
systemd/etc/systemd/system/sysd.service164-byte unit: Description=System Daemon Service, ExecStart=[install path], Restart=always, RestartSec=5, WantedBy=multi-user.target; activated with systemctl daemon-reload / enable / start0x827d470
cron* * * * * [install path] > /dev/null 2>&1staged through /tmp/cron_tmp, installed with the crontab binary0x827d66d
file/etc/rc.local, /etc/rc.d/rc.local, /etc/init.d/boot.localinit-script fallbacks on non-systemd hosts0x827d1b1
process_namesysdinstalled filename, chosen to read like systemd0x8389fc2
fileproxy/tlsplusbypass.txtproxy list read relative to the working directory by Botnet/Methods.loadTLSProxies, then relayed through with Proxy-Authorization: Basic0x8273190

The write calls to the three rc files were located, but the exact line appended to them was not isolated. The strings and symbols recovered from the binary contain no anti-debug, anti-VM or sandbox-evasion checks, and the only ptrace reference is the Go stdlib wrapper. The operator-triggered KILL handler at 0x8279f5d is the only self-deletion path, with no timer or date trigger behind it.

The router exploit chain

main.StartScanner (0x827e190) generates random public IPv4 addresses, filters RFC1918 space, and fingerprints Boa and TOTOLINK router web interfaces over tcp/80. The router-exploit requests and the HTTP floods both draw on a six-entry User-Agent rotation pool whose literals begin at 0x839ff11, 0x83a0467, 0x83a1041, 0x83a164e, 0x83a1c17 and 0x83a2042. The scanner then takes one of two routes onto the device. On the first it logs in and solves the vendor CAPTCHA by posting {"topicurl":"setting/getSanvas"}. On the second it fetches the device’s /config.dat and runs it through main.Decode (0x827e610) to recover the stored credentials. The transform inside main.Decode was not reversed; it decodes victim router configuration and has no bearing on the C2 address.

With a session in hand, the scanner injects a shell command through POST /boafrm/formSysCmd. That command fetches the second stage over HTTP from a runtime-supplied host on a fixed port, built from the template http://%s:5001/bins.sh at 0x838fdb0. The second stage is the payload a loader fetches and holds the capability the operator wants. The host is filled in at runtime, so the static view names the port and the path but not the distribution server.

The sweep items not yet resolved

A byte sweep found 22 network indicators the recovered profile does not list, among them 1[.]1[.]1[.]1, 1[.]2[.]1[.]1, 1[.]2[.]2[.]1, 1[.]3[.]1[.]1, 119[.]0[.]0[.]0 and 120[.]0[.]0[.]0. The candidate embedded payload, a gzip stream at offset 0x1fbb45, still needs carving and analysing separately.

Family
unclassified
First seen
September 22, 2026
Vector
Runs as a ddos-bot/worm; the entry vector is not established by static analysis
Format
5800 KB x86 ELF 32-bit LSB executable
VirusTotal
Not on VirusTotal
Tags
ddos-bot · elf · raw_tcp · worm · x86
Sample
By request. Email security@kinryu.sh

SHA-256

  • 59bdafde87693987c862fee7e25d25f483fd732fe41f1555b67955aac5e6446e as captured

Analysis performed using an automatic malware analysis pipeline using Binary Ninja

← All captures