ventana 2026-08-10 → 2026-11-03
eventos 10.227.820
IOCs 16.203
Diez millones de eventos en ochenta y seis días. Puesto así no significa nada, y esa es la primera lección de tener un honeypot: el volumen no es la historia, es el ruido del que hay que extraer la historia. Las cinco entregas anteriores fueron las historias —el visitante de Jerusalén, los que me ponían a prueba, las botnets de alquiler, los mineros, lo que pregunta la web—. Esta es sobre cómo las saqué, qué me costó creer de más, qué no pude ver y qué dejo para el que monte el próximo. Es la entrega menos narrativa y la que más me interesa escribir, porque un hallazgo sin su método es un rumor.
1. La cadena de custodia#
Un honeypot produce evidencia, y la evidencia que no se puede reproducir ni verificar no vale como evidencia: vale como anécdota. Me impuse una regla desde el primer día —toda cifra del post sale de un script, y la salida del script queda guardada— y una segunda al final, cuando llegó el momento de apagar los sensores: copiar todo antes de borrar nada, porque borrar una VM en la nube es irreversible y la IP se recicla.
El retiro fue un procedimiento, no un rm. Con las claves de administración, por tar a stdout para no escribir en los sensores, me traje los replays de terminal de Cowrie (2.480 sesiones), los logs completos, las descargas, las 47.012 capturas web crudas, los logs de Beelzebub, las alertas de CrowdSec y el registro del tráfico de salida. Trece archivos, cada uno con su SHA-256 anotado en un MANIFEST junto con la fecha y el comando que lo produjo. Recién después se borraron las VMs. Un snapshot del store —la base de datos donde el colector iba acumulando las observaciones— quedó como copia de solo lectura, y sobre ese snapshot corrió todo el análisis posterior.
Ese orden importa por una razón concreta: la parte más valiosa del corpus, los replays de terminal que me dejaron ver lo que el atacante de la entrega I escribía en vivo, solo existe en los sensores. Si hubiera apagado primero y pensado después, habría perdido la única evidencia que convirtió a ese caso en una reconstrucción y no en una conjetura.
2. Tres cosas que creí y eran falsas#
Lo más útil que puedo ofrecer no son los aciertos, sino los errores, porque todos tienen la misma forma y la misma cura. Los tres nacieron de tomar una fuente intermedia —una etiqueta, una anomalía, una nota vieja— por el dato, y los tres se corrigieron de la única manera que funciona: volviendo a la muestra.
redtail.*, el instalador caía en el literal redtail, y dos fuentes independientes marcaban su infraestructura como RedTail. Lo conté entero en la entrega IV./var/sofia/ de un DVR. Al decompilar la función con calma, las dos ramas del condicional devolvían cero: era código muerto. El bot no excluía nada; el autor había dejado la intención a medio escribir.La lección no es “cometí tres errores”. Es que los tres eran creíbles —encajaban con lo que ya pensaba— y que ninguno sobrevivió al contacto directo con la muestra. Verificar contra el dato, no contra el reporte ni contra la propia nota de la semana pasada, es barato y es lo único que corrige. Dejé los tres escritos en la serie a propósito: el próximo que lea “Prometei” para uno de esos hashes merece saber que ya se revisó.
3. Lo que el honeypot no pudo ver#
Un diseño honesto declara sus puntos ciegos. Estos son los míos, y los dejo anotados porque cada uno es una decisión que el próximo puede tomar distinto.
- Catorce días de memoria fina. Cowrie rota sus logs completos cada catorce días. El store guardaba un resumen de cada evento desde el 10 de agosto, pero el comando entero, la versión del cliente y la huella HASSH solo sobrevivían en los logs crudos de los últimos catorce días. Para todo lo anterior tengo el qué y el cuándo, no siempre el exactamente cómo. Si lo volviera a montar, enviaría los logs a un almacenamiento externo desde el primer día.
- Un pull que se rompió. El mecanismo que traía los datos de los sensores al colector se cayó el 3 de noviembre por un timeout, y no me di cuenta hasta el retiro. El noviembre del sensor de servicios solo existe porque lo recuperé a mano al apagar. Un honeypot sin monitoreo de su propia tubería de datos tiene agujeros que uno descubre tarde.
- Una tabla de enriquecimiento vacía. El esquema del store tenía una tabla para cachear la reputación de cada IP; nunca persistió nada. Todo el enriquecimiento (AbuseIPDB, VirusTotal, GreyNoise, ThreatFox…) lo corrí después, contra el snapshot, con su propia caché en disco. No perdí datos, pero descubrí que una parte del diseño no hacía lo que yo creía. Un esquema no es una garantía de comportamiento.
- El bucle de VNC. Nueve de cada diez eventos del corpus son VNC: millones de reconexiones contra un handshake que mi emulador implementaba mal, de cientos de máquinas alquiladas atrapadas en un reintento infinito. No es tráfico de ataque; es un error mío amplificado por bots que no manejan el fallo. Lo conté en la entrega cero. Aquí vale como advertencia: si no se separa, ese ruido ahoga cualquier estadística. Toda cifra de la serie que mezcla servicios se calculó excluyéndolo.
- La cuota de las fuentes. GreyNoise community da 25 consultas por semana; 16 de mis IPs clave dieron error de cuota. Ninguna cifra de la serie depende de GreyNoise, justamente por eso. Una metodología que se apoya en una sola fuente de pago hereda sus límites.
4. ¿Agente o plantilla? La métrica y su honestidad#
La pregunta que arrastré toda la serie —¿cuántos de estos atacantes se comportan como si leyeran lo que el señuelo responde, y cuántos recitan un guion?— la convertí en una métrica. Seis señales por sesión: usa canarios, reacciona a los cebos del señuelo, acepta contraseñas imposibles, muta sus scripts entre intentos, sondea la shell, estructura su salida con delimitadores. El resultado, sobre todo el corpus, es deliberadamente poco espectacular.
hpintel agentic
── agente vs plantilla ───────────────────────────────────────────────────
ip score sens eventos señales
84.13.83.244 6 3 770 canary, decoy_reaction, random_password,
script_mutation, shell_probe, structured_output
20.80.86.196 2 1 11 random_password, script_mutation
(el resto) 0-1 — plantillaUna sola IP de dieciséis mil llega a seis de seis: el visitante de Jerusalén. La única otra que pasa de uno es un detector de honeypots de Azure, con dos. Todo lo demás —los mineros, las botnets, los barridos web, las fuerzas brutas— puntúa cero o uno: plantilla. Y esto es lo que me parece honesto admitir: la métrica tiene un falso positivo conocido y corregido. Varias señales (“muta sus scripts”, “acepta contraseñas raras”) las disparan también cosas que no son inteligencia —un instalador que genera un nombre al azar en cada envío, un banner de acuse que parece un canario—. Las revisé una por una. Cuando se descuentan, el número no sube: baja. La conclusión incómoda de la serie es que casi nadie mira, y la métrica, bien calibrada, lo confirma en vez de inflarlo.
5. El panorama, una vez#
Las cifras del corpus, reunidas en un lugar para que no haya que buscarlas por las seis entregas:
| Dimensión | Valor |
|---|---|
| Ventana | 2026-08-10 → 2026-11-03 (86 días) |
| Eventos totales | 10.227.820 |
| IPs distintas | 16.093 (más una mía y 109 huellas HASSH: 16.203 indicadores) |
| Eventos de VNC (ruido del handshake roto) | 9.381.527 (≈92 %) |
| Logins SSH aceptados | 355.239 · 3.840 IPs · 162.440 credenciales distintas |
| Credencial más probada | 345gs5662d34:345gs5662d34 (3.385 veces, 1.935 IPs) |
| Peticiones web | 104.033 · 6.230 IPs · 12.638 rutas distintas |
| Muestras únicas recogidas | 858 |
| IPs que tocaron ≥2 sensores | 1.463 |
| IPs vistas más de 30 días | 312 |
Dos números dicen casi todo. El primero: el señuelo aceptaba 162.440 credenciales distintas, porque estaba configurado para dejar entrar a casi cualquiera —esa fue la decisión que lo hizo útil y, a la vez, fácil de detectar, como conté en la entrega II—. El segundo: solo 1.463 IPs tocaron más de un sensor. La abrumadora mayoría de los atacantes hace una sola cosa en un solo puerto y se va. Tratar dos direcciones del mismo objetivo como partes de lo mismo —lo que hizo el visitante de la entrega I— es, estadísticamente, rarísimo.
6. MITRE ATT&CK, consolidado#
El mapa de técnicas de toda la serie, con la entrega donde aparece cada una:
| Táctica | Técnica | Entrega |
|---|---|---|
| Reconocimiento | T1595.002/.003 Escaneo de vulnerabilidades y por diccionario | I, II, V |
| Acceso inicial | T1190 Explotar aplicación pública | V |
| Acceso inicial | T1078 Cuentas válidas | I, III, IV |
| Ejecución | T1059.004 Shell de Unix | I, III, IV |
| Ejecución | T1610 Desplegar contenedor | IV |
| Persistencia | T1098.004 Llaves SSH en authorized_keys | IV |
| Persistencia | T1053.003 / T1543.002 / T1037.004 Cron / systemd / scripts RC | III, IV |
| Escalada de privilegios | T1611 Escape al anfitrión (Docker) | III, IV |
| Escalada de privilegios | T1548.003 Sudo con la contraseña del login | IV |
| Evasión de defensas | T1014 Rootkit (ld.so.preload) | IV |
| Evasión de defensas | T1036.005 Enmascaramiento con nombre legítimo | III |
| Evasión de defensas | T1497.001 Chequeos del sistema (anti-sandbox) | I, II |
| Evasión de defensas | T1027 / T1070 Ofuscación y borrado de huellas | III, IV |
| Acceso a credenciales | T1552.001 Credenciales en archivos (.env, .oci, configs de IA) | I, V |
| Acceso a credenciales | T1552.005 Metadatos de la instancia (SSRF a IMDS) | I, V |
| Acceso a credenciales | T1110 Fuerza bruta | II, III, V |
| Descubrimiento | T1082/T1083/T1057/T1046 Sistema, archivos, procesos, red | I, II, V |
| Descubrimiento en nube | T1580 Infraestructura de nube | I |
| Comando y control | T1105 / T1571 Transferencia de herramientas / puerto no estándar | III |
| Recolección | T1213 Datos de repositorios (Elasticsearch) | V |
| Impacto | T1496 Secuestro de recursos (cryptojacking) | IV |
| Impacto | T1498/T1499 Inundación (DDoS) | III |
7. Las reglas#
A lo largo de la serie escribí reglas de detección para lo que vi, y las probé donde tenía con qué. Las de YARA corrieron contra todo el corpus de archivos —cerca de 48.000 únicos, incluidos cuerpos de peticiones y descargas crudas— y cada una coincidió solo con su objetivo: cero falsos positivos cruzados.
| Regla (YARA) | Objetivo | Coincidencias | Entrega |
|---|---|---|---|
HP_Handshakebins_Bot | bot Gafgyt ARM (tls_cfkill, lista blanca con sus disfraces) | familia | III |
HP_Handshakebins_Dropper | su instalador handshakebins.sh | familia | III |
HP_Iran_Mirai_Variant | Mirai iran.* (8/8) | familia | III |
HP_RedTail_Installer | setup.sh de RedTail (dos variantes) | 2 | IV |
HP_XMRig_SupportXMR_Config | minero con la cartera concreta de este operador | 1 | IV |
HP_Linux_Processhider_Preload | rootkit de usuario vía ld.so.preload | 1 | IV |
HP_Docker_API_Host_Escape | cuerpo de escape al host (bind del raíz + Privileged) | 532 | IV |
Las reglas de Sigma, Falco y Suricata las escribí en sus entregas, pero no las probé con un motor —no tengo Suricata ni un backend de Sigma en este entorno—, así que las presento como lo que son: puntos de partida razonados, no firmas validadas en producción. Cubren la persistencia por llave SSH y ld.so.preload, el contenedor privilegiado que monta el raíz, la SSRF a los metadatos de instancia en cualquier nube, el POST de PHP-CGI, el PUT de Hikvision y los marcadores de red más estables (/images/load, KANIT=, el delimitador __B_).
Una nota sobre las firmas: la del minero exige la cartera concreta de este operador, no el pool, porque el pool supportxmr.com:5555 aparece en 51 mineros del corpus con carteras distintas —una firma por el pool solo detectaría XMRig legítimo—. Es un indicador de este actor, no una firma de familia. La distinción vale para toda la serie: un indicador dice “vi esto”; una firma de familia dice “esto es tal cosa”, y confundirlos es exactamente el error de la sección 2.
8. El código#
Nada de esto se hizo a mano sobre diez millones de filas. Lo hice con una herramienta de línea de comandos, hpintel, construida sobre el pipeline de inteligencia que ya venía usando, con una salida pensada para pegar en un post como las terminales de esta serie y un volcado a JSON para archivar como evidencia. Doce subcomandos:
ip reputación en 8 fuentes (+ comentarios de la comunidad) hash MalwareBazaar + VirusTotal (familia, 1ª vista global) actor línea de tiempo de una IP en el store session sesiones Cowrie completas desde los logs crudos tty transcripts de los replays (lo que vio el atacante) agentic puntaje agente vs plantilla cluster IPs que comparten infraestructura top acciones más frecuentes de un servicio stats cifras del panorama inventory triage y orden de muestras iocs exporta IPs/URLs/llaves/credenciales/HASSH a CSV paquete paquete de IOCs: STIX 2.1 + MISP + CSV, en dos niveles
El código se apoya en los enriquecedores de separatio y en el esquema del store; la decompilación estática se hizo con una herramienta de ingeniería inversa por CLI, siempre sobre muestras que nunca se ejecutaron. Durante el análisis encontré y corregí un bug real en el pipeline: la consulta a ThreatFox buscaba la IP con coincidencia exacta y se perdía los indicadores en formato ip:puerto, que son casi todos. El “sin indicadores” de 43 IPs era falso; rehecha la consulta, ThreatFox conocía diez de ellas. Otro recordatorio de que la herramienta también es una fuente que hay que verificar.
9. El paquete#
Los indicadores de las seis entregas —IPs con su ASN y rol, URLs, llaves SSH plantadas, las 500 credenciales más probadas, huellas HASSH— están reunidos en un solo paquete TLP:CLEAR, en tres formatos: STIX 2.1, evento MISP y CSV. Se descarga de acá: honeypots-oci-2026-iocs.zip (2 MB, sin contraseña; suma SHA-256). Va en dos niveles: un núcleo accionable de 228 IPs con un papel concreto, 53 URLs de descarga, 59 hashes y 4 llaves SSH, y un nivel de contexto con otras 12.758 IPs, sin marca de detección y con caducidad a los noventa días. Las familias de los hashes son las del análisis de esta serie y no las etiquetas ajenas: el kit que MalwareBazaar firma como Prometei figura ahí como RedTail. Las muestras no van en el blog (malware vivo sobre GitHub Pages es una mala idea y una violación de términos de servicio); lo que va son los enlaces a sus reportes públicos en MalwareBazaar y VirusTotal, y los hashes, para que cualquiera verifique sin depender de que yo guarde el binario.
Las IPs de los sensores y la de mi casa no aparecen en ningún lado, ni siquiera ahora que las VMs están borradas: la nube recicla las direcciones, y publicar la de un sensor retirado quemaría al próximo inquilino que la reciba. Cada entrega pasó por un filtro que comprueba que no se haya colado ninguna.
10. Lo que aprendió el señuelo#
Ochenta y seis días mirando a dieciséis mil atacantes dejan una conclusión que no esperaba que fuera tan rotunda: casi ninguno mira de vuelta. El noventa y nueve coma nueve por ciento ejecuta un guion. Prueba la credencial de su lista, sube su binario, pide su .env, y nunca comprueba si lo que recibió tiene sentido. Mi honeypot era malo —aceptaba cualquier contraseña, respondía 200 a todo, se tropezaba con head -c— y a casi nadie le importó, porque casi nadie estaba leyendo las respuestas. La detección, para un atacante que no mira, es gratis: basta con no parecerse demasiado a una trampa, y ni eso hace falta.
La excepción fue una sola IP, y es la que me quita el sueño. El visitante de Jerusalén descubrió el señuelo porque leía cada respuesta, corregía cada error y volvía a preguntar. Para él, mirar no era un costo: ya estaba mirando para decidir el paso siguiente. Ese es el atacante contra el que un señuelo no sirve, y es también el que la industria está a punto de volver barato y abundante. Hoy, el que se adapta es uno de cada dieciséis mil. El día que leer cada respuesta y corregir sea el comportamiento por defecto y no la excepción, el honeypot que engaña al que no mira dejará de engañar a nadie. No porque los atacantes se vuelvan más listos. Porque dejarán de tener prisa por no mirar.
Mientras tanto, el señuelo cumplió su única función: preguntarle a internet qué hace cuando cree que nadie lo ve, y anotar la respuesta. La respuesta fue diez millones de líneas largas y una sola de ellas interesante. Las dos cosas son el hallazgo.
Gracias por leer hasta acá.
commit 0x56494
Date: 2026-11-11 23:59 PM
teardown complete; 16093 asked, 1 listened. closing the log.