서론
개인적으로 인터넷에 허니팟(T-Pot)과 위협 인텔리전스 플랫폼(OpenCTI)을 결합한 환경을 운영하고 있습니다.
허니팟만 설치한다면, T-Pot을 넣는 것만으로도 당일부터 공격 흔적을 볼 수 있습니다.
어려웠던 것은 그 다음 단계였습니다.
- 수집된 로그를 잃지 않고 보관하는 방법
- 공격 출처나 검체를 외부 정보와 대조하여 정리하는 방법
- 살펴봐야 할 것만 매일 알림에 올리는 방법
- 수집한 정보를 집 네트워크 방어에도 활용하는 방법
이 글에서는 약 5개월간 운영해 온 구성의 전체적인 모습과, 그 과정에서 여러 번 겪었던 '운영한다고 생각했지만 실제로는 그렇지 않았던' 실패 경험을 정리합니다.
개별 메커니즘 구축 방법은 다음 글에서 자세히 작성할 예정입니다.
참고로, 2026년 여름부터는 Claude Code를 파트너 삼아 진행하고 있습니다.
다만, 여기에 적힌 시스템의 기반은 그 이전부터 혼자서 만들어 운영해 오던 것입니다. 먼저 그 이야기부터 하겠습니다.
Claude Code를 파트너로 삼기 전
집에서 연구실(Lab)을 시작한 것은 2022년경입니다.
계기는 직장에서 관련된 FW를 집에도 설치해 본 것이었습니다.
FW를 만지다 보니 자연스럽게 취약점 정보를 추적하게 되었습니다.
처음에는 취약점 정보 수집에 집중했지만, 점차 '실제로 누가 무엇을 노리고 공격하고 있는지' 하는 위협 정보 쪽에 관심이 옮겨갔습니다.
허니팟과 OpenCTI는 그 흐름에 따라 추가된 것입니다.
2026년 여름 기준으로, 혼자서 만든 다음 시스템들이 이미 작동하고 있었습니다.
허니팟(Honeypot)
- 클라우드 VPS의 T-Pot (1대. 집 네트워크 내부에는 위치하지 않음)
- 다른 VPS의 WOWHoneypot (2024년부터 가동)
수집된 정보를 정리하는 시스템
-
OpenCTI와 외부 정보를 가져오는 커넥터 그룹
-
T-Pot 로그를 OpenCTI로 가져오는 스크립트(자작)
-
공격 출처 IP 조사 파이프라인(자작)
-
T-Pot의 공격 출처를 Shodan, VirusTotal, AbuseIPDB 등에서 조사합니다.
-
봇넷을 분류하여 OpenCTI에 등록합니다.
-
T-Pot 로그를 보관하는 집의 Elasticsearch
이를 지탱하는 집 기반 시설
- Proxmox 3 노드 클러스터
- FW 2대(Palo Alto와 FortiGate) 및 VLAN을 통한 분리
- DNS (AdGuard Home)
- SSO (Authentik과 Traefik)
- 모니터링 및 SOC 도구 (Zabbix, Wazuh, MISP)
수집하고, 정리하고, 조사하는 흐름은 이 시점에서 어느 정도 갖춰져 있었습니다.
반면 어려웠던 것은 시간이었습니다. 시스템을 늘릴수록, 개별 사안을 깊이 파고드는 것에도, 만든 시스템들이 지금도 제대로 작동하는지 점검하는 것에도 손이 부족해졌습니다.
Claude Code에게 처음 도움을 요청한 것은 새로운 것을 만드는 것이 아니라, **집 연구실 전체의 재점검(棚卸し)**이었습니다.
네트워크 조사, FW 설정 감사, 각 시스템 점검, 그리고 기록을 Obsidian 노트에 남기는 작업이었습니다.
그로부터 시작하여, 발견하지 못했던 결함 수리, 심층 조사, 부족한 부분 추가 등으로 나아갔습니다.
역할 분담으로는, 무엇을 만들지/어디까지 할지/파괴해도 되는지는 자신이 결정하고, 조사와 작업과 기록은 Claude Code에게 맡기는 형태였습니다.
전체 개요
역할은 크게 4가지로 나뉩니다.
| 단계 | 위치 | 수행하는 활동 |
|---|
| 수집 | 클라우드 VPS | T-Pot으로 공격을 받아 로그와 검체를 수집합니다. |
| ... | | |
T-Pot의 Elasticsearch는 VPS 안에 있어 용량 문제로 오래된 로그가 사라집니다.
그래서 Logstash 출력을 두 개로 나누어 같은 로그를 집의 Elasticsearch에도 기록하고 있습니다.
집 쪽은 '사라지지 않게 하는 것'이 역할이라 전 기간을 보존하며 매일 밤 스냅샷을 찍고 있습니다.
VPS와 집 사이는 SSH 터널(autossh)로 연결하여 끊어지면 자동으로 다시 연결합니다.
터널이 끊겼던 동안의 누락분은 나중에 채워 넣는 절차를 마련해 두었습니다.
이 부분은 한 번 데이터를 전부 잃었던 경험이 있어 가장 공을 들인 부분입니다(후술).
정리 및 조사: OpenCTI
OpenCTI에는 세 가지 경로로 정보가 들어옵니다.
-
T-Pot 로그 수집 (매시간) - Cowrie, Dionaea, Mailoney의 기록을 공격 출처 IP별로 모아서 등록합니다.
-
같은 IP가 여러 번 오기 때문에 로그 한 줄 단위가 아니라 IP 단위로 모아서 등록하고 있습니다. 어떤 경우에는 1,895줄이 68건으로 요약되었고, 처리 시간은 100분의 1 이하가 되었습니다.
-
공격 출처 조사 (일별) - 그날의 공격 출처 상위 목록을 Shodan, VirusTotal, AbuseIPDB, GreyNoise 등에서 조사하여 봇넷 분류를 붙여 등록합니다.
-
상위 목록만 보면 국내 공격이 묻힐 수 있어 한국 IP만을 위한 별도의 항목도 운영하고 있습니다.
-
결과 보고서는 Discord에 첨부되어 도착합니다.
-
수동 심층 분석 (pivot.py) - 궁금한 IP나 기록의 해시를 시작점으로 삼아 동일 SSH 키, 동일 인증서, 동일 기록 등의 연결고리를 추적하여 결과를 OpenCTI에 Report로 등록합니다.
알림 및 활용: 통지 및 가정 내 적용
알림은 모두 Discord에 모으고 있습니다.
원칙은 '바로 알려주는 것은 개별적으로 볼 가치가 있는 것만. 양은 하루 1건으로 요약한다'입니다.
- 즉시 알릴 내용: 알려진 위험 IP로부터의 공격과 CVE 악용 시도 (하루 5~20건)
- 매일 아침 1건 다이제스트: 공격량, 처음 본 명령어 또는 SSH 클라이언트, 새로운 기록, 수법, 가정 내 감시 결과
- 각 호스트 감시: 15분마다 상태를 확인하고 변한 경우에만 알리며, 매일 한 번 '생존' 메시지를 보냅니다.
수집된 IoC는 허니팟 분석뿐 아니라 가정 통신 감시에도 사용합니다.
가정의 DNS(AdGuard Home) 질의와 FW 목적지를 매일 아침 대조하여, 가정 기기가 알려진 C2에 접촉하지 않았는지 다이제스트로 보냅니다.
현재는 일치 건수가 0건이라 차단은 하지 않고 감시만 하고 있습니다.
운영을 통해 알게 된 것: '작동하는 것처럼 보이는 것'이 가장 무섭다
5개월 동안 가장 많이 부딪힌 것은, 에러도 없고 성공 로그도 나오는데 정작 핵심적인 효과가 없는 방식으로 망가지는 것이었습니다.
비슷한 유형의 장애를 적어도 7번 경험했습니다.
혼자 만들었을 때부터 있던 것도 있고, Claude Code와 함께 만든 것에도 있었습니다.
누가 만들었는지와 상관없이 발생하는 고장이라고 생각합니다. 몇 가지 소개하겠습니다.
1. 백업용 Elasticsearch가 재부팅할 때마다 비어지는 구조였다
집의 보존용 Elasticsearch는 docker compose에 데이터 볼륨을 작성하지 않았습니다.
데이터가 컨테이너 안에만 있어서, 어느 날 docker compose down을 실행하는 순간 모두 사라졌습니다.
그전까지는 정상적으로 검색할 수 있었고 건수도 늘어나고 있어 아무도 의심하지 않았습니다.
'장기 보존용 ES'가 사실은 한 번도 장기 보존 상태가 아니었던 것입니다.
지금은 영구 볼륨으로 옮기고, 매일 밤 스냅샷을 찍고, 스냅샷이 성공했는지 감시하고 있습니다.
2. '두 곳에 기록'하려다 절반만 기록하는 경우였다
Logstash의 하나의 출력에 VPS와 집의 두 목적지를 나란히 작성했습니다.
이것은 '양쪽에 기록한다'가 아니라 '번갈아 분배한다' 설정이라, 각 로그는 둘 중 한 곳에만 들어갔습니다.
어느 ES를 보아도 그럴듯한 건수의 로그가 들어가 있어 알아차리기 어려운 실수였습니다.
출력을 두 블록으로 나누어 정말 양쪽에 기록되도록 수정했습니다.
3. OpenCTI의 자동 채우기가 10.5개월 동안 전혀 작동하지 않았다
OpenCTI에는 등록된 IP를 AbuseIPDB나 Shodan에 자동으로 문의하는 커넥터가 있습니다.
하지만 앞선 두 개의 커넥터 설정이 부족하여, 등록할 때마다 오류를 반환하고 그 다음 커넥터로 처리가 넘어가지 않았습니다.
확인했을 때의 수치는 AbuseIPDB 처리 대기 76,412건에 대해 완료 0건이었습니다.
커넥터는 '작동 중'으로 표시되어 있어 화면상으로는 아무것도 알 수 없었습니다.
4. 세 가지 모두 다른 이유로 멈춰 있었다
T-Pot에서 OpenCTI로의 가져오기(取り込み) 스크립트를 점검한 결과, 3개가 각각 다른 이유로 멈춰 있었습니다.
- Cowrie: 읽기 위치 기록이 손상되어 약 5개월 동안 멈춤
- Mailoney: 읽을 파일 경로가 달라서 처음부터 아무것도 하지 않음
- Dionaea: OpenCTI 형식에 맞지 않는 데이터 때문에 매번 47건씩 누락됨
cron은 매시간 정상적으로 실행되었고, 종료 코드도 0이었습니다.
5. 탐지했지만 누구에게도 전달되지 않았다
ElastAlert2로 탐지 규칙을 만들었지만, 알림 대상이 debug (로그에만 남기) 상태로 3주 동안 작동했습니다.
탐지 자체는 매일 발생하고 있었지만, 아무도 보고 있지 않았습니다.
6. 비교하는 한쪽이 처음부터 연결되어 있지 않았다
집의 ES(Elasticsearch)에서는 공격원 IP를 알려진 위험 IP 목록과 대조합니다.
그 목록의 절반은 공개 피드였고, 나머지 절반은 OpenCTI에서 만드는 설계였습니다.
그런데 OpenCTI 쪽은 구축 후 7주 동안 단 한 번도 연결되지 않았습니다.
공개 피드 부분만으로 대조가 돌아가고 있었기 때문에, 결과가 나오고 있는 것 자체는 부자연스럽게 보이지 않았던 것입니다.
배운 점
이들에 공통적인 것은 확인한 것이 '만들었는지/작동했는지'였지, '사용할 수 있는지'가 아니었다는 점입니다.
지금은 다음 사항들을 원칙으로 삼고 있습니다.
- 확인할 때는 효과를 본다. '스냅샷이 성공했다'가 아니라 '되돌릴 수 있는지', 'cron이 돌아갔다'가 아니라 '건수가 늘었는지'를 봅니다. - 대조군을 만든다. 대조가 0건이라면, 반드시 히트할 값이 섞여서 1건 이상 나오는 것을 확인합니다. - 감시는 '멈춘 것'도 알린다. 0건이라도 매번 기록을 남기고, 기록이 오지 않으면 '감이 멈췄다'고 표시합니다. - 임계값은 실제로 센 후에 정한다. 설계 단계에서 생각한 값을 그대로 넣고, '영원히 울리지 않는' 알림을 2개 만들었습니다.
추가: 실제로 어떻게 도움이 되었나
최근의 사례를 하나 들겠습니다.
JPCERT/CC가 국내 기관에 대한 부정 접근 관련 주의 환기를 내면서 의심스러운 IP 15개를 공개했습니다.
이것을 자신의 하니팟 로그와 대조해 본 결과, 그중 1건(Azure의 IP)이 주의 환기 시기와 같은 무렵 T-Pot으로 들어오고 있었습니다.
손안의 로그를 보니, 그 IP가 했던 것은 PHP 웹 셸이 놓여 있는지 아닌지를 한 번에 60~170개 정도 확인하는 스캔이었습니다.
게다가, 같은 경로 배열을 같은 순서로 사용하는 다른 Azure IP가 6건 발견되었습니다.
처음 두 개의 경로를 따라가 보니, 같은 도구가 6월부터 462개의 IP를 교체하며 계속 사용되고 있다는 것도 알 수 있었습니다.
공개된 IoC(Indicators of Compromise)를 기다리는 것뿐만 아니라, 손안의 로그와 대조하여 '같은 도구의 무리'까지 확장할 수 있는 점이, 직접 하니팟을 갖는 재미라고 느낍니다.
맺음말
하니팟 자체보다도, 수집한 것을 잃지 않고, 확인하고, 사용할 수 있는 형태로 정돈하는 데 시간이 걸렸습니다.
그리고 그 과정에서 가장 무서웠던 것은, 고장 난 것에 알아차릴 수 없는 시스템이었습니다.