Photo by Christopher Robin Ebbinghaus / Unsplash

Two identical bots, one invisible

Aug 7, 2026

Two files landed in the honeypot five days apart, from two different IP addresses. Both were exactly 29,427 bytes. Both were the same Perl IRC bot.

One of them, dropped as /duba, is flagged by 29 of 60 engines on VirusTotal as trojan.perl/shellbot. It has been submitted, catalogued, and signatured.

The other, dropped as /dodu, has no VirusTotal record at all. Not a clean verdict — no record. Nobody has ever uploaded it.

That pair is the most useful thing in this capture, and it is a good argument for running your own honeypot rather than only consuming other people's feeds.

The capture

Twenty-five samples, collected between 28 July and 7 August 2026, sorted into seven families:

Family What it is
MIRAI_OHSHIT Multi-arch IoT botnet, 16 architectures
MIRAI_TELNETCURL Telnet-propagated Mirai variant, 5 architectures
PERLBOT_SHELLBOT Perl IRC shellbot, the twins above
GSOCKET_SSHIT Abuse of a legitimate security tool for persistence
MIRAI_LOADER Unobfuscated Mirai loader
BOTKILL_PROCWIPE Competitor removal — not a bot at all
WEBROOT_PROBE Mass RCE verification, 224 sightings

Nineteen of the twenty-five arrived over telnet. In 2026.

The twins, properly

/duba and /dodu are the same size but not the same file — their MD5, SHA-1 and SHA-256 all differ. They are two builds of one bot, and the difference is the config block:

/duba:  my $server = '213.139.77.150';  my $port = '6667';
/dodu:  my $server = '213.177.179.11';  my $port = '6667';

Different C2 servers, different /16. A third sample, /gots, points at the same server as /dodu and also has no VT record.

So blocking the well-known IP accomplishes about a third of the job. This is the ordinary shape of the problem: the sample everybody has is the one that stopped being useful to the operator.

There is a further wrinkle. All three bots contain this line:

$server = "$ARGV[0]" if $ARGV[0];

The C2 is overridable at launch. Any IP-based block is defeated by restarting the bot with an argument. The control that actually holds is an egress block on tcp/6667 — and outbound cleartext IRC from a server or IoT subnet is close to nonexistent on a modern network, so it costs almost nothing in false positives.

A turf war in the loot

Two samples arrived as /home/.k, written straight over telnet. Neither is a bot. Both are short shell scripts that kill things.

The first walks /proc and kills any process whose executable has been deleted from disk:

result=$(ls -l "/proc/$pid/exe" 2> /dev/null)
if [ "$result" != "${result%(deleted)}" ]; then
    kill -9 "$pid"
fi

Self-deleting after execution is standard IoT-botnet hygiene, so this reliably kills other people's bots while leaving normal daemons running.

The second is more targeted. It reads each process's command line and kills anything containing the string dvrHelper.

dvrHelper is the output filename used by MIRAI_LOADER — another family in this same capture, fetching mirai.<arch> from 77.90.185.66. One operator is actively hunting another's payload on the same boxes.

The practical consequence: a host with /home/.k on it has been compromised by at least two separate actors. Reimage it. Don't clean it.

C2 that dresses as infrastructure

The seven MIRAI_OHSHIT payloads carry an identical, compiled-in domain set:

api-relay-3.metrics-collector.io
cdn-edge-updates.hostcloud-eu.net
mgmt-panel.serverstats-daemon.com
sync.softwaremirror.workers.dev
glibc.malloc.top
control.tor2web-relay-fast.onion

A metrics collector. CDN edge updates. A server stats daemon. A software mirror. And glibc.malloc — a hostname built to survive a tired glance at a DNS log.

Because the set is byte-identical across ARM, ARM7, SH4, MIPS, PowerPC, i686 and x86-64, it is compiled in rather than per-build. That means a string-based rule covers the nine architectures the loader fetches that we never captured.

Those payloads also embed a full SSH client — ssh-ed25519, curve25519, chacha20. The loader chain is telnet-only, so anyone scoping containment from the dropper alone will miss the SSH vector entirely.

The most-seen sample is the least interesting file

By sighting count, the two clear winners are these, at 168 and 56 hits over nine days:

#!/bin/sh
echo "xxxxxx"

Twenty-four bytes. Written to /var/www/html/filter over SSH.

It is a capability probe. The operator writes a trivial script into the webroot, requests it, and looks for xxxxxx in the response. A hit confirms both webroot write access and script execution — after which they come back with something real. The absence of a payload is timing, not luck.

Writing a YARA rule for this would be malpractice; echo "xxxxxx" in a two-line shell script will match test fixtures and scaffolding across any estate. The value is entirely in the 18 source addresses, which rotate about two per day inside five /24s:

2.57.122.0/24   92.118.39.0/24   80.94.92.0/24
195.178.110.0/24   193.32.162.0/24

Per-host blocking will always lag that rotation. Block the ranges.

A mistake worth publishing

Partway through, I searched the ELF payloads for domains and concluded there weren't any interesting ones. I had anchored the pattern like this:

[^a-z0-9.-][a-z0-9-]{2,20}\.top\b

The anchor requires a non-label character before the domain. Every real domain in those binaries is multi-label, so the character before metrics-collector.io is a dot — which that class explicitly excludes.

The anchor didn't remove noise. It removed the signal, and it would have suppressed five live C2 domains.

Both failure modes are real. An unanchored pattern run over raw bytes invents domains that don't exist. An over-anchored one silently drops the ones that do, and a false negative doesn't announce itself. Match against extracted strings, not raw bytes, and allow multiple labels.

What is published

Everything above is in the repo, TLP:WHITE:

  • blocklist.txt — 41 IPs and 5 domains, plain newline-delimited
  • Annotated firewall entries with family, role and confidence
  • Port and egress rules, including the IRC block a target list can't express
  • YARA, Suricata and Sigma rules, validated against YARA 4.5.5 with zero cross-family false positives
  • A written analysis per family, and all 25 samples AES-256 encrypted

Deliberately not in the blocklist: GitHub Pages (185.199.108.153) and Cloudflare (104.21.234.17), both of which appear inside these binaries. Also gsocket.io and thc.org — one payload abuses THC gsocket, a legitimate published security tool. Attribute the abuse, not the tool.

Every exclusion is written down with its reasoning, so you can check the work rather than trust it.

https://github.com/Afterpacket/drosera-threat-intel