ARES攻击图引擎深度剖析:如何用BloodHound数据计算到域管最短路径
ARES攻击图引擎深度剖析:如何用BloodHound数据计算到域管最短路径
ARES 是一款面向授权红队行动(authorized red-team engagement)的自动化平台,其攻击图(Attack Graph)引擎能够将 BloodHound / SharpHound 采集的域环境 JSON 数据导入有向图,并用 Dijkstra 算法从当前立足点计算到 Domain Admin(域管理员)的最短攻击路径,帮助攻击者(或防守方)一眼看清"最快拿下域控的路线"。
这篇文章面向新手,用尽量少的代码,讲清楚三件事:
- 攻击图的节点和边分别代表什么;
- 边权重如何量化"这条路好不好走";
- 从 BloodHound 数据导入,到在 CLI 和 Dashboard 上查看最短路径的完整流程。
一、攻击图是什么:把域环境变成一张"地图"
传统上,渗透测试人员拿到 BloodHound 数据后,要在网页版图里手动翻找关系:谁有 SPN、谁对哪个组有 WriteDACL、哪条 ACL 链能通向 DCSync……节点一多,人眼很容易漏掉短路径。
ARES 的做法是把攻击关系建模成一张有向图(底层使用 NetworkX 的 DiGraph):
| 概念 | 含义 | 示例 |
|---|---|---|
| 节点(Node) | 主机、用户、组、凭据、哈希、域名、发现项 | user:CORP\svc_sql、group:DOMAIN ADMINS |
| 边(Edge) | 一次可执行的攻击关系 | kerberoastable、member_of、dcsync_path |
| 边权重(Weight) | 数值越小 = 这条路越好走 | ACL 滥用 0.3、DCSync 0.2 |
| 高价值目标 | 找到通往它的路径就是胜利 | Domain Admins、krbtgt、NTDS.dit |
引擎的核心定义在 ares/graph/attack_graph.py 的 AttackGraph 类中,其中 HIGH_VALUE_LABELS 列出了域环境中最值得攻击的目标:Domain Admins、Enterprise Admins、Schema Admins、Administrators、krbtgt 和 NTDS.dit。
一个典型的图构建过程(官方文档 docs/ENGINE_FLOW.md 中有完整示例):
CORP.LOCAL (domain)
└─[has_user]──► svc_sql (user)
└─[has_spn]──► MSSQLSvc/db01 (service)
└─[kerberoastable]──► krb5tgs hash
每个节点还带有 risk_score(风险分):域控是 4.0、管理员用户是 5.0、可 Kerberoast 的哈希是 3.5,前端渲染时会据此决定颜色和大小的视觉层级。
二、导入 BloodHound 数据:从 JSON 到图
导入入口是 ingest_bloodhound() 方法(ares/graph/attack_graph.py#L734-L781),它接受单个 JSON 文件或包含多个 JSON 的目录,同时兼容 BloodHound CE(v5+)和旧版(v4)两种格式:
- 自动识别
computers、users、groups、domains、sessions等数据块; - 每个对象上的 ACE(访问控制项)会被逐条解析;
- 只有命中危险权限白名单的 ACE 才会被画进图里,包括:
GenericAll、GenericWrite、WriteOwner、WriteDacl、AllExtendedRights、ForceChangePassword、AddMember、ReadLAPSPassword、ReadGMSAPassword、DCSync、Owns、AddAllowedToAct等(见 ares/graph/attack_graph.py#L885-L908)。
同时,具备 Kerberoast 条件的用户(has_spn=true)会自动连出一条 kerberoastable 边;关闭了预认证的账号(dontreqpreauth=true)则连出 asreproastable 边——这意味着导入完成后,图里已经隐含了大量现成的攻击机会。
导入结果是一个统计 dict:
nodes_added(新增节点数)、edges_added(新增边数)、file_count(处理文件数),方便快速判断数据是否导入成功。
上图是 ARES Dashboard 的 Graph 页面:路径高亮(PATHWAY LOCKED)直接展示从入口网关到目标主机的攻击路径,右侧面板同步展示妥协状态与漏洞发现。
三、边权重设计:怎么量化"这条路好不好走"
攻击图最有意思的部分,是给每条攻击边打一个 0~1 的难度权重,数值越小代表越容易利用。这样"最短路径"就不再是最少跳数,而是综合难度最低的路径。
引擎内置的权重表(_RIGHT_WEIGHTS,ares/graph/attack_graph.py#L893-L898):
| 攻击边 | 权重 | 直观理解 |
|---|---|---|
member_of(组成员关系) |
0.1 | 天然存在的联系,几乎零成本 |
dcsync_path(DCSync 通道) |
0.2 | 拿到即全域哈希,但前置条件苛刻 |
asreproastable |
0.2 | 无需任何凭据即可请求 |
ACL 滥用(ACE) |
0.3 | 一步提权,成功率较高 |
ReadLAPSPassword |
0.5 | 读取本地管理员密码 |
AddMember |
0.6 | 把自己加进目标组 |
ForceChangePassword |
0.7 | 强制重置密码接管账户 |
WriteDacl / WriteOwner |
0.8 | 可篡改任意对象的 ACL |
GenericAll |
0.9 | 万能写权限,路径最"粗" |
理解规则很简单:权重越小的边,越应该优先出现在推荐路径里。比如一条 用户 →(0.1)→ 组 →(0.2)→ NTDS 的链,总难度只有 0.3,远好过一条需要 GenericAll(0.9) + ForceChangePassword(0.7) 的链。
四、计算到域管的最短路径:Dijkstra 实战
图构建完成后,路径计算由三个方法配合完成(docs/ENGINE_FLOW.md 有方法速查表):
shortest_path_to_da():自动定位图中DOMAIN ADMINS节点,从所有普通用户节点出发(最多尝试 50 个,避免大图卡死),用nx.shortest_path(weight="weight")跑 Dijkstra,返回全局最短的那条路;find_path(source, target):按人类可读的标签(如jsmith、Domain Admins)模糊查找两个节点并计算路径,比手填节点 ID 友好得多;path_to_report(path):把路径转换成人类可读的分步报告,每步标注用了哪个攻击模块(如ad.kerberoast、ad.dcsync),并给出路径总难度分total_score(分数越低越容易打)。
另外 top_paths(n) 会一次性列出通往所有高价值目标中最简单的 N 条路径,按难度升序排列——这是"给我 5 条最值得打的路"的标准答案。
CLI 两分钟上手
命令行子命令 graph 注册在 ares/cli/typer_main.py,两条命令即可看到全部结果:
# 查看某 campaign 中难度最低的 5 条攻击路径
ares graph show <campaign-id> --top 5
# 查询两个指定节点之间的最短路径
ares graph path <campaign-id> --from svc_sql --to "Domain Admins"
输出会给出路径长度、总难度分和每步使用的攻击模块,例如:
Path 1 svc_sql → NTDS:CORP score=0.3
svc_sql ──[member of]──► CORP via ad.enum_acl
CORP ──[dcsync → all hashes]──► NTDS:CORP via ad.dcsync
Dashboard 与 API 端点
图形化端点定义在 ares/api/server.py:
| 端点 | 作用 |
|---|---|
POST /graph/{campaign_id}/bloodhound |
导入 BloodHound JSON,导入后自动计算 shortest_to_da 并随响应返回 |
GET /graph/{campaign_id}/attack-paths |
查询最短路径 / Top N 路径(支持 source、target、top_n 参数) |
GET /graph/{campaign_id} |
返回 Dashboard 可视化所需的节点、边与配色图例 |
其中 campaign 视图的节点/边组装逻辑在 ares/api/graph.py 的 build_campaign_graph(),前端渲染页位于 frontend/src/features/graph/GraphPage.tsx。Dashboard 中各模块产生的数据会自动汇入这张图,模块目录如下图所示:
ARES Dashboard 的模块目录:76 个内置模块的运行产出(主机、用户、ACL、凭据)正是攻击图的数据来源。
五、导出与数据安全的两个细节
多格式导出:to_d3_json() 直接对接 Dashboard 的 D3.js 力导向图;to_graphml() 兼容 Gephi / yEd;to_dot() 兼容 Graphviz(无 pydot 时自动退化为手写 DOT 生成),见 ares/graph/attack_graph.py#L707-L730。
敏感信息剥离:图在持久化或返回前端前,会经过 _safe_graph_value() 清洗(ares/graph/attack_graph.py#L50-L62),凡是键名命中 password、hash_value、nt_hash、cracked_value、token 等敏感字段的值都会被整段丢弃。这保证了"图上能看到路径,但看不到密码"——对需要把图截图放进报告的团队来说,是很实用的安全护栏。
六、总结:一条数据的完整旅程
把全文串起来,BloodHound 数据在 ARES 里的旅程是:
ingest_bloodhound()解析 JSON,只保留危险 ACE 与可利用特征,生成节点和带权边;shortest_path_to_da()用 Dijkstra 在"难度"度量下找到通往 Domain Admins 的最优链;path_to_report()把路径翻译成带攻击模块标注的分步报告;- 通过
ares graphCLI、REST API 或 Dashboard Graph 页面查看,并可导出为 GraphML / DOT 交给 Gephi 继续分析。
对于刚接触攻击面分析的同学,建议先跑 ares graph show 看看真实环境里的路径输出,再对照边权重表理解"为什么这条路径被排在第一位"——这就是 ARES 攻击图引擎的精髓:把"哪条路最快"从经验判断变成了可计算、可排序、可导出的工程问题。

