mcpField
A
analyzing-apt-group-with-mitre-navigator

analyzing-apt-group-with-mitre-navigator

github.com/mukul975セキュリティ35.2k532 回インストール8 週間前に更新
リポジトリ

analyzing-apt-group-with-mitre-navigator について

APT グループの技術と戦術を Navigator で整理する、セキュリティ分析者向けの MITRE ATT&CK 分析スキルです。グループ比較、検知カバレッジのギャップ分析、検知エンジニアリング向けレポートを扱います。

主な機能

  1. 01ATT&CK のグループと技術データの取得
  2. 02Navigator レイヤー JSON の生成
  3. 03複数 APT グループの比較
  4. 04レイヤー重ね合わせによる検知ギャップ分析
  5. 05戦術別の技術分類

活用シーン

  1. 01APT グループが使う技術の整理
  2. 02グループ間の TTP 比較と共通点の抽出
  3. 03監視範囲の確認と検知優先度の決定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill analyzing-apt-group-with-mitre-navigator

インストール後、Claude Code で/analyzing-apt-group-with-mitre-navigatorを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
references/
api-reference.md
scripts/
agent.py

詳細

MITRE ATT&CK Navigator を使用した APT グループの分析

概要

MITRE ATT&CK Navigator は、ATT&CK マトリックスに注釈を付けて調査できるウェブベースのツールです。アナリストは、脅威アクターが使用するテクニックの範囲を可視化し、複数の APT グループを比較して、検知のギャップを特定し、脅威情報に基づく防御戦略を策定できます。このスキルでは、ATT&CK データをプログラムで照会する方法、APT グループの TTP を Navigator のレイヤーにマッピングする方法、ギャップ分析用の複数レイヤーのオーバーレイを作成する方法、検知エンジニアリングチーム向けの実用的なインテリジェンスレポートを生成する方法を取り上げます。

使用する場面

  • MITRE Navigator を使用して APT グループを分析する必要があるセキュリティインシデントを調査するとき
  • この領域の検知ルールや脅威ハンティングクエリを作成するとき
  • SOC アナリストがこの種の分析に関する体系的な手順を必要とするとき
  • 関連する攻撃テクニックに対するセキュリティ監視の範囲を検証するとき

前提条件

  • attackcti、mitreattack-python、stix2、requests ライブラリを含む Python 3.9 以降
  • ATT&CK Navigator(https://mitre-attack.github.io/attack-navigator/)またはローカル環境へのデプロイ
  • ATT&CK Enterprise マトリックスの理解:14 個の戦術、200 を超えるテクニック、サブテクニック
  • 脅威アクターデータを取得するための脅威インテリジェンスレポートまたは MISP/OpenCTI へのアクセス
  • STIX 2.1 の Intrusion Set および Attack Pattern オブジェクトに関する知識

主な概念

ATT&CK Navigator のレイヤー

Navigator のレイヤーは、ATT&CK テクニックにスコア、色、コメント、メタデータを付ける JSON ファイルです。各レイヤーは、単一の APT グループが使用するテクニック、検知機能のマップ、または複合オーバーレイを表すことができます。レイヤーバージョン 4.5 は、enterprise-attack、mobile-attack、ics-attack の各ドメインに対応し、プラットフォーム(Windows、Linux、macOS、Cloud、Azure AD、Office 365、SaaS)によるフィルタリングをサポートしています。

ATT&CK における APT グループのプロファイル

ATT&CK には、テクニックの使用が記録された 140 を超える脅威グループが登録されています。各グループのプロファイルには、別名、標的とするセクター、関連するキャンペーン、使用するソフトウェア、および手順レベルの詳細を含むテクニックのマッピングが含まれています。グループは G コードで識別されます(例:APT29 は G0016、APT28 は G0007、Lazarus Group は G0032)。

複数レイヤーの分析

Navigator では複数のレイヤーを同時に読み込めます。これにより、アナリストは脅威アクターの TTP を検知範囲に重ね合わせてギャップを特定したり、複数の APT グループを比較して優先すべき共通テクニックを見つけたり、時間の経過に伴うテクニックのカバレッジの変化を追跡したりできます。

ワークフロー

ステップ 1:APT グループの ATT&CK データを照会する
from attackcti import attack_client
import json

lift = attack_client()

# Get all threat groups
groups = lift.get_groups()
print(f"Total ATT&CK groups: {len(groups)}")

# Find APT29 (Cozy Bear / Midnight Blizzard)
apt29 = next((g for g in groups if g.get('name') == 'APT29'), None)
if apt29:
    print(f"Group: {apt29['name']}")
    print(f"Aliases: {apt29.get('aliases', [])}")
    print(f"Description: {apt29.get('description', '')[:300]}")

# Get techniques used by APT29 (G0016)
techniques = lift.get_techniques_used_by_group("G0016")
print(f"APT29 uses {len(techniques)} techniques")

technique_map = {}
for tech in techniques:
    tech_id = ""
    for ref in tech.get("external_references", []):
        if ref.get("source_name") == "mitre-attack":
            tech_id = ref.get("external_id", "")
            break
    if tech_id:
        tactics = [p.get("phase_name", "") for p in tech.get("kill_chain_phases", [])]
        technique_map[tech_id] = {
            "name": tech.get("name", ""),
            "tactics": tactics,
            "description": tech.get("description", "")[:500],
            "platforms": tech.get("x_mitre_platforms", []),
            "data_sources": tech.get("x_mitre_data_sources", []),
        }
ステップ 2:Navigator レイヤーの JSON を生成する
def create_navigator_layer(group_name, technique_map, color="#ff6666"):
    techniques_list = []
    for tech_id, info in technique_map.items():
        for tactic in info["tactics"]:
            techniques_list.append({
                "techniqueID": tech_id,
                "tactic": tactic,
                "color": color,
                "comment": info["name"],
                "enabled": True,
                "score": 100,
                "metadata": [
                    {"name": "group", "value": group_name},
                    {"name": "platforms", "value": ", ".join(info["platforms"])},
                ],
            })

    layer = {
        "name": f"{group_name} TTP Coverage",
        "versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"},
        "domain": "enterprise-attack",
        "description": f"Techniques attributed to {group_name}",
        "filters": {
            "platforms": ["Linux", "macOS", "Windows", "Cloud",
                          "Azure AD", "Office 365", "SaaS", "Google Workspace"]
        },
        "sorting": 0,
        "layout": {
            "layout": "side", "aggregateFunction": "average",
            "showID": True, "showName": True,
            "showAggregateScores": False, "countUnscored": False,
        },
        "hideDisabled": False,
        "techniques": techniques_list,
        "gradient": {"colors": ["#ffffff", color], "minValue": 0, "maxValue": 100},
        "legendItems": [
            {"label": f"Used by {group_name}", "color": color},
            {"label": "Not observed", "color": "#ffffff"},
        ],
        "showTacticRowBackground": True,
        "tacticRowBackground": "#dddddd",
        "selectTechniquesAcrossTactics": True,
        "selectSubtechniquesWithParent": False,
        "selectVisibleTechniques": False,
    }
    return layer

layer = create_navigator_layer("APT29", technique_map)
with open("apt29_layer.json", "w") as f:
    json.dump(layer, f, indent=2)
print("[+] Layer saved: apt29_layer.json")
ステップ 3:複数の APT グループを比較する
groups_to_compare = {"G0016": "APT29", "G0007": "APT28", "G0032": "Lazarus Group"}
group_techniques = {}

for gid, gname in groups_to_compare.items():
    techs = lift.get_techniques_used_by_group(gid)
    tech_ids = set()
    for t in techs:
        for ref in t.get("external_references", []):
            if ref.get("source_name") == "mitre-attack":
                tech_ids.add(ref.get("external_id", ""))
    group_techniques[gname] = tech_ids

common_to_all = set.intersection(*group_techniques.values())
print(f"Techniques common to all groups: {len(common_to_all)}")
for tid in sorted(common_to_all):
    print(f"  {tid}")

for gname, techs in group_techniques.items():
    others = set.union(*[t for n, t in group_techniques.items() if n != gname])
    unique = techs - others
    print(f"\nUnique to {gname}: {len(unique)} techniques")
ステップ 4:レイヤーのオーバーレイで検知ギャップを分析する
# Define your current detection capabilities
detected_techniques = {
    "T1059", "T1059.001", "T1071", "T1071.001", "T1566", "T1566.001",
    "T1547", "T1547.001", "T1053", "T1053.005", "T1078", "T1027",
}

actor_techniques = set(technique_map.keys())
covered = actor_techniques.intersection(detected_techniques)
gaps = actor_techniques - detected_techniques

print(f"=== Detection Gap Analysis for APT29 ===")
print(f"Actor techniques: {len(actor_techniques)}")
print(f"Detected: {len(covered)} ({len(covered)/len(actor_techniques)*100:.0f}%)")
print(f"Gaps: {len(gaps)} ({len(gaps)/len(actor_techniques)*100:.0f}%)")

# Create gap layer (red = undetected, green = detected)
gap_techniques = []
for tech_id in actor_techniques:
    info = technique_map.get(tech_id, {})
    for tactic in info.get("tactics", [""]):
        color = "#66ff66" if tech_id in detected_techniques else "#ff3333"
        gap_techniques.append({
            "techniqueID": tech_id,
            "tactic": tactic,
            "color": color,
            "comment": f"{'DETECTED' if tech_id in detected_techniques else 'GAP'}: {info.get('name', '')}",
            "enabled": True,
            "score": 100 if tech_id in detected_techniques else 0,
        })

gap_layer = {
    "name": "APT29 Detection Gap Analysis",
    "versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"},
    "domain": "enterprise-attack",
    "description": "Green = detected, Red = gap",
    "techniques": gap_techniques,
    "gradient": {"colors": ["#ff3333", "#66ff66"], "minValue": 0, "maxValue": 100},
    "legendItems": [
        {"label": "Detected", "color": "#66ff66"},
        {"label": "Detection Gap", "color": "#ff3333"},
    ],
}
with open("apt29_gap_layer.json", "w") as f:
    json.dump(gap_layer, f, indent=2)
ステップ 5:戦術ごとの内訳を分析する
from collections import defaultdict

tactic_breakdown = defaultdict(list)
for tech_id, info in technique_map.items():
    for tactic in info["tactics"]:
        tactic_breakdown[tactic].append({"id": tech_id, "name": info["name"]})

tactic_order = [
    "reconnaissance", "resource-development", "initial-access",
    "execution", "persistence", "privilege-escalation",
    "defense-evasion", "credential-access", "discovery",
    "lateral-movement", "collection", "command-and-control",
    "exfiltration", "impact",
]

print("\n=== APT29 Tactic Breakdown ===")
for tactic in tactic_order:
    techs = tactic_breakdown.get(tactic, [])
    if techs:
        print(f"\n{tactic.upper()} ({len(techs)} techniques):")
        for t in techs:
            print(f"  {t['id']}: {t['name']}")

検証基準

  • TAXII サーバー経由で ATT&CK データの照会に成功している
  • APT グループが、手順の例を含む、記録済みのすべてのテクニックにマッピングされている
  • Navigator レイヤーの JSON が検証に合格し、ATT&CK Navigator で正しく表示される
  • 複数レイヤーのオーバーレイで、脅威アクターと検知範囲を比較できる
  • 検知ギャップ分析により、監視されていないテクニックが特定され、推奨データソースが提示される
  • グループ間の比較で、共通および固有の TTP が明らかになる
  • 出力が検知エンジニアリングの優先順位付けに活用できる

参考資料

コメント