ES EN
Index

DIICOT · Chapter 34

DIICOT: One syllable apart

Comes from chapter 33 · DIICOT: Ciocolata flavour

The executor from the last chapter calls a machine I already knew and keeps as a fallback a domain that looks far too much like one that did exist. Pulling on that one-syllable difference brings out its big brother, the previous C2 and the slot it uses to get into its victims. In the end, I asked the other side what it sends.

The last chapter left the critter open on the table: a command executor that calls 91.92.47.220:222, introduces itself with Ciocolata and hands bash whatever it's sent. And it left two loose ends. The fallback domain, which rang a bell. And the first line the server sends, which the critter throws away without looking at it.

Neither gets resolved inside the binary. I started with the address, because that one I already knew.

01The thread to DIICOT

It was the one that made me look twice. This is what ties the critter to the series, split into what I saw and what I deduce:

what ties it, and what doesn't
seen      91.92.47.220: here, the C2 on 222. In chapter 27, the mesh's seed on 8081
seen      same network: AS197170 TechTies
seen      the same range, 77.239.124.0/24, dropped into /tmp/cache the mesh bot (7-9 Oct) and this executor (15 Oct)
seen      Go, 2026, and the same kind of obfuscator: every string encrypted, decrypted right before use
seen      nothing of the mesh inside: no 8081, no Telegram, no peers.dat, no DIICOT-BOTNET, no miners
seen      its hash matches no sample from chapters 23 to 28
deduced   another piece of the same setup: not the mesh bot, something else

Then I looked at the machine without touching it: what Shodan and Censys had already gathered on their own, without me sending it a single packet.

one machine, four roles
91.92.47.220    AS197170 TechTies · Netherlands or United Kingdom, depending on the source
  22     SSH                   same key from August to October, updated month by month
  1337   distribution          served a file to an intruder on the decoy in October
  8081   mesh seed             visible: answers «auth:bad»
  222    this executor         invisible to Shodan and to Censys
  …      hundreds more ports, the pattern of a scanner

Shodan has scanned it 878 times since August, on 652 different ports. Port 222 hasn't shown up once, and not in Censys either, not even as an open, silent port. Maybe the server stays quiet until someone says Ciocolata to it, or maybe that port hasn't been open for long: this C2 appears with the sample, in mid-October. From the outside you can't tell which.

The SSH tells a different story: the same machine key for months, and the SSH server moving up a version with every patch. It isn't an abandoned machine: someone looks after it.

Last, I searched for other machines with that same key, in case the operator had cloned the image onto more servers. Shodan gave me one candidate that turned out to be a coincidence in its own index (a different service that happened to share the same internal number), so I discarded it. Censys, which is the right source for this, returned a single result: the machine itself.

Censys result for the machine's SSH key: a single host, 91.92.47.220, with the services SSH, 2082, 6009, 8081, 23518, 27562 and 29508
A single answer. Censys, searching for any machine with the same SSH key: only this one shows up. Its list of services includes the mesh's 8081. Not 222.
What I don't claimI'm not saying it's the same operator. I'm saying it shares machine, network, build style and even delivery channel with the 2026 variant, and does something else. That's a link through infrastructure, not a signature. Asking that machine what answers on 222 wouldn't settle it either: whatever it says isn't signed. For most of the investigation I ruled it out, so as not to tip off the operator. In the end I did it, carefully, and it's in section 03. But before that, a syllable saved me.

02One syllable apart

Searching for the fallback domain, hotel.wildhorsehotnet.net, in case anyone had seen it, another almost identical one came up: hotel.wildhorsehotel.net. Where the critter says hotnet, that one says hotel. And it carries malware detections.

The first thing was to check I hadn't got it wrong when decrypting. I hadn't. On the wire, each piece of a domain name travels with its length in front, and the critter sent a 15. wildhorsehotnet has 15 letters; wildhorsehotel, 14. The binary asks for hotnet. The difference is its, not mine.

So I looked at the other one's history, without touching it: what passive DNS, VirusTotal and urlscan already had stored.

hotel.wildhorsehotel.net, according to the passive records
Feb 2025            served by Njalla                     # the favourite of those who'd rather not give a name
Jun-Oct 2025        hotel. → 5.178.96.15
Feb 2026            expires · "renew your domain" page
23 Apr 2026         someone else registers it · parked on Google Cloud

A domain somebody used for a year, let expire and lost. Today it belongs to someone else, with every sign of being a parked domain. The detections it carries are the legacy of its past; today it isn't an indicator.

And who used it? VirusTotal keeps track of which files asked for that name when run. There are eight. Two are called ciubuc_x86 (ciubuc is a Romanian word) and are a Mirai/Gafgyt from June 2025. The rest are big binaries, eight to eighteen megabytes packed with UPX, that wipe other people's cron, kill the competition by name and ask a service of their own what their public IP is; one of them sweeps SSH and installs itself in cron. In one of them that service is 31.57.105.94:42. The same one as in chapter 27: the first one the mesh bot asked.

And the 2025 IP, 5.178.96.15: VirusTotal has eleven files talking to it, between July 2025 and April 2026, and the ones I've looked at do so on port 222. ThreatFox lists it as a C2 since July, with these tags: Diicot, Mexals and ElPatrono1337, the signature on the SSH key in chapter 28.

Among those eleven was one of almost three megabytes, unpacked. I ran the fuzzy hash against ours: 13. The closer to zero, the more alike. That alone doesn't prove much: in two Go binaries almost everything is the engine, and the hash mostly measures the workshop. What proves it is the code, and I'm getting there. It arrived packed under the name cache, and it was dropped by those big bots, several of them named Update on disk. In chapter 26, /tmp/cache was already among the things the chain leaves behind. Our sample, seen through those eyes, also arrived packed and was also called cache.

The proof that mattered was still missing. I pulled the sibling from MalwareBazaar and, without running it, searched it for the call chain from the last chapter with a search tool that knows nothing about either of them; I'd tested it on ours first, and it pulled out the domain on its own:

each one's second address, read from the file
sibling   (2025)   28 numbers, K = 0x48   →   hotel.wildhorsehotel.net:222
ours      (2026)   29 numbers, K = 0x12   →   hotel.wildhorsehotnet.net:222
                                                           ^^^

The same trick, in the same spot in the program and with the same port. The seed changes because the obfuscator draws it at random on every build. In the fallback, one syllable changes, and one more letter is one more number in the chain. In the bot, more changed: the new version's main function is twice the size, and it's the one that adds the ten-second wait and throws away the first line. The old one has neither.

the executor, version by version
                 C2                     fallback
2025 → Oct 2026  5.178.96.15:222        hotel.wildhorsehotel.net:222    # the domain expires in February
Oct 2026         91.92.47.220:222       hotel.wildhorsehotnet.net:222   # nobody has registered it

Both versions came through my decoy three days apart. On 12 October, the old cache arrived with the worm, without anyone uploading it by name, and called 5.178.96.15:222 with its Ciocolata. On the 15th, the new one was uploaded straight over scp by the 77.239.124.0/24 range, and called 91.92.47.220:222. And earlier, from the 7th to the 9th, that same range had dropped something else into the same /tmp/cache: the mesh bot from chapter 26, same hash.

cache is a slot, not a programIt's a fixed name that gets filled with whatever is due: the mesh bot one week, the executor the next. That's why the script's clean-up starts by killing anything called that before uploading the new one. If you find a /tmp/cache, the name doesn't tell you what it is. It tells you who put it there.

And the sibling left one more thing, as a gift. In March, in one of VirusTotal's sandboxes, its C2 was still answering. The critter ran this:

what the previous C2 told the sibling, as seen by VirusTotal
bash -c "ClientID: 27813"

The server greets with a client number, and the old version handed it to bash as if it were a command. The new one, ours, throws away the first line without looking at it: the thing that puzzled me in the last chapter. It fits as a fix between versions, and the code backs it up: it's exactly what the old one lacks. In the next section, today's C2 shows it.

What I don't claimI don't know whether hotnet is a deliberate change or a finger that slipped. Nor do I know who owns wildhorsehotel.net today; I know it doesn't look like the operator, and that's why it isn't in the indicators. The ThreatFox tags are a third party's. What is seen is that the old fallback was lost, and nobody has bought the new one yet. If today's C2 went down, the critter would ask for an empty name.

03What the other side said

For most of the investigation I held that you don't ask port 222 anything. In the end I thought it over again. What's behind it isn't a door hidden for one: it serves anyone who says Ciocolata, and it's built for hundreds of infected machines. One more connection doesn't stand out. The condition was that it shouldn't come from any machine of mine.

So it came from one that has nothing to do with the decoy, the lab or this blog. The program was very short and did one thing only: introduce itself the way the critter would, with a made-up machine name, and listen. It doesn't answer, doesn't obey, doesn't call back. Whatever arrives it stores in hexadecimal, and nothing more.

half a second of conversation
0.000   →  Ciocolata · <made-up name>        # the greeting, once only
0.053   ←  ClientID: <n>                      # the banner: a number
0.054   ←  1,316 bytes, five lines of shell    # the commands
  …     ←  nothing else                       # we didn't answer; no heartbeat

The first line is a client number, like the ClientID the old C2 sent the sibling on VirusTotal. And that settles what puzzled me in the last chapter. The critter throws away the first line because the server always starts with it. If it ran it, bash would answer ClientID: command not found, which is exactly what the old version did. The real commands come after.

I'm not printing the exact number I got: it's the fingerprint of my connection. But there are two others that can be used, because the sibling received them in VirusTotal's sandboxes, from its C2 at the time:

two ClientIDs from the previous C2, seen by third parties
10 Dec 2025   CAPE     ClientID: 5842
 5 Mar 2026   Zenbox   ClientID: 27813
              ──────────────────────────
              about 22,000 more in 85 days   ≈ 260 a day · ≈ 11 an hour

If it's a counter, and if nobody reset it in between, that server was getting eleven calls an hour. But those are calls, not victims. The critter leaves after ten seconds if nobody talks to it, every time something relaunches it a new number gets used, and a single machine that keeps trying can burn through dozens a day. Sandboxes and curious people like me count too. It's the door's pulse, not the size of the fleet.

And what comes after the banner asks for nothing secret. It's five lines, five commands the bot runs one by one, and all of them ask for measurements:

the commands, summarised
1  how many cores     nproc
2  how much memory    free -m
3  how much disk      df -m /
4  how much download  against speed.cloudflare.com, up to four downloads at once
5  how much upload    the same, uploading ten megabytes of zeros
                      with curl if it's there; otherwise, with wget

No passwords, no files, no keys. It's what someone does when they have lots of machines and need to decide what to do with each one: this one has eight cores, this one has a fat pipe, this one is no good for anything. The first thing it asks every victim is how much it can deliver. And it isn't the first time I've seen it. Before uploading anything to the decoy, the 77.239.124.0/24 range asked the same thing another way: nproc, lspci, nvidia-smi looking for a graphics card. Two different pieces with the same obsession.

This, by the way, isn't something I uncovered. The first four commands were already out in the open: on 14 October, the day before the critter landed on the decoy, VirusTotal's sandboxes ran it, the C2 answered them and the triage was recorded, letter for letter the same. What the listening added is the banner, the order in which everything arrives and the fifth command, the upload one, which doesn't appear there.

What it does with those numbers afterwards, I don't know. To find out I'd have to send them back, and at that point I'd stop listening and start playing on their side.

What was done, and what wasn'tOne connection, once, from outside, and only to listen. The program can't run anything it receives because it has nothing to run it with. It didn't answer, didn't send a heartbeat and didn't call back. Nothing was measured and nothing was sent back. speed.cloudflare.com shows up in the commands, but we didn't touch it. With 5.178.96.15 and the two domains there was no contact at all.

04Indicators

The binary's are in the last chapter. These are the infrastructure's and the family's.

TypeValue
Primary C291.92.47.220:222 (TCP, plain text; AS197170 TechTies; the same machine is the mesh seed on 8081, chapter 27, and distributes files on 1337)
Fallback C2hotel.wildhorsehotnet.net:222 (unregistered as of November 2026: dormant fallback)
Previous C25.178.96.15:222 (seen from July 2025 to October 2026; in ThreatFox as Diicot; rented IP, may change hands)
C2 bannerClientID: <n> as the first line, before the commands
First commands seenfive-line triage: cores, memory, disk, download and upload against speed.cloudflare.com (legitimate service: what gives it away is the pattern, not the domain) · in VirusTotal sandboxes since 14 October 2026; received again, with the upload, on 2 November
Delivery77.239.124.0/24 (SSH brute force with a Go client, scp of /var/tmp/<8 letters> and /tmp/cache, /tmp/d.log marker holding the guessed password)
Downloadshxxp://91.92.47[.]220:1337/<6 letters>/c (the same machine also distributes files)
Name on disk/tmp/cache is a slot: it has held the mesh bot and both versions of this executor · the old one is dropped by the worm (Update), the new one arrives straight over scp
C2 SSH keySHA-256 ba13ccd57a8dce8d84f49deacdcbe1697035bd8a577b34c5c63cb1758182448f · MD5 dc:d0:64:24:28:b0:cf:cc:cc:3d:8e:b7:c0:48:43:40
SHA-256 sibling6041b27598fa7db6df3364ba1e1d94268616bef7ccab5cd48c2646b6a7d087e2 (unpacked from 640c817722a4cd22251fcff100fdba167b7dfff885f36b5f64f2d59c52514180)

If a server, without anyone asking, starts measuring its speed against speed.cloudflare.com with several threads at once, someone is taking its measurements.

To be continued - the decoy stays lit. I already know the first thing its master sends every new machine: a tape measure. What comes after the measuring, only whoever sends the numbers back will find out, and nothing gets sent back from here. 🍯

Comments