tracking-threat-actor-infrastructure について
脅威アクターが管理するインフラの発見と追跡を支援する脅威インテリジェンス向けスキルです。パッシブ DNS、証明書透明性、スキャンサービス、WHOIS、ネットワークフィンガープリントを用いた関連付け、時系列化、STIX 2.1 オブジェクトへのエクスポートを扱います。
主な機能
- 01パッシブ DNS による関連付け
- 02証明書透明性ログの監視
- 03Shodan と Censys による発見
- 04WHOIS とネットワーク指紋の分析
- 05インフラの時系列と STIX 2.1 エクスポート
活用シーン
- 01既知の C2 IP に関連するドメインの発見
- 02証明書記録による不審なドメインの特定
- 03インフラの経時変化の追跡
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill tracking-threat-actor-infrastructureインストール後、Claude Code で/tracking-threat-actor-infrastructureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEassets/template.mdreferences/api-reference.mdstandards.mdworkflows.mdscripts/agent.pyprocess.py詳細
脅威アクターのインフラストラクチャの追跡
概要
脅威アクターのインフラストラクチャの追跡では、コマンド&コントロール(C2)サーバー、フィッシングドメイン、エクスプロイトキットのホスト、弾丸防御ホスティング、ステージングサーバーなど、敵対者が管理する資産を監視し、マッピングします。このスキルでは、パッシブ DNS、証明書の透明性ログ、Shodan/Censys によるスキャン、WHOIS 分析、ネットワークフィンガープリンティングを使用して、脅威アクターのインフラストラクチャを発見・追跡し、時間の経過に伴って関連先をたどる方法を扱います。
使用する場面
- 脅威アクターのインフラストラクチャの追跡が必要なセキュリティ運用を管理する場合
- セキュリティプログラムの成熟度と運用プロセスを向上させる場合
- セキュリティチームのワークフローに標準手順を確立する場合
- 脅威インテリジェンスまたは脆弱性データを運用に統合する場合
前提条件
shodan、censys、requests、stix2ライブラリを含む Python 3.9+- API キー:Shodan、Censys、VirusTotal、SecurityTrails、PassiveTotal
- DNS、TLS/SSL 証明書、IP 割り当て、ASN 構造に関する理解
- パッシブ DNS と証明書の透明性の概念に関する知識
- ドメイン登録情報(WHOIS)検索サービスへのアクセス
主な概念
インフラストラクチャのピボット
ピボットとは、既知のインジケーターを使って、関連するインフラストラクチャを発見する手法です。既知の C2 IP アドレスから始める場合、アナリストはパッシブ DNS(ドメインの検索)、逆 WHOIS(関連する登録情報の検索)、SSL 証明書(共通の証明書の検索)、SSH キーのフィンガープリント、HTTP 応答のフィンガープリント、JARM/JA3S ハッシュ、WHOIS 登録者データを利用してピボットできます。
パッシブ DNS
パッシブ DNS データベースには、再帰リゾルバーで観測された DNS クエリと応答のデータが記録されます。これにより、アナリストは過去のドメインと IP の対応関係を調べたり、既知の C2 IP でホストされているドメインを発見したり、高速フラックスやドメイン生成アルゴリズム(DGA)の挙動を特定したりできます。
証明書の透明性
証明書の透明性(CT)ログには、認証局が発行したすべての SSL/TLS 証明書が公開記録されます。CT ログを監視することで、不審なドメインに新しく登録された証明書を把握し、フィッシングサイトや C2 インフラストラクチャが活動を開始する前に特定できます。
ネットワークフィンガープリンティング
- JARM:アクティブな TLS サーバーのフィンガープリント(TLS ハンドシェイク応答のハッシュ)
- JA3S:パッシブな TLS サーバーのフィンガープリント(Server Hello のハッシュ)
- HTTP ヘッダー:サーバーバナー、カスタムヘッダー、応答パターン
- ファビコンハッシュ:サーバー識別に使用する HTTP ファビコンのハッシュ
ワークフロー
ステップ 1:Shodan によるインフラストラクチャの発見
import shodan
api = shodan.Shodan("YOUR_SHODAN_API_KEY")
def discover_infrastructure(ip_address):
"""Discover services and metadata for a target IP."""
try:
host = api.host(ip_address)
return {
"ip": host["ip_str"],
"org": host.get("org", ""),
"asn": host.get("asn", ""),
"isp": host.get("isp", ""),
"country": host.get("country_name", ""),
"city": host.get("city", ""),
"os": host.get("os"),
"ports": host.get("ports", []),
"vulns": host.get("vulns", []),
"hostnames": host.get("hostnames", []),
"domains": host.get("domains", []),
"tags": host.get("tags", []),
"services": [
{
"port": svc.get("port"),
"transport": svc.get("transport"),
"product": svc.get("product", ""),
"version": svc.get("version", ""),
"ssl_cert": svc.get("ssl", {}).get("cert", {}).get("subject", {}),
"jarm": svc.get("ssl", {}).get("jarm", ""),
}
for svc in host.get("data", [])
],
}
except shodan.APIError as e:
print(f"[-] Shodan error: {e}")
return None
def search_c2_framework(framework_name):
"""Search Shodan for known C2 framework signatures."""
c2_queries = {
"cobalt-strike": 'product:"Cobalt Strike Beacon"',
"metasploit": 'product:"Metasploit"',
"covenant": 'http.html:"Covenant" http.title:"Covenant"',
"sliver": 'ssl.cert.subject.cn:"multiplayer" ssl.cert.issuer.cn:"operators"',
"havoc": 'http.html_hash:-1472705893',
}
query = c2_queries.get(framework_name.lower(), framework_name)
results = api.search(query, limit=100)
hosts = []
for match in results.get("matches", []):
hosts.append({
"ip": match["ip_str"],
"port": match["port"],
"org": match.get("org", ""),
"country": match.get("location", {}).get("country_name", ""),
"asn": match.get("asn", ""),
"timestamp": match.get("timestamp", ""),
})
return hosts
ステップ 2:パッシブ DNS によるピボット
import requests
def passive_dns_lookup(indicator, api_key, indicator_type="ip"):
"""Query SecurityTrails for passive DNS records."""
base_url = "https://api.securitytrails.com/v1"
headers = {"APIKEY": api_key, "Accept": "application/json"}
if indicator_type == "ip":
url = f"{base_url}/search/list"
payload = {
"filter": {"ipv4": indicator}
}
resp = requests.post(url, json=payload, headers=headers, timeout=30)
else:
url = f"{base_url}/domain/{indicator}/subdomains"
resp = requests.get(url, headers=headers, timeout=30)
if resp.status_code == 200:
return resp.json()
return None
def query_passive_total(indicator, user, api_key):
"""Query PassiveTotal for passive DNS and WHOIS data."""
base_url = "https://api.passivetotal.org/v2"
auth = (user, api_key)
# Passive DNS
pdns_resp = requests.get(
f"{base_url}/dns/passive",
params={"query": indicator},
auth=auth,
timeout=30,
)
# WHOIS
whois_resp = requests.get(
f"{base_url}/whois",
params={"query": indicator},
auth=auth,
timeout=30,
)
results = {}
if pdns_resp.status_code == 200:
results["passive_dns"] = pdns_resp.json().get("results", [])
if whois_resp.status_code == 200:
results["whois"] = whois_resp.json()
return results
ステップ 3:証明書の透明性の監視
import requests
def search_ct_logs(domain):
"""Search Certificate Transparency logs via crt.sh."""
resp = requests.get(
f"https://crt.sh/?q=%.{domain}&output=json",
timeout=30,
)
if resp.status_code == 200:
certs = resp.json()
unique_domains = set()
cert_info = []
for cert in certs:
name_value = cert.get("name_value", "")
for name in name_value.split("\n"):
unique_domains.add(name.strip())
cert_info.append({
"id": cert.get("id"),
"issuer": cert.get("issuer_name", ""),
"common_name": cert.get("common_name", ""),
"name_value": name_value,
"not_before": cert.get("not_before", ""),
"not_after": cert.get("not_after", ""),
"serial_number": cert.get("serial_number", ""),
})
return {
"domain": domain,
"total_certificates": len(certs),
"unique_domains": sorted(unique_domains),
"certificates": cert_info[:50],
}
return None
def monitor_new_certs(domains, interval_hours=1):
"""Monitor for newly issued certificates for a list of domains."""
from datetime import datetime, timedelta
cutoff = (datetime.utcnow() - timedelta(hours=interval_hours)).isoformat()
new_certs = []
for domain in domains:
result = search_ct_logs(domain)
if result:
for cert in result.get("certificates", []):
if cert.get("not_before", "") > cutoff:
new_certs.append({
"domain": domain,
"cert": cert,
})
return new_certs
ステップ 4:インフラストラクチャの相関付けとタイムライン
from datetime import datetime
def build_infrastructure_timeline(indicators):
"""Build a timeline of infrastructure changes."""
timeline = []
for ind in indicators:
if "passive_dns" in ind:
for record in ind["passive_dns"]:
timeline.append({
"timestamp": record.get("firstSeen", ""),
"event": "dns_resolution",
"source": record.get("resolve", ""),
"target": record.get("value", ""),
"record_type": record.get("recordType", ""),
})
if "certificates" in ind:
for cert in ind["certificates"]:
timeline.append({
"timestamp": cert.get("not_before", ""),
"event": "certificate_issued",
"domain": cert.get("common_name", ""),
"issuer": cert.get("issuer", ""),
})
timeline.sort(key=lambda x: x.get("timestamp", ""))
return timeline
検証基準
- Shodan/Censys のクエリで、対象 IP のインフラストラクチャの詳細が返される
- パッシブ DNS から過去のドメインと IP の対応関係が明らかになる
- 証明書の透明性検索で、関連ドメインが見つかる
- インフラストラクチャのピボットによって、新たな関連インジケーターが発見される
- インフラストラクチャの経時的な変化がタイムラインに示される
- 結果を STIX 2.1 の Infrastructure オブジェクトとしてエクスポートできる