TLP:CLEARCierre 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.
 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.

Error 1 — “Prometei”. El kit de minero multi-arquitectura venía etiquetado como Prometei en MalwareBazaar, y lo repetí durante dos sesiones. Era RedTail. La etiqueta venía de un solo reportero; cuando la verifiqué contra la muestra, no estaba ninguno de los marcadores públicos de Prometei, y sí estaban los de RedTail: los archivos subidos se llamaban 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.
Error 2 — “el config cifrado”. Una muestra de minero traía ~300 KB de datos tras el trailer de UPX. Lo anoté como una posible configuración cifrada —justo lo que tendría un Prometei, lo que reforzaba el error 1—. Los abrí: eran símbolos RTTI de la biblioteca estándar de C++ en claro, el final no comprimido de un binario C++ estático. No una carga anti-desempaque. Una anomalía de formato tomada por una intención.
Error 3 — “la exclusión”. En el bot ARM de la entrega III leí, en una lectura rápida, que su limpiador excluía el directorio /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.

agente vs plantilla · puntaje por sesión
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                 — plantilla

Una 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ónValor
Ventana2026-08-10 → 2026-11-03 (86 días)
Eventos totales10.227.820
IPs distintas16.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 aceptados355.239 · 3.840 IPs · 162.440 credenciales distintas
Credencial más probada345gs5662d34:345gs5662d34 (3.385 veces, 1.935 IPs)
Peticiones web104.033 · 6.230 IPs · 12.638 rutas distintas
Muestras únicas recogidas858
IPs que tocaron ≥2 sensores1.463
IPs vistas más de 30 días312

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ácticaTécnicaEntrega
ReconocimientoT1595.002/.003 Escaneo de vulnerabilidades y por diccionarioI, II, V
Acceso inicialT1190 Explotar aplicación públicaV
Acceso inicialT1078 Cuentas válidasI, III, IV
EjecuciónT1059.004 Shell de UnixI, III, IV
EjecuciónT1610 Desplegar contenedorIV
PersistenciaT1098.004 Llaves SSH en authorized_keysIV
PersistenciaT1053.003 / T1543.002 / T1037.004 Cron / systemd / scripts RCIII, IV
Escalada de privilegiosT1611 Escape al anfitrión (Docker)III, IV
Escalada de privilegiosT1548.003 Sudo con la contraseña del loginIV
Evasión de defensasT1014 Rootkit (ld.so.preload)IV
Evasión de defensasT1036.005 Enmascaramiento con nombre legítimoIII
Evasión de defensasT1497.001 Chequeos del sistema (anti-sandbox)I, II
Evasión de defensasT1027 / T1070 Ofuscación y borrado de huellasIII, IV
Acceso a credencialesT1552.001 Credenciales en archivos (.env, .oci, configs de IA)I, V
Acceso a credencialesT1552.005 Metadatos de la instancia (SSRF a IMDS)I, V
Acceso a credencialesT1110 Fuerza brutaII, III, V
DescubrimientoT1082/T1083/T1057/T1046 Sistema, archivos, procesos, redI, II, V
Descubrimiento en nubeT1580 Infraestructura de nubeI
Comando y controlT1105 / T1571 Transferencia de herramientas / puerto no estándarIII
RecolecciónT1213 Datos de repositorios (Elasticsearch)V
ImpactoT1496 Secuestro de recursos (cryptojacking)IV
ImpactoT1498/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)ObjetivoCoincidenciasEntrega
HP_Handshakebins_Botbot Gafgyt ARM (tls_cfkill, lista blanca con sus disfraces)familiaIII
HP_Handshakebins_Droppersu instalador handshakebins.shfamiliaIII
HP_Iran_Mirai_VariantMirai iran.* (8/8)familiaIII
HP_RedTail_Installersetup.sh de RedTail (dos variantes)2IV
HP_XMRig_SupportXMR_Configminero con la cartera concreta de este operador1IV
HP_Linux_Processhider_Preloadrootkit de usuario vía ld.so.preload1IV
HP_Docker_API_Host_Escapecuerpo de escape al host (bind del raíz + Privileged)532IV

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:

hpintel · 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.