TLP:CLEARÍndice de la serie. Las IPs de los sensores aparecen enmascaradas como `` y ``; los sensores ya fueron retirados. Todas las cifras salen de scripts reproducibles cuya salida quedó archivada como evidencia.

El 10 de agosto de 2026, temprano por la mañana, cambié una regla de firewall para que el puerto 22 de una máquina virtual dejara de llegar a su sshd y empezara a llegar a un impostor. A los pocos minutos ya había alguien adentro probando contraseñas. No lo había invitado nadie; estaba ahí desde antes, golpeando la puerta de verdad, y lo único que cambió fue que ahora la puerta se abría.

Ochenta y seis días después apagué todo. Entre una fecha y la otra quedaron diez millones de eventos, y esta serie es lo que saqué de ellos. Son seis entregas y esta, que es la cero: la que explica qué era el señuelo, cómo estaba armado, cuánto recogió y dónde está cada cosa. Se lee primero y se escribió al final, porque un mapa solo se puede dibujar cuando ya se caminó el terreno.

1. Qué se montó#

Dos máquinas virtuales en Oracle Cloud, con direcciones sin relación aparente entre sí y dos papeles distintos.

La primera, <sensor-ssh-web>, hacía de servidor de aplicaciones. En el puerto 22 respondía Cowrie, un honeypot SSH de interacción media: acepta el login, entrega una shell falsa con un sistema de archivos de utilería, registra cada comando y guarda lo que el visitante descarga o sube. En el 80 y el 443 respondía un nginx configurado para decir 200 OK a cualquier ruta y guardar la petición entera, con cabeceras y cuerpo.

La segunda, <sensor-servicios>, hacía de caja con bases de datos expuestas por error. Corría Beelzebub, que emula servicios a partir de archivos de configuración: Redis en el 6379, la API de Docker en el 2375, Elasticsearch en el 9200, Postgres en el 5432, MySQL en el 3306 y VNC en el 5900. Ninguno era el servicio real. Cada uno sabía responder a un puñado de preguntas y anotaba todas las demás.

flowchart LR
    NET(("internet"))
    subgraph OCI["Oracle Cloud"]
        S1["#lt;sensor-ssh-web#gt;\nCowrie · SSH 22\nnginx catch-all · 80 / 443"]
        S2["#lt;sensor-servicios#gt;\nBeelzebub\nRedis · Docker · Elasticsearch\nPostgres · MySQL · VNC"]
    end
    OUT["salida: DROP por defecto\nsolo DNS, NTP\ny 80/443 con registro"]
    subgraph CASA["casa"]
        COL["colector\npull cada 6 h\nllave de solo lectura"]
        ST[("store\nSQLite")]
        HP["hpintel"]
    end
    NET -->|ataques| S1
    NET -->|ataques| S2
    S1 -.-> OUT
    S2 -.-> OUT
    S1 -->|logs y muestras| COL
    S2 -->|logs| COL
    COL --> ST --> HP

Las flechas hacia casa indican el sentido del dato, no el de la conexión: la conexión la abría siempre el colector. En el store, las dos máquinas son tres sensores lógicos: vm1-cowrie, vm1-web y vm2-services. Esos nombres aparecen en las terminales de toda la serie.

La decisión que más pesó fue la credencial. Cowrie estaba configurado para dejar entrar a casi cualquier combinación de usuario y contraseña, y el nginx para no devolver nunca un 404. Eso multiplica lo que se recoge, porque nadie se queda afuera, y también es la forma más fácil de reconocer un señuelo. Las dos consecuencias tienen su entrega: lo que entró, en la III y la IV; cómo me descubrieron, en la II.

2. Cómo se aisló#

Un honeypot es una máquina que uno pone a propósito en manos de desconocidos, así que la primera pregunta de diseño es qué pasa si la usan.

La contención principal no está en el firewall: está en que nada de lo que traen los visitantes se ejecuta. Cowrie no es una shell, es un programa que imita una; cuando alguien sube un minero y lo lanza, lo que ocurre es que queda un archivo guardado y una línea en un log. Beelzebub tampoco crea contenedores ni escribe en ningún Redis. En ochenta y seis días no corrió en esas máquinas una sola instrucción ajena.

El firewall era la segunda capa, por si la primera fallaba. La política de salida de las dos máquinas era descartar por defecto, con excepciones contadas: DNS, NTP, y HTTP/HTTPS permitidos pero registrados paquete a paquete. El 80 y el 443 tenían que salir porque así es como Cowrie recoge muestras: cuando el visitante escribe wget http://…/bot.arm, es Cowrie quien va a buscarlo para archivarlo. El correo saliente estaba cortado de forma explícita. Todo lo demás se descartaba y quedaba anotado.

Ese registro de salida sirvió para comprobar la política contra los hechos. De los intentos de conexión nueva que el firewall cortó en la máquina de SSH, 126 fueron hacia la misma dirección: 90 por FTP y 36 por TFTP contra 213.232.114.14, el repartidor de la botnet de la entrega III. Era el plan B de su instalador para cuando wget no alcanza, y murió en la regla por defecto.

En las dos máquinas corría además CrowdSec en modo de pura detección, sin bloquear a nadie. Bloquear en un honeypot es tirar el dato. Y el acceso de administración iba por otro puerto, solo con llave.

3. El viaje a casa#

Los sensores no sabían nada de mi casa: no guardaban credenciales, no iniciaban conexiones hacia mí, no conocían ninguna dirección mía. El flujo iba siempre en el otro sentido. Un colector en un contenedor de mi red doméstica salía cada seis horas a buscar los logs por SSH, con una llave propia que no daba shell: en cada sensor estaba atada a un envoltorio con una lista de cinco lecturas permitidas, y cualquier otra orden devolvía un error y dejaba un aviso en el log. Si alguien comprometía el sensor, no encontraba nada que apuntara a casa. Si alguien comprometía el colector, obtenía permiso para leer cinco archivos de un señuelo.

Lo que llegaba se normalizaba y se guardaba en un store SQLite: una fila por observación (quién, cuándo, en qué sensor, contra qué servicio, qué hizo) y un archivo por cada binario o script capturado, nombrado por su SHA-256. El colector y su etiquetado de escáneres conocidos vienen del pipeline que conté en Separatio: Construyendo un Pipeline de Threat Intelligence Autónomo con IA Local.

El store guarda la acción recortada. El comando entero, la versión del cliente y los replays de terminal vivían solo en los sensores, y Cowrie rotaba esos logs cada catorce días. Ese límite, y el día en que el pull se rompió sin que yo lo notara, están contados en la entrega VI.

4. El panorama en números#

panorama del store
hpintel stats | head -18
── panorama ──────────────────────────────────────────────────────────────
 ventana      2026-08-10T06:58 → 2026-11-03T21:33
 eventos      10.227.820
 IOCs         16.203
── por servicio ──────────────────────────────────────────────────────────
 vnc            9.381.527 eventos   2.276 IPs
 ssh              675.823 eventos   3.961 IPs
 web              104.033 eventos   6.230 IPs
 postgres          19.304 eventos   1.403 IPs
 redis             17.977 eventos   1.931 IPs
 mysql             11.221 eventos   1.654 IPs
 docker             9.894 eventos   1.033 IPs
 elastic            7.977 eventos   1.488 IPs
 ssh-download          64 eventos      25 IPs
── IPs por nº de sensores ────────────────────────────────────────────────
 1 sensor(es)   14.631
 2 sensor(es)    1.427
 3 sensor(es)       36

Una precisión sobre la cuarta línea, porque la cifra se repite en toda la serie. Los 16.203 indicadores son 16.094 direcciones IP —una de ellas mía, así que las ajenas son 16.093— y 109 huellas HASSH de clientes SSH, que el store guarda en la misma tabla. Cuando en las otras entregas digo “dieciséis mil”, hablo de las direcciones.

Por SSH hubo 355.239 logins aceptados desde 3.840 direcciones, con 162.440 pares distintos de usuario y contraseña. Por web, 104.033 peticiones a 12.638 rutas distintas. De todo eso quedaron 858 muestras únicas. Y solo 1.463 direcciones tocaron más de un sensor: casi todos los visitantes hacen una sola cosa en un solo puerto y se van.

Dos gráficos de la serie diaria entre el 10 de agosto y el 3 de noviembre de 2026. Arriba, IPs distintas por día: la línea de todas las IPs oscila entre 300 y 500 en agosto, salta a unas 900 a comienzos de septiembre, baja a unas 500 a inicios de octubre y sube hasta el máximo de 1.058 el 26 de octubre; la línea que excluye a las que solo hablaron VNC se mantiene casi plana alrededor de 400 durante toda la ventana, con un único pico de 800 el 4 de septiembre. Abajo, eventos por día en barras apiladas: el VNC domina todas las barras, con un máximo de 561.161 eventos el 30 de agosto, mientras todo lo demás es una franja delgada en la base. Siete días de agosto aparecen sombreados como días sin datos en el store.
La serie diaria. Arriba, cuántas direcciones distintas llegaron cada día; abajo, cuántos eventos dejaron. Datos: el store, una consulta agrupada por día.

El gráfico de arriba es el que conviene mirar. Sin el VNC, la línea es casi una recta: unas cuatrocientas direcciones nuevas o repetidas cada día, desde la primera semana hasta la última, sin tendencia. Ese es el ruido de fondo de internet contra una dirección cualquiera de una nube, y no depende de que uno haga nada para atraerlo. Todo el relieve del gráfico (el escalón de septiembre, el valle de octubre, la subida final) lo pone un solo servicio.

Hay siete días de agosto sombreados: el 13, el 19 y el 20, y del 23 al 26. El store no tiene ninguna observación de esas fechas. Los sensores estaban arriba; lo que falta es el dato, y no pude reconstruir la causa con lo que quedó. La ventana es de ochenta y seis días y los días con datos son setenta y nueve.

5. La trampa del VNC#

El gráfico de abajo es el mismo periodo contado en eventos, y es casi todo de un color. El 92 % de las filas del store, 9.381.527 de 10.227.820, son VNC.

qué decían los clientes VNC
hpintel top vnc | head -4
── top vnc ───────────────────────────────────────────────────────────────
 4753548  2273 IPs  
 2730552   621 IPs  RFB 003.003
 1895244   993 IPs  RFB 003.008

Nadie estaba atacando nada. El protocolo de VNC empieza con un saludo: el servidor anuncia su versión, el cliente responde con la suya, y el servidor le dice qué tipos de autenticación acepta. Mi emulador hacía bien el primer paso y mal el tercero. A los clientes que respondían con la versión 3.8 les mandaba un byte donde el protocolo espera dos, y a los que respondían con la 3.3 no les mandaba nada. El saludo nunca terminaba. El cliente esperaba, se rendía, y volvía a conectar. Cada vuelta dejaba dos filas en el store: la versión que anunció y el silencio que siguió.

Un escáner bien hecho abandona después de unos intentos. Estos no. La dirección más insistente, una máquina de DigitalOcean, dejó 362.604 eventos en treinta y cuatro días con ráfagas de unas ocho conexiones por minuto.

Proveedor (ASN)IPsEventos de VNC% del bucle
DigitalOcean (AS14061)1174.767.60950,9 %
Contabo (AS51167)521.339.09314,3 %
Alibaba (AS45102, AS37963)163714.3427,6 %
Tencent (AS45090, AS132203)137696.3717,4 %
OVH (AS16276)13172.1671,8 %
todas las que solo hablaron VNC1.7439.365.852100 %

La concentración es alta pero no es un puñado: la mitad del volumen sale de 26 direcciones, y hacen falta 322 para llegar al noventa por ciento. En el otro extremo, 603 de esas 1.743 direcciones dejaron menos de diez eventos, que es lo que deja un escáner que prueba y se va. El bucle es un mismo programa desplegado en cientos de máquinas alquiladas, sobre todo de DigitalOcean, que no sabe qué hacer cuando el otro lado no contesta.

Lo cuento como trampa porque casi caigo. Diez millones de eventos es un titular, y nueve de esos diez millones son un error de configuración mío amplificado por clientes que no manejan el fallo. Cualquier ranking por volumen (el país más activo, el proveedor más ruidoso, el día más intenso) habría terminado midiendo ese bucle y nada más. Por eso toda cifra de la serie que mezcla servicios está calculada sin él, y por eso la tabla que sigue lo deja afuera.

6. Quién llamó#

Sin las direcciones que solo hablaron VNC quedan 14.350, con 849.847 eventos. Ordenadas de las dos maneras posibles cuentan dos historias distintas.

Por cantidad de IPsIPsEventos
Google Cloud (AS396982)1.41731.420
Microsoft (AS8075)1.3833.687
DigitalOcean (AS14061)1.1757.966
Bandwidth (AS25369)8972.248
Driftnet (AS211298)6213.261
Amazon (AS14618)5592.478
Tencent (AS132203)4141.636
Onyphe (AS213412)315599
Censys (AS398324)2783.852
Oracle (AS31898)24812.036
Por cantidad de eventosIPsEventos%
BanatSync (AS198364, Bulgaria)150373.60444,0 %
Unmanaged Dedicated Servers (AS47890)3740.4524,8 %
Techties (AS197170)7632.2783,8 %
Google Cloud (AS396982)1.41731.4203,7 %
DMZHOST (AS48090)2830.8433,6 %
HiNet (AS3462, Taiwán)1629.2613,4 %

La primera tabla es de nubes y de escáneres. Muchas direcciones, pocos eventos cada una: la firma de quien recorre internet entero y le dedica a cada dirección dos o tres paquetes. Driftnet, Onyphe y Censys son empresas que se dedican a eso y lo declaran; las dejo en una cubeta aparte en la entrega V.

La segunda es de quien vino a quedarse. Un solo sistema autónomo búlgaro, con 150 direcciones, puso el 44 % de todos los eventos que no son VNC, casi todo por SSH: 188.455 logins desde ahí. De AS47890 y AS48090, más abajo en la tabla, salió la campaña de mineros .16 de la entrega IV.

Por país, el orden de las direcciones es Estados Unidos (6.404), Reino Unido (1.533), China (1.052), Singapur (569) y Francia (440). Lo anoto y lo desactivo en la misma línea: ese dato dice dónde está registrado un bloque de direcciones de un proveedor de nube, no dónde está sentado nadie. Una IP de nube no es una persona, y esa frase es el título de la primera sección de la primera entrega por algo.

7. El retiro#

El 3 de noviembre dejó de llegar el dato y una semana después apagué los sensores. Antes de borrar nada copié todo: los replays de terminal, los logs completos, las descargas, las capturas web crudas, los logs de Beelzebub, las alertas de CrowdSec, las reglas de firewall y el registro de salida. Trece archivos con su SHA-256 anotado en un manifiesto. Borrar una máquina virtual es irreversible, y lo más valioso del corpus —lo que el visitante de la primera entrega tecleó, pulsación por pulsación— solo existía ahí.

El análisis de toda la serie corrió sobre esa copia y sobre un snapshot de solo lectura del store. El procedimiento completo, y los tres errores que cometí analizándolo, están en la entrega VI.

8. Cómo se hizo#

Con una herramienta de línea de comandos, hpintel, escrita para este corpus sobre los enriquecedores de separatio. Las ventanas de terminal que aparecen en las seis entregas son su salida, sin retocar: reputación de una IP en ocho fuentes, veredicto de un hash, línea de tiempo de un actor, sesiones y replays de Cowrie, agrupación de IPs por infraestructura compartida. La regla fue que ninguna cifra entrara a un post si no salía de un comando que se pudiera volver a ejecutar.

Las muestras se analizaron en estático. Ninguna se ejecutó.

9. El mapa#

Las entregas se pueden leer sueltas, pero están pensadas en este orden: primero el caso raro, después el catálogo de lo común, al final el método.

I — El visitante de Jerusalén. Una IP de Oracle Cloud pasó tres días cazando credenciales de OCI en los tres sensores. Leyó lo que el señuelo respondía, se tropezó con sus mentiras, cambió de herramienta cuatro veces y terminó demostrando que el servidor aceptaba cualquier contraseña. El único caso, entre dieciséis mil, que se comportó como si estuviera pensando.

II — Cómo te descubren. Todas las formas en que los visitantes intentaron averiguar si el servidor era real: baterías de fidelidad con nonce, contraseñas imposibles, canarios web, un contenedor que solo calcula una cuenta. Y mis propios delatores.

III — Botnets de alquiler. Un bot ARM que llegó catorce veces en cuatro semanas sin que su autor le quitara los símbolos, un Mirai que jura no serlo, y un actor que tocó la misma puerta por SSH y por Docker.

IV — Minar en casa ajena. RedTail y su instalador que se delata solo, una llave SSH que 2.029 máquinas empujan al mismo authorized_keys, y la API de Docker abierta como la puerta más ancha de todas.

V — Lo que la web pregunta. Las CVE que llegaron con payload, la caza de .env y de credenciales de agentes de IA, la SSRF contra los metadatos de cuatro nubes, y qué emulador sirvió de carnada y cuál se delató.

VI — Lo que aprendió el señuelo. El cierre: cadena de custodia, errores corregidos, puntos ciegos, el mapa MITRE consolidado y el catálogo de reglas de detección.

Las entregas técnicas comparten esqueleto: hallazgos, indicadores, MITRE ATT&CK y detección, en ese orden.

10. El paquete#

Los indicadores de toda la serie están reunidos en un paquete TLP:CLEAR, en tres formatos con el mismo contenido: un bundle STIX 2.1 para OpenCTI, un evento MISP, y CSV con listas planas para todo lo demás. Se descarga de acá: honeypots-oci-2026-iocs.zip (2 MB, sin contraseña; suma SHA-256).

Va en dos niveles, porque no todo lo que llamó a la puerta merece una regla. El núcleo es lo accionable: 228 direcciones con un papel concreto —servidores de descarga, C2, inyectores, abuso de la API de Docker, y las citadas en las entregas—, 53 URL de descarga, 59 hashes de archivos completos con familia o detección, y las cuatro llaves SSH que los atacantes dejaron plantadas. El resto es contexto: 12.758 direcciones con su ASN, su país, su rol y sus fechas de primera y última vista, sin marca de detección y con caducidad a los noventa días. Fuera de los dos niveles quedan, solo en CSV y etiquetadas, las 1.382 direcciones de escáneres declarados y las 1.743 que solo hablaron VNC: ninguna de las dos cosas es un ataque. Completan el paquete las quinientas credenciales más probadas y las 109 huellas HASSH.

Los 59 hashes salen de un inventario de 858 entradas. De ellas, 620 eran cuerpos de peticiones a la API de Docker y no archivos; 94, subidas cortadas cuyo hash no es el del binario real; 21 pesaban menos de 64 bytes, y 63 eran cuerpos de otras peticiones HTTP. Quedaron sesenta archivos completos, y uno solo sin clasificar.

Las muestras no están en el blog ni van a estar. Publicar malware vivo en un sitio estático es una mala idea y viola los términos del servicio que lo aloja. Lo que cada entrega publica son los hashes y los enlaces a los reportes públicos de MalwareBazaar y VirusTotal, que alcanzan para verificar cualquier afirmación sin depender de que yo conserve el binario.

Las direcciones de los sensores tampoco aparecen, ni ahora que no existen. La nube recicla sus direcciones, y publicar la de un señuelo retirado es dejarle una reputación quemada a quien la reciba después.

La serie empieza por el único visitante que miró de vuelta: Ochenta y seis días de señuelo · I — El visitante de Jerusalén.

commit 0x56000

Date: 2026-08-10 11:33 AM

redirect 22 -> 2222; the door opens now. logging everything.