Honeypot capture
mozi
A honeypot sensor network captured a 137,480-byte MIPS ELF sample, and the analysis ran statically between 8 and 12 September 2026. The analysis loaded the sample as data, never ran it, and recovered 17 command-and-control endpoints across 15 distinct hosts, including the bare IP literals 130[.]239[.]18[.]159, 188[.]200[.]144[.]6, 212[.]129[.]33[.]59 and 82[.]221[.]103[.]244. C2 is the channel an infected machine uses to reach its operator for instructions. All 17 carry an agreement verdict from the second backend.
The analysis classifies the sample as Mozi and types it as a DDoS bot, a worm and a loader in one statically linked binary; a loader is a small first-stage program whose only job is to fetch and start the real payload. The bencode KRPC handling and the acsMozi / Mozi.m artefacts are the family signature.
The sample builds for a single architecture, which the analysis records as the signature of a campaign aimed at routers, cameras and other embedded devices, not at servers, and it describes such hardware as rarely patched, rarely monitored and permanently online.
The DHT command channel
The C2 channel has no server component that a defender could seize. The bot bootstraps from an 8-entry node table at 0x49acd4, read by sub_4197e8 at 0x41983c, walks the DHT with find_node toward its own node ID, and accepts a configuration blob from whichever peer offers one (0x41ac7c, ATT&CK T1071). The bot sends bencoded KRPC over UDP/6881, the BitTorrent port, so its traffic blends with legitimate torrent flows (T1571).
recvfrom at 0x41c3e8 reads into a 1536-byte buffer, and sendto at 0x41840c writes over the socket(AF_INET, SOCK_DGRAM, 0) created at 0x41aa04. KRPC messages are self-delimiting bencode, classified at 0x417138 against the literals "1:q4:ping", "1:q9:find_node", "1:q9:get_peers" and "1:q13:announce_peer". There is no magic value and no length field.
sub_40ecbc verifies an ECDSA-P384 signature over the operator config before anything is dispatched. The routine decompresses a 49-byte compressed public key (parity bit ‖ X), multiplies the point by a scalar with double-and-add, and splits the signature into r‖s at offset +0x30. A config the bot will accept must be signed with the operator’s private key, which is not present in the sample; the bot holds verify-only public keys at 0x49acf4 and 0x49ad28. Relaying an already-signed config requires no key at all. The emulator in reproduction/ answers DHT housekeeping — ping and find_node — but cannot deliver an accepted [cnc], [atk] or [dr] config, because such a config has to carry a signature made with the operator’s private key.
Table 1: The bot’s 8 DHT bootstrap nodes
Values as they appear in the bootstrap array at 0x49acd4, defanged.
| Value | Port | Role | VA |
|---|---|---|---|
dht[.]transmissionbt[.]com | 6881 | primary | 0x4197e8 |
router[.]bittorrent[.]com | 6881 | primary | 0x441718 |
router[.]utorrent[.]com | 6881 | primary | 0x441734 |
bttracker[.]debian[.]org | 6881 | primary | 0x441750 |
212[.]129[.]33[.]59 | 6881 | fallback | 0x44176c |
82[.]221[.]103[.]244 | 6881 | fallback | 0x441780 |
130[.]239[.]18[.]159 | 6881 | fallback | 0x441794 |
87[.]98[.]162[.]88 | 6881 | fallback | 0x4417a8 |
The 4 IP literals exist so bootstrap survives DNS failure, although they are public bootstrap services just as the 4 domain names above them are. The analysis notes as much against the table:
router[.]bittorrent[.]com,router[.]utorrent[.]com,dht[.]transmissionbt[.]comandbttracker[.]debian[.]orgserve every legitimate BitTorrent client in the world… blocking them breaks lawful peer-to-peer traffic and does not disconnect an infected device, which stays in the DHT through any peer it has already learned. Alert on them; do not blindly block them.
One of those fallbacks, 212[.]129[.]33[.]59, also appears in 1 other analysed capture, which the analysis records as an indication that this sample belongs to a wider campaign.
The analysis lists 10 opcodes, each a bracketed ASCII tag that the bot parses out of the config or message body; its results summary records 5 documented commands, and the findings do not reconcile the two counts. Each opcode-to-handler mapping was confirmed by the second backend; the behaviour descriptions for [ud], [dr], [nd], [ss]/[sv], [idp] and [cpu] are one reading of each handler, inferred from the tag name and call shape rather than a full trace, and the last two are provisional.
Table 2: The opcodes and their handlers Opcodes as they appear in the config or message body.
| Opcode | Handler | Behaviour |
|---|---|---|
[cnc] | 0x40aeac | set C2/attack node and launch a DDoS |
[rn] | 0x419a84 | run a shell command, or fetch-and-run over the DHT socket |
[hp] | 0x4151c4 | set/parse an endpoint (host:port) |
[set]/[hj] | 0x41fa9c | configure HTTP hijacking / ad injection |
[ud] | 0x416890 | update — replace the running bot with a new image |
[dr] | 0x416d64 | download-and-run a payload |
[nd] | 0x41a1d8 | supply a DHT node list |
[ss]/[sv] | 0x419a84 | service/self control (start/stop, self-version) |
[idp] | 0x41ac7c | identity/ping tag carrying the botv2 build tag |
[cpu] | 0x419a84 | report/limit CPU or worker count |
The runtime target of a live [cnc] command arrives inside a signed config over the wire, so only the default config compiled into the sample is visible statically. The beacon interval is likewise unrecovered. The loop at 0x41ac7c re-bootstraps and polls with poll() timeouts of 3000 and 10000 ms, but the analysis isolated no fixed announce-interval constant and attaches a confidence of 0.40 to that unknown, against the 0.75 to 0.85 it attaches to most of the decoded HTTP config fields.
The XOR’d HTTP config at 0x44217c
The sample obfuscates a 122-byte blob at 0x44217c with a 6-byte repeating-key XOR, keeps the key 020304050607 at 0x442170, and decodes the blob in sub_41f908. The decoder is NUL-preserving: out[i] = in[i] ^ key[i % 6] unless that would produce a zero byte, in which case the input byte passes through, which keeps the C string intact. The decode validates itself, because the blob terminates in the literal ok. Decoded in full, defanged:
3+333#bi0u[.]com#g12g[.]com:/:g12gg[.]com/:5:0#.xelf:d[.]b12u[.]com/xelf:1#.xjs:js[.]b12u[.]com/go[.]js:1#echo 1#d[.]dns[.]la:188[.]200[.]144[.]6#ok
9 of the 17 endpoints come out of this one blob: bi0u[.]com, g12g[.]com, g12gg[.]com, d[.]b12u[.]com, js[.]b12u[.]com, d[.]dns[.]la, 188[.]200[.]144[.]6 on port 53, and the two payload references d[.]b12u[.]com/xelf and js[.]b12u[.]com/go.js. These 9 are attacker-controlled, and the analysis records them as the endpoints that should be blocked. The decode is certain; the role each field plays inside the hijack configuration is inferred from its position in the string, with no parser trace to confirm it, and 7 of the 9 carry confidence values between 0.75 and 0.85. The two path-bearing entries, read directly from the decoded bytes, are recorded at 0.90. The parser at 0x40b950 walks a {"http://", "https://"} table, strips a matching prefix when it finds one, and otherwise parses a bare host[:port]/path; because no code path in it prepends a scheme and the stored config carries none, that reading settled the endpoint disagreement described below.
Propagation and device lockdown
The bot spreads by telnet brute force and by router exploit. A telnet brute force at 0x443edc works through a roughly 60-entry credential dictionary heavy with vendor backdoor accounts — xc3511, vizxv, 7ujMko0vizxv, CenturyL1nk, @HuaweiHgw (T1110). Another 13 router and CPE RCE exploit templates at 0x48fa24 cover GPON, Netgear, Huawei CVE-2017-17215, TR-064, HNAP, UPnP, DrayTek, JAWS, Realtek and Netlink, each fetching http://[peer]:[port]/Mozi.[arch] (T1105). The 13 templates were enumerated from strings; the 22 KB engine at sub_426774 was not traced per exploit, so per-template behaviour is an open item.
Once installed, the bot restricts access to the device it has infected. 0x440bec firewalls the management ports 22, 23, 2323, 7547, 35000, 50023 and 58000 and sabotages the ISP’s TR-069 ACS by pointing its URL at 127.0.0.1, setting PeriodicInformEnable to 0 and the password to acsMozi. Persistence is by init script at 0x440e84, including /etc/init.d/S95baby.sh and an OpenWrt /overlay remount-and-install (T1037). It renames its own process with prctl(PR_SET_NAME) and kills rival bots and telnet daemons (0x42e180, T1036); the process check at 0x442940 runs killall -9 telnetd utelnetd scfgmgr. It learns its public IP from ipinfo[.]io/ip (0x4407fc) before announcing to the DHT.
The bot’s attack code is a Mirai-derived flood module at 0x425878. It keeps its strings behind a separate single-byte XOR 0x22 over 0x442aec–0x443058 that yields changeme[.]com, HTTPFLOOD, zollard and /bin/busybox MIRAI, and it offers HTTP flood, Source-engine query flood and raw-socket floods using IP_HDRINCL, selected by [cnc]/[atk] (T1498, T1499). Execution needs only root, plus outbound UDP/6881, an inbound UDP listener, outbound HTTP and raw sockets.
The analysis never submitted its 5 host artefacts to the cross-backend round, so all 5 are carried unverified and the generated Sigma rule is empty as a result. Those artefacts are /etc/init.d/S95baby.sh, the process identity Mozi at 0x444904, the state file /var/.ipds and config file /var/.config at 0x4405c4/0x4405cc, and /tmp/gpon8080 at 0x48d281, one reading of which is a dropped GPON exploit payload path.
Packing and sample identity
The sample is UPX-packed with the p_info field at file offset 0x80 deliberately zeroed, so stock upx -d fails with CantUnpackException while the binary still self-unpacks at runtime. The executable segment measures 7.8138 bits of entropy per byte — entropy being how random a file’s bytes are, a measure used to spot compression or encryption — which is consistent with a packed or encrypted payload rather than plain machine code. The header was repaired from the tail PackHeader (u_file_size=0x5e3c8 at file offset 0x218e4) and the image unpacked statically, without execution. The ELF section headers are stripped, which removes symbol names and defeats section-based tooling while the loadable segments still run. Every virtual address quoted above refers to the unpacked image (57744761595c…). The hashes identify the packed sample, which has SHA-256 f6c97b1e2ed02578ca1066c8235ba4f991e645f89012406c639dbccc6582eec8, MD5 3849f30b51a5c49e8d1546960cc206c7, SHA-1 61c74136534b826059c63221a2373dc0613a47b7 and ssdeep 3072:biMYFJvw6Yh0b1gKobtCGCmCRlrisfrYm:fYFJvwe1gKCYVl2szN, where ssdeep is a fuzzy hash that stays similar across small edits.
The dissector and its test vectors
reproduction/c2_dissect.py recovers the KRPC message type, the bot’s node ID and, where a config was in flight, the signed configuration and its command tags, while c2_client.py can impersonate the bot. Both touch the network only when explicitly given a --target, and the analysis contacted no endpoint in this report at any point. 3 of 3 test vectors round-trip and the constant-input and client round-trip checks pass, but every vector is origin: ["synthesised"] — bytes derived from the binary, checked against themselves — so agreement with real captured traffic is untested. The wire format is in protocol_spec.md; endpoints and verdicts in c2_profile.json; indicators in iocs.csv and blocklist.txt. The extractor reproduces all 17 endpoints and the XOR key from the raw file.
Blocking and hunting
The analysis recommends hunting MIPS or ARM CPE devices that emit sustained UDP/6881 DHT traffic while running no torrent client. Treat a device that beaconed as fully compromised and reflash it, because the command set includes shell execution and self-update and the bot rewrites the device firewall.
The beacon interval and the untraced exploit engine
The announce interval, the per-template behaviour of the 22 KB exploit engine at sub_426774, and an operator-supplied C2 node from a live [cnc] command are all unrecovered. Whether the recovered infrastructure is still live is unresolved.
- Family
- mozi
- First seen
- September 13, 2026
- Vector
- Runs as a ddos-bot/worm; the entry vector is not established by static analysis
- Format
- 134 KB mips ELF 32-bit LSB executable
- VirusTotal
- 49/74 engines: trojan.mirai/mozi
- Tags
- ddos-bot · elf · loader · mips · udp · worm
- Sample
- By request. Email [email protected]
SHA-256
-
f6c97b1e2ed02578ca1066c8235ba4f991e645f89012406c639dbccc6582eec8as captured -
57744761595c2dccdf76560c4e0fe7ea33ea85be281d1b7a9c9b4e9e9dbb0221unpacked payload
Analysis performed using an automatic malware analysis pipeline using Binary Ninja