
AD 랩을 대상으로 자동화된 적대자 에뮬레이션(Caldera)을 수행하여 Sigma 탐지 커버리지를 검증하고 결과를 MITRE ATT&CK에 매핑합니다.
detection-as-code-repo에서 구축한 Sigma 탐지 규칙에 대한 자동화된 퍼플팀 검증으로, MITRE Caldera를 사용하여 기존 도메인 랩을 대상으로 연쇄적인 Active Directory 자격 증명 접근 공격 경로를 실행하고, ATT&CK Navigator 히트맵으로 커버리지를 시각화합니다.
이 프로젝트에서 Atomic Red Team 대신 Caldera를 선택한 이유는, 단일하고 고립된 기법 실행이 아니라 에이전트, 적대자 프로필, 연쇄적인 다단계 작업을 갖춘 완전한 C2 프레임워크를 제공하기 때문입니다. 이는 이 프로젝트의 목표와 더 밀접하게 부합합니다: 단순히 "이 하나의 기법이 탐지되었는가"가 아니라, "현실적이고 순서가 정해진 공격 체인이 우리의 현재 탐지 스택을 처음부터 끝까지 견뎌내는가"입니다.
Purple-Team-Automation/
├── abilities/ 사용자 정의 Caldera ability YAML
├── adversary-profiles/ 작업에 사용된 연쇄 적대자 프로필
├── validation/ 기법별 Kibana 증거 + LLMNR 알려진 격차 문서
├── attack-navigator-heatmap.json ATT&CK Navigator 레이어, mitre-attack.github.io/attack-navigator에서 로드
├── purple-team-automation-report.md 전체 문서: 범위, 방법론, 결과, 격차 분석
└── README.md 이 파일
기존 AD 도메인 랩과 동일한 랩 네트워크에 있는 별도의 Ubuntu VM(caldera-server, 192.168.18.205)에 Docker Compose를 통해 전용 Caldera 서버를 배포하여, ELK/SIEM 스택과 격리되도록 유지했습니다. Caldera v5.0.0은 기본적으로 2000개의 내장 ability와 29개의 내장 적대자를 갖추고 시작되었습니다.
과정에서 근본 원인을 파악한 빌드 문제:
plugins/magma/dist/assets/) 누락으로 크래시 루프에 빠졌습니다. 이는 docker-compose.yml의 전체 디렉터리 Docker 볼륨 마운트가 이미지의 컴파일된 프론트엔드를 컴파일되지 않은 호스트 소스로 덮어쓰기 때문임을 추적했습니다. 전체 디렉터리 마운트를 제거하여 수정했습니다.npm/nodejs를 의도적으로 제거하기 때문에 실패했습니다.localhost:8888이 API 베이스로 하드코딩되어 있었는데, 이는 Vue 빌드 시점에 plugins/magma/.env(VITE_CALDERA_URL)를 통해 박혀 있으며, conf/local.yml의 런타임 app.frontend.api_base_url 설정으로는 제어되지 않습니다. .env를 VM의 실제 IP로 편집하고 재빌드하여 수정했습니다.lvextend -l +100%FREE + resize2fs로 수정하고, docker system prune -a --volumes로 빌드 캐시 레이어를 회수했습니다.Stockpile은 LSASS/Mimikatz 기반 자격 증명 덤프(T1003.001)에 대한 네이티브 ability만 제공합니다. 이 프로젝트에 필요했던 네 가지 기법인 Kerberoasting, AS-REP Roasting, Password Spraying, DCSync는 모두 Impacket(GetUserSPNs.py, GetNPUsers.py, secretsdump.py)과 Kerbrute를 기반으로 제가 직접 구축한 사용자 정의 ability가 필요했습니다. Stockpile의 기존 Kerberoasting ability(Rubeus, WinPwn)는 Windows/.NET 전용이며 이 랩의 Linux 기반 Sandcat 에이전트와 호환되지 않기 때문입니다.
이를 작성하는 동안 두 가지 빌드 문제에 부딪혔습니다:
source/edge/target 필드를 가진 용도별 도구별 파서 모듈(예: plugins.stockpile.app.parsers.katz)을 사용하며, 제가 원래 가정했던 일반 정규식 pattern 파서가 아닙니다. 이로 인해 로드 시 조용한 TypeError('ParserConfig.__init__()')가 발생했습니다. 원시 Impacket 출력에 대한 내장 파서가 존재하지 않으므로, 네 가지 ability 모두에서 parsers: 블록을 완전히 제거했습니다. 결과는 원시 출력/해시 파일로 캡처되어 Kibana에 대해 수동으로 검증됩니다(/validation 참조).nano 붙여넣기가 조용히 실패한 후 초기에 0바이트 파일로 저장되었습니다. 컨테이너를 재시작하기 전에 모든 파일을 cat/wc -l로 점검하여 이를 발견했습니다.Kali VM(192.168.18.70)에 Sandcat 에이전트(Linux, 그룹 red)를 배포했으며, OPSEC 위장을 위해 프로세스 이름 splunkd를 사용했고, proc/sh 실행기로 root 권한으로 실행되며 활성 상태이고 신뢰할 수 있음을 확인했습니다.
기회주의적 내부 공격자가 일반적으로 시도할 순서대로 네 가지 사용자 정의 ability를 연쇄하는 AD Credential Access Chain 적대자 프로필을 구축했습니다:
→ Password Spray (Kerbrute)
→ Kerberoasting (GetUserSPNs.py)
→ AS-REP Roasting (GetNPUsers.py)
→ DCSync (secretsdump.py)
LLMNR/NBT-NS 포이즈닝(T1557.001)은 Caldera 프로필에서 의도적으로 제외했습니다. 이유와 이것이 여전히 알려진 격차 음성 대조군으로 포함되는 방식은 validation/llmnr-known-gap.md를 참조하세요.
실행된 네 가지 기법 모두 detection-as-code-repo의 Sigma 규칙에 대해 탐지가 확인되었으며, Kibana에서 직접 교차 검증했습니다. LLMNR/NBT-NS 포이즈닝은 문서화된 미해결 격차로 남아 있습니다.
| 기법 | 상태 |
|---|---|
| T1110.003 – Password Spraying | 🟢 탐지됨 |
| T1558.003 – Kerberoasting | 🟢 탐지됨 |
| T1558.004 – AS-REP Roasting | 🟢 탐지됨 |
| T1003.006 – DCSync | 🟢 탐지됨 |
| T1557.001 – LLMNR/NBT-NS Poisoning | 🔴 격차 |
전체 세부 정보: validation/detection-results.md
전체 문서: purple-team-automation-report.md
대화형 히트맵: attack-navigator-heatmap.json