캠페인 귀속 증거 분석은(는) 무엇을 하나요?
개요
캠페인 귀속 분석은 사이버 운영에 책임이 있는 위협 행위자 또는 그룹을 결정하기 위해 증거를 체계적으로 평가하는 것을 포함합니다. 이 스킬은 다이아몬드 모델과 ACH(경쟁 가설 분석)를 사용하여 귀속 지표를 수집하고 가중치를 부여하는 방법, 인프라 중복, TTP 일관성, 악성코드 코드 유사성, 운영 타이밍 패턴 및 언어 아티팩트를 분석하여 신뢰도 가중치가 적용된 귀속 평가를 구축하는 방법을 다룹니다.
사용 시기
- 캠페인 귀속 증거 분석이 필요한 보안 사고를 조사할 때
- 이 도메인에 대한 탐지 규칙 또는 위협 헌팅 쿼리를 구축할 때
- SOC 분석가가 이 분석 유형에 대한 구조화된 절차가 필요할 때
- 관련 공격 기술에 대한 보안 모니터링 범위를 검증할 때
필수 조건
- Python 3.9+ 및
attackcti,stix2,networkx라이브러리 - 위협 인텔리전스 플랫폼(MISP, OpenCTI)에 대한 액세스
- 침입 분석의 다이아몬드 모델 이해
- MITRE ATT&CK 위협 그룹 프로필에 대한 친숙함
- 악성코드 분석 및 인프라 추적 기술에 대한 지식
주요 개념
귀속 증거 범주
- 인프라 중복: 공유 C2 서버, 도메인, IP 범위, 호스팅 제공업체
- TTP 일관성: 캠페인 전반에 걸쳐 일치하는 ATT&CK 기술 및 하위 기술
- 악성코드 코드 유사성: 공유 코드 기반, 컴파일러, PDB 경로, 암호화 루틴
- 운영 패턴: 타이밍(근무 시간, 시간대), 표적 패턴, 운영 템포
- 언어 아티팩트: 특정 언어로 된 임베디드 문자열, 변수 이름, 오류 메시지
- 피해자 특성: 표적 부문, 지리적 위치 및 조직 프로필 일관성
신뢰 수준
- 높은 신뢰도: 여러 독립적인 증거 범주가 동일한 행위자로 수렴
- 중간 신뢰도: 여러 증거 범주가 일치하지만 약간의 모호함이 남아 있음
- 낮은 신뢰도: 제한된 증거, 가능한 오해 또는 공유 도구 사용 가능성
경쟁 가설 분석 (ACH)
여러 경쟁 가설에 대해 증거를 평가하는 구조화된 분석 방법입니다. 각 증거는 각 가설에 대해 일관됨, 일관되지 않음 또는 중립으로 점수가 매겨집니다. 가장 일관되지 않은 증거가 적은 가설이 선호됩니다.
워크플로우
1단계: 귀속 증거 수집
from stix2 import MemoryStore, Filter
from collections import defaultdict
class AttributionAnalyzer:
def __init__(self):
self.evidence = []
self.hypotheses = {}
def add_evidence(self, category, description, value, confidence):
self.evidence.append({
"category": category,
"description": description,
"value": value,
"confidence": confidence,
"timestamp": None,
})
def add_hypothesis(self, actor_name, actor_id=""):
self.hypotheses[actor_name] = {
"actor_id": actor_id,
"consistent_evidence": [],
"inconsistent_evidence": [],
"neutral_evidence": [],
"score": 0,
}
def evaluate_evidence(self, evidence_idx, actor_name, assessment):
"""증거를 가설에 대해 평가합니다: consistent/inconsistent/neutral."""
if assessment == "consistent":
self.hypotheses[actor_name]["consistent_evidence"].append(evidence_idx)
self.hypotheses[actor_name]["score"] += self.evidence[evidence_idx]["confidence"]
elif assessment == "inconsistent":
self.hypotheses[actor_name]["inconsistent_evidence"].append(evidence_idx)
self.hypotheses[actor_name]["score"] -= self.evidence[evidence_idx]["confidence"] * 2
else:
self.hypotheses[actor_name]["neutral_evidence"].append(evidence_idx)
def rank_hypotheses(self):
"""귀속 점수로 가설 순위를 매깁니다."""
ranked = sorted(
self.hypotheses.items(),
key=lambda x: x[1]["score"],
reverse=True,
)
return [
{
"actor": name,
"score": data["score"],
"consistent": len(data["consistent_evidence"]),
"inconsistent": len(data["inconsistent_evidence"]),
"confidence": self._score_to_confidence(data["score"]),
}
for name, data in ranked
]
def _score_to_confidence(self, score):
if score >= 80:
return "HIGH"
elif score >= 40:
return "MODERATE"
else:
return "LOW"
2단계: 인프라 중복 분석
def analyze_infrastructure_overlap(campaign_a_infra, campaign_b_infra):
"""귀속을 위해 두 캠페인 간의 인프라를 비교합니다."""
overlap = {
"shared_ips": set(campaign_a_infra.get("ips", [])).intersection(
campaign_b_infra.get("ips", [])
),
"shared_domains": set(campaign_a_infra.get("domains", [])).intersection(
campaign_b_infra.get("domains", [])
),
"shared_asns": set(campaign_a_infra.get("asns", [])).intersection(
campaign_b_infra.get("asns", [])
),
"shared_registrars": set(campaign_a_infra.get("registrars", [])).intersection(
campaign_b_infra.get("registrars", [])
),
}
overlap_score = 0
if overlap["shared_ips"]:
overlap_score += 30
if overlap["shared_domains"]:
overlap_score += 25
if overlap["shared_asns"]:
overlap_score += 15
if overlap["shared_registrars"]:
overlap_score += 10
return {
"overlap": {k: list(v) for k, v in overlap.items()},
"overlap_score": overlap_score,
"assessment": "STRONG" if overlap_score >= 40 else "MODERATE" if overlap_score >= 20 else "WEAK",
}
3단계: 캠페인 간 TTP 비교
from attackcti import attack_client
def compare_campaign_ttps(campaign_techniques, known_actor_techniques):
"""알려진 위협 행위자 프로필과 캠페인 TTP를 비교합니다."""
campaign_set = set(campaign_techniques)
actor_set = set(known_actor_techniques)
common = campaign_set.intersection(actor_set)
unique_campaign = campaign_set - actor_set
unique_actor = actor_set - campaign_set
jaccard = len(common) / len(campaign_set.union(actor_set)) if campaign_set.union(actor_set) else 0
return {
"common_techniques": sorted(common),
"common_count": len(common),
"unique_to_campaign": sorted(unique_campaign),
"unique_to_actor": sorted(unique_actor),
"jaccard_similarity": round(jaccard, 3),
"overlap_percentage": round(len(common) / len(campaign_set) * 100, 1) if campaign_set else 0,
}
4단계: 귀속 보고서 생성
def generate_attribution_report(analyzer):
"""구조화된 귀속 평가 보고서를 생성합니다."""
rankings = analyzer.rank_hypotheses()
report = {
"assessment_date": "2026-02-23",
"total_evidence_items": len(analyzer.evidence),
"hypotheses_evaluated": len(analyzer.hypotheses),
"rankings": rankings,
"primary_attribution": rankings[0] if rankings else None,
"evidence_summary": [
{
"index": i,
"category": e["category"],
"description": e["description"],
"confidence": e["confidence"],
}
for i, e in enumerate(analyzer.evidence)
],
}
return report
검증 기준
- 증거 수집은 6가지 귀속 범주를 모두 포함합니다.
- ACH 매트릭스는 경쟁 가설에 대해 증거를 적절하게 평가합니다.
- 인프라 중복 분석은 공유 지표를 식별합니다.
- TTP 비교는 정밀도를 위해 ATT&CK 기술 ID를 사용합니다.
- 귀속 신뢰 수준이 적절하게 정당화됩니다.
- 보고서에는 대체 가설 및 오해의 소지가 있는 플래그(거짓 긍정) 고려 사항이 포함됩니다.