
dns-honeypot
Como ingeniero que pasa la mayor parte de mis días inmerso en herramientas de observabilidad, de vez en cuando tengo una idea que simplemente tengo que llevar a cabo. Este fue uno de esos experimentos: levantar un resolvedor DNS en una IP limpia que nadie anuncie, y luego dejar que internet hable con ella de todas formas. La única función del resolvedor era permanecer en silencio, registrar todo y alimentar a Grafana con las consultas resultantes. Un docker compose up -d después, ya tenía Unbound, Loki, Prometheus, Grafana y Traefik rastreando tráfico en vivo e imprimiendo histogramas de curiosidad, mala configuración y algún que otro escáner. Este README es el informe de ese primer día: lo que captura la pila, por qué es importante para mí y lo que resalta sobre el panorama de seguridad actual.
Introduje intencionalmente cero señal de mi parte: sin descartes de paquetes, sin respuestas personalizadas, sin mitigación. Solo Unbound con el registro habilitado, Loki siguiendo el archivo de registro, Prometheus extrayendo métricas del exportador, Traefik sirviendo de fachada para Grafana y Docker Compose conectándolos a todos. El resolvedor se encontraba en 94.130.27.226, una IPv4 refrescantemente "limpia" que había encontrado (verifica su estado en https://www.abuseipdb.com/check/94.130.27.226 si quieres una línea base previa al ruido), y dejé que el mundo hiciera lo suyo. Un solo portátil podía observar todos los paneles, ejecutar tools/dns_query_storm.sh cuando quería agitar las cosas, y luego dejar que el ruido se asentara en los patrones que internet global eligiera enviar.
Puedes echar un vistazo en vivo a esos paneles en https://dns.cybersafeintl.co.uk/public-dashboards/eb554b5b74e14f4d95e376c0033ee83d, aunque están en el servidor más básico de la pila, así que espera actualizaciones lentas durante consultas pesadas.
unbound_total_num_queries del exportador de Unbound, por lo que el panel "Rendimiento (QPS, tasa 5m)" muestra consultas por segundo y las desglosa por origen. Esa vista responde a la pregunta "¿quién está golpeando el resolvedor?": los picos repentinos apuntan directamente a ASNs de Bangladés o Polonia, y los registros facilitan ver si las ráfagas van acompañadas de tormentas de SERVFAIL/NXDOMAIN.client_ip, y los paneles ya envuelven todo en topk(sort_desc(...)). Esto mantiene los paneles limpios, mientras que el script exportador me permite volcar las mismas consultas en CSV para análisis sin conexión, informes o historias reproducibles. La primera captura mostró cinco direcciones IP en los rangos 45.179.* y 45.6.*, cada una disparando más de 5k consultas en cinco minutos: ya sea una granja de escáneres o un cliente agresivo.qname en ventanas de 5m y 24h. La instantánea de 5 minutos mostraba scb.se, dhl.com y cmu.edu, mientras que la exportación de 24 horas incluía cbs.nl, scb.se, atlassian.com, y . ¿Por qué estos dominios? Esa es la parte interesante: ¿son servicios legítimos, resolvedores mal configurados o escáneres oportunistas buscando registros obsoletos? Envíame una nota si tienes una teoría.Cada panel que ves tiene un CSV correspondiente en exports/; comprímelos (zip -r exports.zip exports/) cuando quieras adjuntar la historia sin procesar a una publicación de blog o informe de incidente.
docker-compose.yml levanta Unbound, el exportador de Unbound, Loki + Promtail, Prometheus, Grafana y Traefik con un solo comando.unbound/ almacena configuraciones y registros del resolvedor. Los controles de TTL, serve-expired y la configuración de caché mantienen la fidelidad para que capturemos lo que los clientes realmente preguntan.prometheus/, loki/ y grafana/ contienen datos y archivos de aprovisionamiento para que las métricas y los paneles sobrevivan a los reinicios.grafana/dashboards/unbound-traffic-insights.json está preaprovisionado con la vista que ves; todas las consultas de PromQL/Loki ya agregan y ordenan para mantener los paneles legibles.tools/dns_query_storm.sh te permite simular tormentas de consultas cuando necesites probar los tiempos de reacción.redeploy.sh automatiza la bajada de toda la pila, la descarga de actualizaciones y la reconstrucción con un solo script.export_dashboard_data.py ahora recorre el JSON del panel, ejecuta cada consulta de Prometheus/Loki y escribe archivos CSV saneados en un directorio para compartir.
cd hetzner_deploy/unbound-dnscp .env.example .env y configura GRAFANA_DOMAIN, las credenciales de administrador de Grafana, LETSENCRYPT_EMAIL y cualquier anulación TLS que necesites.sudo chown -R 472:472 grafana-data && sudo mkdir -p prometheus/data && sudo chown -R 65534:65534 prometheus/datadocker compose build && docker compose up -dpip install requests (el exportador es Python puro).python export_dashboard_data.py --duration 24h --outdir exports/24h --timeout 90 para extraer cada consulta del panel, convertirla a CSV y colocar los resultados en exports/24h.zip -r exports.zip exports/ para empaquetar las tablas sin procesar antes de publicarlas, adjuntarlas a una publicación de blog o enviarlas a colaboradores.--duration 6h o marcas de tiempo --end para segmentos específicos, o usa --filter domains si solo quieres los paneles de dominios.scb.se, dhl.com, cmu.edu, up.pt y utc.fr generaron cada uno cientos de miles de consultas. ¿Por qué estos objetivos? La constelación de dominios corporativos europeos me hace sospechar de una CDN, un servicio de restauración o un escáner tratando de rehidratar cachés obsoletos.cbs.nl, scb.se, atlassian.com, abb.com y up.pt generaron colectivamente más de 250 millones de consultas. Ese nivel de volumen no es ruido aleatorio: o son clientes a gran escala o un dispositivo persistente que nunca deja de resolver.45.179.* y 45.6.*, cada una disparando más de 5k consultas en los cinco minutos observados. Podrían ser parte de un ISP o una granja de escáneres, pero sean lo que sean, los paneles hacen que rastrearlos sea trivial.¿Qué resalta esto? Ilustra cómo la infraestructura DNS expuesta puede convertirse en un feed pasivo de tráfico interesante incluso cuando no se anuncia. Internet sigue haciendo preguntas, y esta configuración simplemente escucha con atención. Si tienes curiosidad sobre cómo encaja este experimento en mi trabajo más amplio, revisa los otros repositorios: a veces ejecuto una idea como esta y tengo que ver a dónde lleva.
exports/ o adjunta los CSV directamente donde cuentes la historia.export_dashboard_data.py o las consultas de Loki con metadatos adicionales (ASN del cliente, motivo de SERVFAIL, país) para responder preguntas más profundas.--duration 12h, --end ...), guarda las salidas en directorios con marca de tiempo y actualiza este README con las estadísticas frescas para que la trama se mantenga actualizada.Si estás siguiendo el hilo con tu propio honeypot, actualiza este README con estadísticas de tus exportaciones para que podamos comparar historias y ver si los mismos sitios y clientes siguen regresando.
Este proyecto se proporciona "tal cual". No hay garantías de ningún tipo, expresas o implícitas, incluyendo pero no limitándose a comerciabilidad, idoneidad para un propósito particular o no infracción, y no soy responsable por daños que surjan de su uso. Asumes todos los riesgos asociados con el despliegue, configuración u operación de esta pila.
Si encuentras útil este proyecto, considera apoyarlo:
| Moneda | Dirección |
|---|---|
| Bitcoin (BTC) | 3QjWqhQbHdHgWeYHTpmorP8Pe1wgDjJy54 |
| Ethereum (ETH) | 0x5851e6145F4773d1585b8686095FB16E368a4dA1 |
| ZCash (ZEC) | t1KSR5YkNPbjqRSCoLKo5AddFWdm9Kzxh1B |
abb.comup.ptexports/