skills/building-threat-actor-profile-from-osint/SKILL.md
使用开源情报(OSINT)技术构建全面的威胁行为者档案,记录对手的动机、能力、基础设施和 TTP,用于主动防御。
npx skillsauth add killvxk/cybersecurity-skills-zh building-threat-actor-profile-from-osintInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
利用 OSINT 进行威胁行为者画像,系统性地收集和分析公开可用信息,以构建对手组织的全面档案。本技能涵盖从公开来源(安全厂商报告、粘贴站点、暗网论坛、社交媒体、代码仓库)收集情报、跨平台关联指标、使用 Maltego 和 SpiderFoot 等工具映射对手基础设施,以及生成指导防御策略和归因评估的结构化威胁行为者档案。
shodan、requests、beautifulsoup4、maltego-trx、stix2 库主要情报来源包括:厂商威胁报告(Mandiant、CrowdStrike、Recorded Future、Talos)、政府建议(CISA、NSA、FBI 联合建议)、学术研究论文、恶意软件仓库(VirusTotal、MalwareBazaar、Malpedia)、粘贴站点(Pastebin、GitHub Gists)、代码仓库、社交媒体账号、暗网论坛和证书透明度日志。
画像使用菱形模型(对手、基础设施、能力、受害者)、竞争假说分析(ACH)进行归因置信度评估,以及 MITRE ATT&CK 映射进行 TTP 记录。Maltego 等链接分析工具可视化指标、基础设施和行为者之间的关系。
完整的威胁行为者档案包括:各厂商的别名和命名规范、可疑来源和赞助方、动机(间谍、财务、黑客主义、破坏),以及目标行业和地区、已知攻击活动和行动、映射到 ATT&CK 的 TTP、工具集和恶意软件家族、基础设施模式和历史时间线。
import requests
import json
from datetime import datetime
class OSINTCollector:
def __init__(self, vt_key=None, otx_key=None, shodan_key=None):
self.vt_key = vt_key
self.otx_key = otx_key
self.shodan_key = shodan_key
self.collected_data = {"sources": [], "indicators": [], "reports": []}
def search_alienvault_otx(self, actor_name):
"""在 AlienVault OTX 中搜索威胁行为者情报包。"""
headers = {"X-OTX-API-KEY": self.otx_key}
url = f"https://otx.alienvault.com/api/v1/search/pulses?q={actor_name}&limit=20"
resp = requests.get(url, headers=headers)
if resp.status_code == 200:
data = resp.json()
pulses = data.get("results", [])
for pulse in pulses:
self.collected_data["reports"].append({
"source": "AlienVault OTX",
"title": pulse.get("name", ""),
"created": pulse.get("created", ""),
"description": pulse.get("description", "")[:500],
"tags": pulse.get("tags", []),
"indicators_count": len(pulse.get("indicators", [])),
"pulse_id": pulse.get("id", ""),
})
for ioc in pulse.get("indicators", []):
self.collected_data["indicators"].append({
"type": ioc.get("type", ""),
"value": ioc.get("indicator", ""),
"source": "OTX",
"pulse": pulse.get("name", ""),
})
print(f"[+] OTX: 为 '{actor_name}' 找到 {len(pulses)} 个情报包")
return self.collected_data
def search_virustotal_collections(self, actor_name):
"""在 VirusTotal 中搜索威胁行为者集合。"""
headers = {"x-apikey": self.vt_key}
url = "https://www.virustotal.com/api/v3/intelligence/search"
params = {"query": f"tag:{actor_name.lower().replace(' ', '-')}"}
resp = requests.get(url, headers=headers, params=params)
if resp.status_code == 200:
results = resp.json().get("data", [])
print(f"[+] VT: 找到 {len(results)} 个标记为 '{actor_name}' 的样本")
return results
return []
def query_shodan_infrastructure(self, indicators):
"""通过 Shodan 查询 IP 的基础设施详情。"""
results = []
for ip in indicators:
url = f"https://api.shodan.io/shodan/host/{ip}?key={self.shodan_key}"
resp = requests.get(url)
if resp.status_code == 200:
data = resp.json()
results.append({
"ip": ip,
"org": data.get("org", ""),
"asn": data.get("asn", ""),
"country": data.get("country_code", ""),
"ports": data.get("ports", []),
"hostnames": data.get("hostnames", []),
"os": data.get("os", ""),
"last_update": data.get("last_update", ""),
})
print(f"[+] Shodan: 已富化 {len(results)} 个 IP")
return results
collector = OSINTCollector(
vt_key="YOUR_VT_KEY",
otx_key="YOUR_OTX_KEY",
shodan_key="YOUR_SHODAN_KEY",
)
data = collector.search_alienvault_otx("APT29")
from stix2 import ThreatActor, IntrusionSet, Identity, Relationship, Bundle
from datetime import datetime
# 创建 STIX 2.1 威胁行为者档案
identity = Identity(
name="网络安全分析师",
identity_class="individual",
)
threat_actor = ThreatActor(
name="APT29",
description="APT29(也称为 Cozy Bear、Midnight Blizzard、NOBELIUM、The Dukes)"
"是归因于俄罗斯对外情报局(SVR)的俄罗斯国家支持的威胁组织。"
"该组织至少自 2008 年起活跃,主要针对 NATO 国家的政府、外交、"
"智库、医疗和能源机构实施网络间谍活动。",
aliases=["Cozy Bear", "Midnight Blizzard", "NOBELIUM", "The Dukes",
"Dark Halo", "UNC2452", "YTTRIUM", "Blue Kitsune", "Iron Ritual"],
roles=["agent"],
sophistication="strategic",
resource_level="government",
primary_motivation="organizational-gain",
secondary_motivations=["ideology"],
threat_actor_types=["nation-state"],
goals=["收集外国政府情报",
"长期持续访问高价值目标",
"供应链入侵以获得广泛访问"],
created_by_ref=identity.id,
)
intrusion_set = IntrusionSet(
name="APT29",
description="归因于俄罗斯 SVR 的入侵集合 APT29。",
aliases=["Cozy Bear", "Midnight Blizzard"],
first_seen="2008-01-01T00:00:00Z",
goals=["espionage"],
resource_level="government",
primary_motivation="organizational-gain",
)
relationship = Relationship(
relationship_type="attributed-to",
source_ref=intrusion_set.id,
target_ref=threat_actor.id,
)
bundle = Bundle(objects=[identity, threat_actor, intrusion_set, relationship])
with open("apt29_profile.json", "w") as f:
f.write(bundle.serialize(pretty=True))
print("[+] STIX 档案已保存: apt29_profile.json")
from attackcti import attack_client
lift = attack_client()
apt29_techs = lift.get_techniques_used_by_group("G0016")
profile_ttps = {
"initial_access": [],
"execution": [],
"persistence": [],
"defense_evasion": [],
"credential_access": [],
"lateral_movement": [],
"collection": [],
"c2": [],
"exfiltration": [],
}
tactic_mapping = {
"initial-access": "initial_access",
"execution": "execution",
"persistence": "persistence",
"defense-evasion": "defense_evasion",
"credential-access": "credential_access",
"lateral-movement": "lateral_movement",
"collection": "collection",
"command-and-control": "c2",
"exfiltration": "exfiltration",
}
for tech in apt29_techs:
tech_id = ""
for ref in tech.get("external_references", []):
if ref.get("source_name") == "mitre-attack":
tech_id = ref.get("external_id", "")
break
for phase in tech.get("kill_chain_phases", []):
tactic = phase.get("phase_name", "")
key = tactic_mapping.get(tactic)
if key:
profile_ttps[key].append({
"id": tech_id,
"name": tech.get("name", ""),
"description": tech.get("description", "")[:200],
})
print("=== APT29 TTP 档案 ===")
for tactic, techs in profile_ttps.items():
if techs:
print(f"\n{tactic.upper()}({len(techs)} 个技术):")
for t in techs[:5]:
print(f" {t['id']}: {t['name']}")
import subprocess
import json
def run_spiderfoot_scan(target, scan_name="actor_recon"):
"""对目标域名或 IP 运行 SpiderFoot 扫描。"""
cmd = [
"python3", "-m", "spiderfoot", "-s", target,
"-m", "sfp_dns,sfp_whois,sfp_shodan,sfp_virustotal,sfp_certspotter",
"-o", "json", "-q",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if result.returncode == 0:
findings = json.loads(result.stdout) if result.stdout else []
print(f"[+] SpiderFoot: 为 {target} 找到 {len(findings)} 个发现")
return findings
return []
def correlate_infrastructure(indicators):
"""查找基础设施指标之间的关系。"""
ip_to_domains = {}
domain_to_ips = {}
registrar_patterns = {}
for indicator in indicators:
ioc_type = indicator.get("type", "")
value = indicator.get("value", "")
if ioc_type == "IP_ADDRESS":
if value not in ip_to_domains:
ip_to_domains[value] = set()
elif ioc_type == "INTERNET_NAME":
if value not in domain_to_ips:
domain_to_ips[value] = set()
# 识别共享托管和注册模式
shared_ips = {ip: domains for ip, domains in ip_to_domains.items() if len(domains) > 1}
print(f"[+] 共享基础设施 IP: {len(shared_ips)} 个")
return {"shared_ips": shared_ips, "registrar_patterns": registrar_patterns}
def generate_dossier(actor_name, profile_data, ttp_data, infrastructure_data):
dossier = f"""# 威胁行为者档案: {actor_name}
## 生成时间: {datetime.now().isoformat()}
## 摘要
{profile_data.get('description', '')}
## 归因
- **可疑来源**: {profile_data.get('origin', '未知')}
- **赞助方**: {profile_data.get('sponsorship', '未知')}
- **置信度**: {profile_data.get('confidence', '中等')}
- **首次发现**: {profile_data.get('first_seen', '未知')}
## 别名
{', '.join(profile_data.get('aliases', []))}
## 目标
- **行业**: {', '.join(profile_data.get('sectors', []))}
- **地区**: {', '.join(profile_data.get('regions', []))}
- **动机**: {profile_data.get('motivation', '未知')}
## TTP 摘要(MITRE ATT&CK)
"""
for tactic, techs in ttp_data.items():
if techs:
dossier += f"\n### {tactic.replace('_', ' ').title()}\n"
for t in techs:
dossier += f"- **{t['id']}**: {t['name']}\n"
dossier += f"""
## 基础设施模式
- 已知 C2 服务器: {len(infrastructure_data.get('c2_servers', []))} 个
- 域名模式: {', '.join(infrastructure_data.get('domain_patterns', []))}
- 托管偏好: {', '.join(infrastructure_data.get('hosting', []))}
## 建议措施
1. 在 EDR/SIEM 中监控已知 TTP
2. 封锁已知基础设施指标
3. 在网络流量中狩猎行为模式
4. 针对主要技术缺口实施检测
"""
with open(f"{actor_name.lower().replace(' ', '_')}_dossier.md", "w") as f:
f.write(dossier)
print(f"[+] 已为 {actor_name} 保存档案报告")
generate_dossier("APT29", {
"description": "归因于 SVR 的俄罗斯国家支持的间谍组织",
"origin": "俄罗斯", "sponsorship": "SVR(对外情报局)",
"confidence": "高", "first_seen": "2008",
"aliases": ["Cozy Bear", "Midnight Blizzard", "NOBELIUM", "The Dukes"],
"sectors": ["政府", "外交", "智库", "医疗", "能源"],
"regions": ["北美", "欧洲", "NATO 国家"],
"motivation": "间谍活动",
}, profile_ttps, {"c2_servers": [], "domain_patterns": [], "hosting": []})
testing
设计并执行社会工程学渗透测试,包括钓鱼、语音钓鱼、短信钓鱼和物理借口活动,以衡量人员安全韧性并识别培训差距。
testing
主持结构化的事件后审查,以识别根本原因、记录有效和无效的措施,并提出可操作的改进建议以提升未来的事件响应能力。
testing
通过分析举报的邮件、提取指标、评估凭据受攻陷情况、在全组织范围隔离恶意邮件并修复受影响账号来响应网络钓鱼事件。涵盖邮件头分析、URL/附件沙箱检测和邮箱范围清除操作。适用于网络钓鱼响应、邮件事件、凭据钓鱼、鱼叉式网络钓鱼调查或钓鱼修复相关请求。
tools
票据传递(Pass-the-Ticket,PtT)是一种横向移动技术,使用窃取的 Kerberos 票据(TGT 或 TGS)在不知道用户密码的情况下向服务进行认证。通过从已控制的主机内存中提取 Kerberos 票据,攻击者可以将这些票据注入自己的会话以模拟票据所有者。