DIICOT · Capítulo 27
Solo el líder habla
El kit se quedó quieto en el disco, así que lo encendí yo en una jaula sin salida. Dentro hay un bot que exige saber su propia dirección antes de nada, se une a una malla de hasta dos mil nodos, celebra una elección y se corona líder — y solo entonces abre un chat de Telegram. El operador no entra en ninguna máquina: manda un mensaje al jefe de la manada. Y cuando le quemas el chat, la botnet se cura sola.
En el capítulo anterior el kit llegó entero y no llegó a arrancar: se estrelló contra un montaje noexec. Así que lo que hace no me lo enseñó el cebo — me lo tuvo que enseñar el laboratorio.
De los cinco módulos que traía dentro, el que manda es el más pequeño: dos megas y pico, un fichero llamado cache. No mina nada. Su trabajo es decidir quién mina y cuándo, y para eso necesita recibir órdenes. Cómo las recibe es lo que va en este capítulo.
01Antes de encender nada
Esto se detona en una jaula: una máquina virtual dentro de un espacio de red propio, sin ruta a internet, con el bicho corriendo como usuario sin privilegios. Pero «sin salida» hay que demostrarlo cada vez, no suponerlo — si el aislamiento falla, lo que sale es un nodo de botnet real conectándose a una malla real.

La prueba es tonta y por eso funciona: intentar llegar a un par de sitios que siempre contestan. Si alguno responde, no se detona nada y se arregla la jaula primero.
02Exige saber dónde está, o se muere
Lo primero que hace al arrancar no es conectarse a su amo. Es preguntar cuál es su propia dirección pública. Y lo intenta tres veces, por este orden:
[WRN] self-hosted IP fail → 31.57.105.94:42 # un servicio propio del atacante
[WRN] api4.ipify fail → … # respaldo público
[WRN] ifconfig attempt 1..5/5 fail # respaldo público, cinco veces
[ERR] pub IP fail after all methods — exiting # y se apagaSiete intentos, unos cincuenta segundos, y si no lo consigue se apaga solo. En una máquina sin salida a internet, este bicho no llega a hacer nada.
La forma de sacarlo del atasco fue darle lo que pedía: un servicio falso, dentro de la propia jaula, que le devuelve una dirección inventada de las reservadas para documentación. Con eso se lo cree y despliega todo. Obsérvese la asimetría: para verlo funcionar no hay que dejarle salir, hay que mentirle.
03Se corona líder
Con su dirección en la mano, monta la red. Y aquí es donde deja de parecer un minero:

Cuatro cosas pasan en ese arranque, y cada una añade una pieza:
Escucha en el puerto 8081 y se anuncia ahí. No es un cliente que llama a casa: es un nodo que también recibe.
Lleva un vecino de arranque grabado a fuego — una dirección concreta a la que llamar la primera vez, para entrar en la red. Es el problema del huevo y la gallina de toda red entre iguales: para conocer a alguien hay que conocer ya a alguien.
Se propone llegar a dos mil conexiones y, si tiene pocas, se pone a buscar más por su cuenta. La malla no es un adorno: está dimensionada.
Y celebra una elección. El nodo empieza como seguidor, y en cuanto ve que no hay nadie por encima se proclama jefe. Entonces, y solo entonces, abre el canal con su operador.
Aquí solo uno habla con el exterior, y el resto se entera por la malla. El operador manda un mensaje y la orden llega a miles de máquinas sin que él se conecte a ninguna. Y si el líder cae, la malla elige otro. Para quien defiende, la consecuencia incómoda es que puedes tener un nodo de esto en tu red sin verle jamás una conexión sospechosa: tu máquina solo habla con otras víctimas.
04Por qué strings no dice nada
Lo normal, con un bicho así, es pasarle la herramienta que saca los textos legibles del fichero y ver aparecer direcciones, dominios, rutas. Aquí no sale nada: ni el dominio del chat, ni el identificador del bot, ni una sola de las palabras que acabas de ver en pantalla.
El motivo es el ofuscador con el que lo compilaron. Guarda cada texto cifrado en el fichero y lo descifra en memoria justo antes de usarlo, con un bucle de dos líneas que mezcla una tabla y una semilla que también viajan dentro.

Contra eso hay dos caminos. El lento es leer el código y deshacer el cifrado a mano, tabla por tabla. El rápido es dejar que lo descifre él: arrancarlo, congelarlo en marcha y leerle la memoria. Ahí están todos los textos, ya en claro, porque el programa necesita usarlos.
Es la lección más reutilizable del capítulo: un ofuscador protege el fichero, no la ejecución. Todo lo que el programa necesite entender, tendrá que descifrarlo — y en ese momento está a la vista de quien mire.
05El que manda, y la reja de la puerta
De la memoria sale el canal, y es de lo más cómodo que hay: un bot de Telegram. El nodo líder pregunta cada pocos segundos si hay mensajes nuevos, con una petición que lleva dentro el identificador del bot:
GET https://api.telegram.org/bot8778142498:AAE2YhxC6AB5PF8GOucHxCviYV4FA1JJnIE/getUpdates?offset=0&timeout=30
Host: api.telegram.org
User-Agent: skemaTiene su gracia como decisión de diseño. El tráfico va a un dominio legítimo por el que pasa medio mundo, cifrado, y no hay servidor propio que tirar: mientras Telegram funcione, el canal funciona. Ese skema del final es lo único que desentona — un identificador de navegador que no se parece a nada, y que por eso sirve de firma.
Y hay un detalle de oficio: no usa el servidor de nombres de la máquina. Se trae el suyo dentro y resuelve el dominio por su cuenta, saltándose el del sistema. Quien vigile su red mirando qué nombres pregunta cada equipo, a éste no lo ve preguntar.
Lo siguiente era la pregunta obvia: si el canal es público y el identificador está a la vista, ¿puede mandarle órdenes cualquiera? Le inyecté comandos desde un Telegram de mentira montado dentro de la jaula. Respuesta:
{"chat_id":…,"text":"Unauthorized."}Hay una reja. El bot compara quién manda el mensaje con un número guardado en su interior y, si no coincide, no hace nada. Leerlo exigió bajar al código y después al proceso en marcha: el número vive en un campo concreto de su estructura interna, y ahí estaba.

06El repertorio, y cómo se llama a sí mismo
Pasada la reja, el bot obedece. Éste es su repertorio completo:
/peers lista los vecinos que conoce
/connect ip:port añade uno a mano
/leader ip designa quién manda
/hub ip designa un supernodo: todos convergen ahí
/check ip ¿está esta máquina en la malla?
/update reparte un binario nuevo por la malla ← el importanteEse /check merece una pausa. Sirve para preguntarle a la red si una dirección concreta está infectada. Es la herramienta de un operador que quiere saber si ya tiene dentro a un objetivo antes de gastar esfuerzo en él — o si lo ha perdido.
Y al pedirle el estado, el bot se presenta. Esto es lo que contesta:
DIICOT-BOTNET
Nodes : 1 | Cores: 4 | Miners: 0
RAM : 3.8 GB | Disk: 19.6 GB
Ver : v2-update-1Ahí está la firma, y no me la ha dado ningún antivirus ni ninguna etiqueta de comunidad: el propio programa dice cómo se llama. Lleva el nombre de la familia escrito en su panel de control, junto al recuento de nodos, núcleos y mineros activos — un cuadro de mando para el que cobra.
Y trae número de versión. v2-update-1: la segunda generación, primera actualización. Alguien lleva la cuenta.
07La jugada maestra: se cura sola
Queda el comando importante. /update no descarga nada de fuera. Hace algo bastante más elegante:

El nodo abre su propio fichero, lo parte en más de mil setecientos trozos y los reparte por la malla. Los demás nodos los recomponen, se quedan con la versión nueva y se reinician solos. No hay servidor de descargas, no hay dominio que bloquear, no hay ni una conexión al exterior: el binario viaja de víctima en víctima.

Y ahora júntalo con lo de antes, porque es donde encaja todo. El identificador del bot de Telegram está a la vista de cualquiera que abra la muestra — y Telegram cancela los que se filtran. Cuando eso pasa, el canal muere. Parecería el final.
No lo es, porque la malla no depende de Telegram. Los nodos siguen hablando entre ellos, y el cifrado de ese canal usa como semilla el identificador que llevan grabado: sigue valiendo como clave aunque Telegram ya no lo acepte. El operador recupera el mando por ahí, lanza un /update con una compilación nueva —con un identificador nuevo dentro— y la red entera se renueva sola.
Para tumbar esto de verdad hay que ir a los nodos, uno a uno. No hay un enchufe central que desconectar — que es exactamente para lo que se diseñó así.
Lo cual deja una pregunta incómoda sobre la muestra que tengo delante: su identificador ya no funciona. Está cancelado. Y eso, en un bicho recién salido, puede significar dos cosas muy distintas — que la campaña está muerta, o que se renovó hace tiempo y esto es una versión abandonada.
08Indicadores (IOCs)
Los de la llegada están en el capítulo 26. Éstos son los del mando.
| Tipo | Valor |
|---|---|
| Puerto de la malla | TCP 8081 — escucha y se anuncia; objetivo 2.000 conexiones |
| Vecino de arranque | 91.92.47.220:8081 (NL, ASN 197170 TechTies; en Shodan aparece además como escáner) |
| Servicio «cuál es mi IP» | 31.57.105.94:42 · respaldos api4.ipify.org e ifconfig.me |
| Canal de mando | api.telegram.org/bot<id>/getUpdates?offset=N&timeout=30 — con resolutor DNS propio |
| Identificador del bot | 8778142498:AAE2YhxC6AB5PF8GOucHxCviYV4FA1JJnIE (ya cancelado) |
| User-Agent | skema — no se parece a ningún navegador: buena firma de red |
| Número del operador | 6059167279 — el único autorizado a dar órdenes |
| Comandos | /peers /connect /leader /hub /check /update |
| Se identifica como | DIICOT-BOTNET, versión v2-update-1 |
| Fichero de vecinos | peers.dat, con la semilla p2p-peers-salt-v1 |
| Mineros que dirige | xmrig · ccminer · nbminer · gminer · bminer · t-rex y los algoritmos randomx · kawpow · etchash |
La detección más barata de todas: una máquina que escucha en el 8081 y habla con otras máquinas cualesquiera por ese puerto. Un servidor normal no hace eso. Y si además sale hacia Telegram con un agente llamado skema, ya no hay duda.
Continuará — quedan dos cabos, y los dos son de dinero. El primero: cómo sé que el identificador está cancelado, que no lo deduje, lo comprobé. Y el segundo, el que de verdad importa — este kit trae dos mineros y ninguno lleva dentro la cartera a la que cobrar. La configuración de minado no viaja con el bicho: la baja después, de un sitio que hay que ir a buscar. Fui. En el Capítulo 28. 🍯
Comentarios