
dns-honeypot
관측 가능성 도구에 깊이 빠져 지내는 엔지니어로서, 가끔은 꼭 해봐야겠다는 아이디어가 떠오릅니다. 이번 실험이 그런 경우였습니다: 아무도 광고하지 않는 깨끗한 IP에서 DNS 리졸버를 띄우고, 인터넷이 그냥 접속하게 두는 것. 리졸버의 유일한 임무는 조용히 있으면서 모든 것을 로깅하고, 결과 쿼리를 Grafana에 공급하는 것이었습니다. docker compose up -d 한 번으로 Unbound, Loki, Prometheus, Grafana, Traefik이 실시간 트래픽을 추적하고 호기심, 설정 오류, 그리고 가끔의 스캐너의 히스토그램을 출력했습니다. 이 README는 그 첫날의 보고서입니다. 무엇을 캡처했는지, 왜 나에게 중요한지, 현재 보안 환경에 대해 무엇을 시사하는지에 대한 내용입니다.
의도적으로 내 쪽에서는 신호를 전혀 발생시키지 않았습니다. 패킷 드롭 없음, 맞춤형 응답 없음, 완화 조치 없음. 단지 로깅이 활성화된 Unbound, 로그 파일을 추적하는 Loki, 익스포터 메트릭을 스크래핑하는 Prometheus, Grafana를 프록시하는 Traefik, 그리고 이들을 연결하는 Docker Compose뿐이었습니다. 리졸버는 94.130.27.226에 위치했으며, 상쾌할 정도로 '깨끗한' IPv4 주소였습니다 (사전 노이즈 기준을 확인하려면 https://www.abuseipdb.com/check/94.130.27.226 에서 상태를 확인하세요). 그리고 세상이 알아서 하도록 두었습니다. 노트북 하나로 모든 패널을 지켜보고, tools/dns_query_storm.sh를 실행하여 상황을 뒤흔들고 싶을 때 사용했으며, 그 후에는 전 세계 인터넷이 보내는 어떤 패턴이든 다시 노이즈가 안정되도록 두었습니다.
해당 대시보드를 https://dns.cybersafeintl.co.uk/public-dashboards/eb554b5b74e14f4d95e376c0033ee83d 에서 실시간으로 볼 수 있습니다. 다만 스택 중 가장 낮은 사양의 서버에 있으므로, 쿼리가 많을 때는 새로고침이 느릴 수 있습니다.
unbound_total_num_queries 메트릭을 스크래핑하므로, "처리량(QPS, 5m rate)" 패널은 초당 쿼리 수를 보여주고 이를 소스별로 분류합니다. 이 보기는 "누가 리졸버를 때리고 있는가?"라는 질문에 답합니다. 갑작스러운 스파이크는 방글라데시 또는 폴란드 기반 ASN을 직접 가리키며, 로그를 통해 SERVFAIL/NXDOMAIN 폭풍이 발생과 함께 나타나는지 쉽게 확인할 수 있습니다.client_ip로 그룹화하며, 대시보드는 이미 모든 것을 topk(sort_desc(...))로 감쌉니다. 이렇게 하면 패널이 깔끔하게 유지되면서, 익스포터 스크립트를 통해 동일한 쿼리를 CSV로 덤프하여 오프라인 분석, 보고, 재현 가능한 스토리텔링에 사용할 수 있습니다. 첫 번째 캡처에서는 45.179.* 및 45.6.* 범위의 다섯 개 IP 주소가 각각 5분 동안 5k+ 쿼리를 발사했으며, 스캐너 팜이거나 공격적인 클라이언트일 가능성이 있습니다.qname 인기도를 보여줍니다. 5분 스냅샷에는 scb.se, dhl.com, cmu.edu가 나타났고, 24시간 내보내기에는 cbs.nl, scb.se, atlassian.com, abb.com, up.pt가 포함되었습니다. 왜 이 도메인들일까요? 이것이 흥미로운 부분입니다. 합법적인 서비스일까요, 잘못 구성된 리졸버일까요, 아니면 오래된 레코드를 쫓는 기회주의적 스캐너일까요? 의견이 있으시면 알려주세요.보이는 모든 패널에는 exports/에 해당 CSV가 있습니다. 블로그 게시물이나 사고 보고서에 원시 스토리를 첨부하려면 번들로 묶으세요(zip -r exports.zip exports/).
docker-compose.yml은 단일 명령으로 Unbound, Unbound 익스포터, Loki + Promtail, Prometheus, Grafana, Traefik을 띄웁니다.unbound/는 리졸버 구성과 로그를 저장합니다. TTL 제어, serve-expired, 캐시 설정은 클라이언트가 실제로 요청하는 것을 캡처할 수 있도록 정확성을 유지합니다.prometheus/, loki/, grafana/ 디렉토리는 데이터와 프로비저닝 파일을 보관하여 메트릭과 대시보드가 재시작 후에도 유지되도록 합니다.grafana/dashboards/unbound-traffic-insights.json은 보이는 뷰로 사전 프로비저닝되어 있습니다. 모든 PromQL/Loki 쿼리는 이미 집계 및 정렬되어 패널을 읽기 쉽게 유지합니다.tools/dns_query_storm.sh는 반응 시간을 테스트해야 할 때 쿼리 폭풍을 시뮬레이션할 수 있게 해줍니다.redeploy.sh는 전체 스택을 중단하고, 업데이트를 가져오고, 단일 스크립트로 재구축하는 작업을 자동화합니다.export_dashboard_data.py는 이제 대시보드 JSON을 읽고, 각 Prometheus/Loki 쿼리를 실행하고, 공유를 위해 exports/ 디렉토리에 정리된 CSV 파일을 작성합니다.
cd hetzner_deploy/unbound-dnscp .env.example .env를 실행하고 GRAFANA_DOMAIN, Grafana 관리자 자격 증명, LETSENCRYPT_EMAIL, 필요한 TLS 재정의를 구성합니다.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 (익스포터는 순수 Python입니다).python export_dashboard_data.py --duration 24h --outdir exports/24h --timeout 90을 실행하여 모든 대시보드 쿼리를 가져와 CSV로 변환하고 결과를 exports/24h 아래에 배치합니다.zip -r exports.zip exports/를 실행하여 게시하거나 블로그 게시물에 첨부하거나 협업자에게 보내기 전에 원시 테이블을 번들로 묶습니다.--duration 6h 또는 --end 타임스탬프를 사용하여 다시 실행하거나, 도메인 패널만 원하는 경우 --filter domains를 사용합니다.scb.se, dhl.com, cmu.edu, up.pt, utc.fr 각각 수십만 건의 조회를 생성했습니다. 왜 이 대상들일까요? 유럽 기업 도메인의 별자리를 보면 CDN, 복원 서비스, 또는 오래된 캐시를 재수화하려는 스캐너가 의심됩니다.cbs.nl, scb.se, atlassian.com, abb.com, up.pt가 총 2억 5천만 개 이상의 쿼리를 생성했습니다. 이 정도 볼륨은 무작위 노이즈가 아닙니다. 대규모 클라이언트이거나 해석을 멈추지 않는 지속적인 장비일 가능성이 큽니다.45.179.* 및 45.6.* IPv4 주소로, 각각 관찰된 5분 동안 5k개 이상의 쿼리를 발사했습니다. 이들은 ISP나 스캐닝 팜의 일부일 수 있지만, 무엇이든 대시보드를 통해 추적이 매우 쉽습니다.이것이 시사하는 바는 무엇일까요? DNS 인프라가 광고되지 않더라도 흥미로운 트래픽의 수동 피드가 될 수 있다는 점을 보여줍니다. 인터넷은 계속 질문을 하고, 이 설정은 단순히 주의 깊게 듣습니다. 이 실험이 내 더 넓은 작업과 어떻게 연결되는지 궁금하다면 다른 레포를 확인해 보세요. 때로는 이런 아이디어를 실행해 보고 그 결과가 어디로 이어지는지 확인합니다.
exports/ 폴더를 압축하거나 스토리를 전달하는 곳에 CSV를 직접 첨부하세요.export_dashboard_data.py 또는 Loki 쿼리를 추가 메타데이터(클라이언트 ASN, SERVFAIL 이유, 국가)로 확장하여 더 깊은 질문에 답하세요.--duration 12h, --end ...)로 익스포터를 다시 실행하고, 출력을 타임스탬프 디렉토리에 보관하며, 최신 통계로 이 README를 업데이트하여 플롯이 최신 상태로 유지되도록 하세요.자체 허니팟을 따라하고 있다면, 내보내기의 통계로 이 README를 업데이트하여 서로 이야기를 비교하고 동일한 사이트와 클라이언트가 계속 돌아오는지 확인할 수 있습니다.
이 프로젝트는 "있는 그대로" 제공됩니다. 상품성, 특정 목적에의 적합성, 비침해를 포함하되 이에 국한되지 않는 어떠한 종류의 명시적 또는 묵시적 보증도 없으며, 사용으로 인해 발생하는 어떠한 손해에 대해서도 책임을 지지 않습니다. 이 스택을 배포, 구성 또는 운영하는 모든 위험은 사용자가 부담합니다.
이 프로젝트가 유용하다고 생각되면 지원을 고려해 주세요:
| 통화 | 주소 |
|---|---|
| 비트코인 (BTC) | 3QjWqhQbHdHgWeYHTpmorP8Pe1wgDjJy54 |
| 이더리움 (ETH) | 0x5851e6145F4773d1585b8686095FB16E368a4dA1 |
| ZCash (ZEC) | t1KSR5YkNPbjqRSCoLKo5AddFWdm9Kzxh1B |