커맨드 앤 컨트롤 통신 분석은(는) 무엇을 하나요?
사용 시기
- 악성코드 샘플 리버스 엔지니어링 과정에서 프로토콜 분석이 필요한 네트워크 통신이 발견된 경우
- 특정 C2 프레임워크(Cobalt Strike, Metasploit, Sliver)에 대한 네트워크 수준 탐지 시그니처를 구축할 때
- 주 서버, 폴백 도메인, 데드 드롭을 포함한 C2 인프라를 매핑할 때
- 암호화 또는 인코딩된 C2 트래픽을 분석하여 명령 세트와 데이터 형식을 이해해야 할 때
- C2 인프라 패턴과 도구 사용을 기반으로 악성코드를 특정 위협 행위자에게 귀속시킬 때
일반적인 네트워크 이상 탐지에는 사용하지 마십시오. 이 스킬은 악성코드 분석을 통해 알려지거나 의심되는 C2 프로토콜을 이해하기 위해 특별히 고안되었습니다.
사전 요구사항
- 악성코드 네트워크 트래픽의 PCAP 캡처 (샌드박스, 네트워크 탭, 또는 전체 패킷 캡처에서 획득)
- 패킷 수준 분석을 위한 Wireshark/tshark
- 악성코드 바이너리의 C2 코드 이해를 위한 리버스 엔지니어링 도구 (Ghidra, dnSpy)
- 프로토콜 분석 및 재생을 위한 Python 3.8+ (
scapy,dpkt,requests) - C2 인프라 상관 분석을 위한 위협 인텔리전스 데이터베이스 (VirusTotal, Shodan, Censys)
- TLS 기반 C2 식별을 위한 JA3/JA3S 지문 데이터베이스
워크플로우
1단계: C2 채널 식별
C2 통신에 사용되는 프로토콜과 전송 방식을 결정합니다:
C2 통신 채널:
━━━━━━━━━━━━━━━━━━━━━━━━━
HTTP/HTTPS: 가장 일반적; 표준 웹 트래픽을 사용하여 네트워크에 섞여 들어감
지표: 정기적인 POST/GET 요청, 특정 URI 패턴, 사용자 정의 헤더
DNS: DNS 쿼리와 응답을 통해 데이터를 터널링
지표: 대량의 TXT 쿼리, 긴 서브도메인 이름, 높은 엔트로피
사용자 정의 TCP/UDP: 비표준 포트를 사용한 독점 바이너리 프로토콜
지표: 높은 포트의 비-HTTP 트래픽, 알 수 없는 프로토콜
ICMP: ICMP 에코/응답 페이로드에 데이터를 인코딩
지표: 크거나 비표준적인 페이로드를 가진 ICMP 패킷
WebSocket: 실시간 C2를 위한 지속적인 양방향 연결
지표: WebSocket 업그레이드 후 바이너리 프레임 전송
클라우드 서비스: 합법적인 API 사용 (Telegram, Discord, Slack, GitHub)
지표: 예상치 못한 프로세스에서 클라우드 서비스로의 API 호출
이메일: C2 명령 및 데이터 유출을 위한 SMTP/IMAP 사용
지표: 이메일 관련 프로세스가 아닌 곳에서 발생하는 자동화된 이메일 작업
2단계: 비콘 패턴 분석
주기적인 통신 패턴을 특성화합니다:
from scapy.all import rdpcap, IP, TCP
from collections import defaultdict
import statistics
import json
packets = rdpcap("c2_traffic.pcap")
# 목적지별로 TCP SYN 패킷 그룹화
connections = defaultdict(list)
for pkt in packets:
if IP in pkt and TCP in pkt and (pkt[TCP].flags & 0x02):
key = f"{pkt[IP].dst}:{pkt[TCP].dport}"
connections[key].append(float(pkt.time))
# 각 목적지의 비코닝 분석
for dst, times in sorted(connections.items()):
if len(times) < 3:
continue
intervals = [times[i+1] - times[i] for i in range(len(times)-1)]
avg_interval = statistics.mean(intervals)
stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0
jitter_pct = (stdev / avg_interval * 100) if avg_interval > 0 else 0
duration = times[-1] - times[0]
beacon_data = {
"destination": dst,
"connections": len(times),
"duration_seconds": round(duration, 1),
"avg_interval_seconds": round(avg_interval, 1),
"stdev_seconds": round(stdev, 1),
"jitter_percent": round(jitter_pct, 1),
"is_beacon": 5 < avg_interval < 7200 and jitter_pct < 25,
}
if beacon_data["is_beacon"]:
print(f"[!] 비콘 탐지됨: {dst}")
print(f" 간격: {avg_interval:.0f}s +/- {stdev:.0f}s ({jitter_pct:.0f}% 지터)")
print(f" 세션: {len(times)}회, {duration:.0f}초 동안")
3단계: C2 프로토콜 구조 디코딩
캡처된 트래픽에서 메시지 형식을 리버스 엔지니어링합니다:
# HTTP 기반 C2 프로토콜 분석
import dpkt
import base64
with open("c2_traffic.pcap", "rb") as f:
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
if not isinstance(eth.data, dpkt.ip.IP):
continue
ip = eth.data
if not isinstance(ip.data, dpkt.tcp.TCP):
continue
tcp = ip.data
if tcp.dport == 80 or tcp.dport == 443:
if len(tcp.data) > 0:
try:
http = dpkt.http.Request(tcp.data)
print(f"\n--- C2 요청 ---")
print(f"메서드: {http.method}")
print(f"URI: {http.uri}")
print(f"헤더: {dict(http.headers)}")
if http.body:
print(f"본문 ({len(http.body)} 바이트):")
# Base64 디코딩 시도
try:
decoded = base64.b64decode(http.body)
print(f" 디코딩됨: {decoded[:200]}")
except:
print(f" 원본: {http.body[:200]}")
except:
pass
4단계: C2 프레임워크 식별
관찰된 패턴을 알려진 C2 프레임워크와 매칭합니다:
알려진 C2 프레임워크 시그니처:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Cobalt Strike:
- 기본 URI: /pixel, /submit.php, /___utm.gif, /ca, /dpixel
- Malleable C2 프로필로 모든 트래픽 특성 사용자 정의 가능
- JA3: 프로필에 따라 다양함, ja3er.com에서 카탈로그 확인
- 비콘 설정 내 워터마크 (라이선스별 고유)
- 설정 추출: CobaltStrikeParser 또는 1768.py 사용
Metasploit/Meterpreter:
- 기본 스테이징 URI 패턴: 랜덤 4자 체크섬
- 역방향 HTTP(S) 핸들러 패턴
- Meterpreter TLV (Type-Length-Value) 프로토콜 구조
Sliver:
- mTLS, HTTP, DNS, WireGuard 전송 옵션
- Protobuf로 인코딩된 메시지
- 통신 내 고유 임플란트 ID
Covenant:
- .NET 기반 C2 프레임워크
- 사용자 정의 가능한 프로필을 가진 HTTP
- 태스크 기반 명령 실행
PoshC2:
- PowerShell/C# 기반
- 암호화된 페이로드를 사용한 HTTP
- 쿠키 기반 세션 관리
# PCAP 또는 샘플에서 Cobalt Strike 비콘 설정 추출
python3 << 'PYEOF'
# CobaltStrikeParser 사용 (pip install cobalt-strike-parser)
from cobalt_strike_parser import BeaconConfig
try:
config = BeaconConfig.from_file("suspect.exe")
print("Cobalt Strike 비콘 설정:")
for key, value in config.items():
print(f" {key}: {value}")
except Exception as e:
print(f"Cobalt Strike 비콘이 아니거나 파싱 오류: {e}")
PYEOF
5단계: C2 인프라 매핑
전체 C2 인프라와 장애 조치 메커니즘을 문서화합니다:
# 인프라 매핑
import requests
import json
c2_indicators = {
"primary_c2": "185.220.101.42",
"domains": ["update.malicious.com", "backup.evil.net"],
"ports": [443, 8443],
"failover_dns": ["ns1.malicious-dns.com"],
}
# Shodan으로 정보 보강
def shodan_lookup(ip, api_key):
resp = requests.get(f"https://api.shodan.io/shodan/host/{ip}?key={api_key}")
if resp.status_code == 200:
data = resp.json()
return {
"ip": ip,
"ports": data.get("ports", []),
"os": data.get("os"),
"org": data.get("org"),
"asn": data.get("asn"),
"country": data.get("country_code"),
"hostnames": data.get("hostnames", []),
"last_update": data.get("last_update"),
}
return None
# 패시브 DNS로 정보 보강
def pdns_lookup(domain):
# VirusTotal 패시브 DNS 사용
resp = requests.get(
f"https://www.virustotal.com/api/v3/domains/{domain}/resolutions",
headers={"x-apikey": VT_API_KEY}
)
if resp.status_code == 200:
data = resp.json()
resolutions = []
for r in data.get("data", []):
resolutions.append({
"ip": r["attributes"]["ip_address"],
"date": r["attributes"]["date"],
})
return resolutions
return []
6단계: 네트워크 탐지 시그니처 생성
분석된 C2 특성을 기반으로 탐지 규칙을 구축합니다:
# 분석된 C2에 대한 Suricata 규칙
cat << 'EOF' > c2_detection.rules
# HTTP 비콘 패턴
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"악성코드 MalwareX C2 HTTP 비콘";
flow:established,to_server;
http.method; content:"POST";
http.uri; content:"/gate.php"; startswith;
http.header; content:"User-Agent: Mozilla/5.0 (compatible; MSIE 10.0)";
threshold:type threshold, track by_src, count 5, seconds 600;
sid:9000010; rev:1;
)
# JA3 지문 매칭
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"악성코드 MalwareX TLS JA3 지문";
ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1";
sid:9000011; rev:1;
)
# DNS 비콘 탐지 (고엔트로피 서브도메인)
alert dns $HOME_NET any -> any any (
msg:"악성코드 의심 DNS C2 터널링";
dns.query; pcre:"/^[a-z0-9]{20,}\./";
threshold:type threshold, track by_src, count 10, seconds 60;
sid:9000012; rev:1;
)
# 인증서 기반 탐지
alert tls $HOME_NET any -> $EXTERNAL_NET any (
msg:"악성코드 MalwareX 자체 서명 C2 인증서";
tls.cert_subject; content:"CN=update.malicious.com";
sid:9000013; rev:1;
)
EOF
주요 개념
| 용어 | 정의 |
|---|---|
| 비코닝 | 악성코드가 C2 서버에 정기적으로 체크인하는 통신 패턴. 패턴 탐지를 피하기 위해 지터를 포함하는 경우가 많음 |
| 지터 | 비콘 간격에 적용되는 무작위화 (예: 60초 +/- 15%). 타이밍 패턴을 덜 예측 가능하게 만들어 탐지를 어렵게 함 |
| Malleable C2 | Cobalt Strike의 기능. 운영자가 C2 트래픽의 모든 측면(URI, 헤더, 인코딩)을 사용자 정의하여 합법적인 서비스를 모방할 수 있게 함 |
| 데드 드롭 | 악성코드가 명령을 검색하기 위해 C2 명령이 게시되는 중간 위치 (페이스트 사이트, 클라우드 저장소, 소셜 미디어) |
| 도메인 프론팅 | TLS SNI에 신뢰할 수 있는 CDN 도메인을 사용하면서 다른 백엔드로 라우팅하여 C2 트래픽이 합법적인 서비스로 향하는 것처럼 보이게 함 |
| 패스트 플럭스 | C2 도메인의 DNS 레코드를 빠르게 변경하여 여러 IP에 분산시키고 차단 노력에 저항함 |
| C2 프레임워크 | C2 서버, 임플란트 생성기 및 운영자 인터페이스를 제공하는 소프트웨어 툴킷 (Cobalt Strike, Metasploit, Sliver, Covenant) |
도구 및 시스템
- Wireshark: 패킷 수준의 상세한 C2 프로토콜 분석을 위한 패킷 분석기
- RITA (Real Intelligence Threat Analytics): 비콘 탐지 및 DNS 터널링을 위해 Zeek 로그를 분석하는 오픈소스 도구
- CobaltStrikeParser: 샘플 및 메모리 덤프에서 Cobalt Strike 비콘 설정을 추출하는 도구
- JA3/JA3S: TLS 구현 특성을 기반으로 C2 프레임워크를 식별하기 위한 TLS 지문 방법
- Shodan/Censys: C2 인프라 매핑 및 관련 서버 식별을 위한 인터넷 스캐닝 플랫폼
일반적인 시나리오
시나리오: 사용자 정의 C2 프로토콜 리버스 엔지니어링
컨텍스트: 악성코드 샘플이 TCP 포트 8443을 통해 알 수 없는 바이너리 프로토콜을 사용하여 C2 서버와 통신합니다. 명령 세트를 이해하고 탐지 시그니처를 구축하기 위해 프로토콜을 디코딩해야 합니다.
접근 방식:
- PCAP에서 TCP 포트 8443 대화를 필터링하고 TCP 스트림을 추출합니다
- 처음 몇 번의 교환을 분석하여 핸드셰이크/인증 메커니즘을 식별합니다
- 메시지 구조를 매핑합니다 (길이 접두사, 유형 필드, 페이로드 인코딩)
- 악성코드의 송수신 함수에 대한 Ghidra 디스어셈블리와 상호 참조합니다
- 명령 디스패처를 식별하고 각 명령 코드의 기능을 문서화합니다
- 지속적인 트래픽 분석을 위해 Python으로 프로토콜 디코더를 구축합니다
- 프로토콜 핸드셰이크 또는 정적 헤더 바이트와 일치하는 Suricata 규칙을 생성합니다
주의사항:
- 프로토콜이 정적이라고 가정하지 마십시오. 일부 C2 프레임워크는 핸드셰이크 중에 암호화를 협상합니다
- 모든 명령 유형을 보기 위해 충분한 트래픽을 캡처하지 못하는 경우 (일부 명령은 드뭅니다)
- 기본 채널이 실패할 때 활성화되는 대체 C2 채널(DNS, ICMP)을 놓치는 경우
- 암호화된 페이로드 데이터와 프로토콜 프레이밍 구조를 혼동하는 경우
출력 형식
C2 통신 분석 보고서
===================================
샘플: malware.exe (SHA-256: e3b0c44...)
C2 프레임워크: Cobalt Strike 4.9
비콘 설정
C2 서버: hxxps://185.220.101[.]42/updates
비콘 유형: HTTPS (역방향)
슬립: 60초
지터: 15%
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
URI (GET): /dpixel
URI (POST): /submit.php
워터마크: 1234567890
프로토콜 분석
전송 방식: HTTPS (TLS 1.2)
JA3 해시: a0e9f5d64349fb13191bc781f81f42e1
인증서: CN=Microsoft Update (자체 서명)
인코딩: Base64 with XOR key 0x69
명령 형식: [4B 길이][4B 명령_ID][페이로드]
명령 세트
0x01 - 슬립 비콘 간격 변경
0x02 - 셸 cmd.exe 명령 실행
0x03 - 다운로드 C2에서 파일 전송
0x04 - 업로드 C2로 파일 유출
0x05 - 인젝트 프로세스 인젝션
0x06 - 키로그 키로거 시작
0x07 - 스크린샷 화면 캡처
인프라
기본 서버: 185.220.101[.]42 (AS12345, Hosting Co, NL)
폴백 서버: 91.215.85[.]17 (AS67890, VPS Provider, RU)
DNS: update.malicious[.]com -> 185.220.101[.]42
등록 대행자: NameCheap
등록일: 2025-09-01
탐지 시그니처
SID 9000010: HTTP 비콘 패턴
SID 9000011: JA3 TLS 지문
SID 9000013: C2 인증서 매칭