$npx -y skills add killvxk/cybersecurity-skills-zh --skill analyzing-apt-group-with-mitre-navigator使用 MITRE ATT&CK Navigator 分析高级持续性威胁(APT)组织的技术手法,创建对手 TTP 的分层热力图,用于检测差距分析和威胁导向防御。
| 1 | # 使用 MITRE ATT&CK Navigator 分析 APT 组织 |
| 2 | |
| 3 | ## 概述 |
| 4 | |
| 5 | MITRE ATT&CK Navigator 是一款基于 Web 的工具,用于标注和探索 ATT&CK 矩阵,使分析人员能够可视化威胁行为者(Threat Actor)的技术覆盖情况、比较多个 APT 组织、识别检测差距,并构建威胁导向防御策略。本技能涵盖通过编程方式查询 ATT&CK 数据、将 APT 组织的 TTP 映射到 Navigator 层、创建多层叠加进行差距分析,以及为检测工程团队生成可执行情报报告。 |
| 6 | |
| 7 | ## 前置条件 |
| 8 | |
| 9 | - Python 3.9+,安装 `attackcti`、`mitreattack-python`、`stix2`、`requests` 库 |
| 10 | - ATT&CK Navigator (https://mitre-attack.github.io/attack-navigator/) 或本地部署版本 |
| 11 | - 了解 ATT&CK Enterprise 矩阵:14 个战术、200+ 个技术及子技术 |
| 12 | - 访问威胁情报报告或 MISP/OpenCTI 获取威胁行为者数据 |
| 13 | - 熟悉 STIX 2.1 的 Intrusion Set 和 Attack Pattern 对象 |
| 14 | |
| 15 | ## 核心概念 |
| 16 | |
| 17 | ### ATT&CK Navigator 层 |
| 18 | |
| 19 | Navigator 层是 JSON 文件,用于为 ATT&CK 技术添加分数、颜色、注释和元数据标注。每个层可以代表单个 APT 组织的技术使用情况、检测能力图谱或组合叠加层。4.5 版本层格式支持 enterprise-attack、mobile-attack 和 ics-attack 域,并可按平台(Windows、Linux、macOS、Cloud、Azure AD、Office 365、SaaS)进行过滤。 |
| 20 | |
| 21 | ### ATT&CK 中的 APT 组织画像 |
| 22 | |
| 23 | ATT&CK 收录了超过 140 个威胁组织及其记录在案的技术使用情况。每个组织画像包含别名、目标行业、关联攻击活动、所用软件及技术映射(含过程级详情)。组织通过 G 代码标识(如 APT29 为 G0016,APT28 为 G0007,Lazarus Group 为 G0032)。 |
| 24 | |
| 25 | ### 多层分析 |
| 26 | |
| 27 | Navigator 支持同时加载多个层,使分析人员能够将威胁行为者的 TTP 叠加到检测覆盖范围上以识别差距,比较多个 APT 组织以发现值得优先处理的共同技术,并追踪技术覆盖随时间的变化。 |
| 28 | |
| 29 | ## 实践步骤 |
| 30 | |
| 31 | ### 步骤 1:查询 APT 组织的 ATT&CK 数据 |
| 32 | |
| 33 | ```python |
| 34 | from attackcti import attack_client |
| 35 | import json |
| 36 | |
| 37 | lift = attack_client() |
| 38 | |
| 39 | # 获取所有威胁组织 |
| 40 | groups = lift.get_groups() |
| 41 | print(f"Total ATT&CK groups: {len(groups)}") |
| 42 | |
| 43 | # 查找 APT29(Cozy Bear / Midnight Blizzard) |
| 44 | apt29 = next((g for g in groups if g.get('name') == 'APT29'), None) |
| 45 | if apt29: |
| 46 | print(f"Group: {apt29['name']}") |
| 47 | print(f"Aliases: {apt29.get('aliases', [])}") |
| 48 | print(f"Description: {apt29.get('description', '')[:300]}") |
| 49 | |
| 50 | # 获取 APT29(G0016)使用的技术 |
| 51 | techniques = lift.get_techniques_used_by_group("G0016") |
| 52 | print(f"APT29 uses {len(techniques)} techniques") |
| 53 | |
| 54 | technique_map = {} |
| 55 | for tech in techniques: |
| 56 | tech_id = "" |
| 57 | for ref in tech.get("external_references", []): |
| 58 | if ref.get("source_name") == "mitre-attack": |
| 59 | tech_id = ref.get("external_id", "") |
| 60 | break |
| 61 | if tech_id: |
| 62 | tactics = [p.get("phase_name", "") for p in tech.get("kill_chain_phases", [])] |
| 63 | technique_map[tech_id] = { |
| 64 | "name": tech.get("name", ""), |
| 65 | "tactics": tactics, |
| 66 | "description": tech.get("description", "")[:500], |
| 67 | "platforms": tech.get("x_mitre_platforms", []), |
| 68 | "data_sources": tech.get("x_mitre_data_sources", []), |
| 69 | } |
| 70 | ``` |
| 71 | |
| 72 | ### 步骤 2:生成 Navigator 层 JSON |
| 73 | |
| 74 | ```python |
| 75 | def create_navigator_layer(group_name, technique_map, color="#ff6666"): |
| 76 | techniques_list = [] |
| 77 | for tech_id, info in technique_map.items(): |
| 78 | for tactic in info["tactics"]: |
| 79 | techniques_list.append({ |
| 80 | "techniqueID": tech_id, |
| 81 | "tactic": tactic, |
| 82 | "color": color, |
| 83 | "comment": info["name"], |
| 84 | "enabled": True, |
| 85 | "score": 100, |
| 86 | "metadata": [ |
| 87 | {"name": "group", "value": group_name}, |
| 88 | {"name": "platforms", "value": ", ".join(info["platforms"])}, |
| 89 | ], |
| 90 | }) |
| 91 | |
| 92 | layer = { |
| 93 | "name": f"{group_name} TTP Coverage", |
| 94 | "versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"}, |
| 95 | "domain": "enterprise-attack", |
| 96 | "description": f"Techniques attributed to {group_name}", |
| 97 | "filters": { |
| 98 | "platforms": ["Linux", "macOS", "Windows", "Cloud", |
| 99 | "Azure AD", "Office 365", "SaaS", "Google Workspace"] |
| 100 | }, |
| 101 | "sorting": 0, |
| 102 | "layout": { |
| 103 | "layout": "side", "aggregateFunction": "average", |
| 104 | "showID": True, "showName": True, |
| 105 | "showAggregateScores": False, "countUnscored": False, |
| 106 | }, |
| 107 | "hideDisabled": False, |
| 108 | "techniques": techniques_list, |
| 109 | "gradient": {"colors": ["#ffffff", color], "minValue": 0, "maxValue": 100}, |
| 110 | "legendItems": [ |
| 111 | {"label": f"Used by {group_name}", "color": color}, |
| 112 | {"label": "Not observed", "color": "#ffffff"}, |
| 113 | ], |
| 114 | "showTacticRowBackground": True, |
| 115 | "tacticRowBackground": "#dddddd", |
| 116 | "selectTechniquesAcrossTactics": True, |
| 117 | "selectSubtechniquesWithParent": False, |
| 118 | "selectVisibleTechniques": False, |
| 119 | } |
| 120 | return layer |
| 121 | |
| 122 | layer = create_navigator_layer("APT29", technique_map) |
| 123 | with open("apt29_layer.json", "w") as f: |
| 124 | json.dump(layer, f, indent=2) |
| 125 | print("[+] Layer saved: apt29_layer.json") |
| 126 | ``` |
| 127 | |
| 128 | ### 步骤 3:比较多个 APT 组织 |
| 129 | |
| 130 | ```python |
| 131 | groups_to_compare = {"G0016": "APT29", "G0007": "APT28", "G0032": "Lazarus Group"} |
| 132 | group_techniques = {} |
| 133 | |
| 134 | for gid, gname in groups_to_compare.items(): |
| 135 | techs = lift.get_techniques_used_by_group(gid) |
| 136 | tech_ids = set() |