资讯动态

BloodHound CE实战:AD攻击路径分析与权限提升路径排查

发布时间:2026/10/21 6:42:03 来源:尧图企业网站定制
BloodHound CE 这个东西很多人一听名字就以为是进攻侧的专属工具。实际上我在做 AD 环境安全评估时最后能让团队点头的往往不是几十页巡检报告而是 BloodHound 画出的一条权限提升路径。所谓攻击路径分析就是看清域里“谁能通过组关系、对象权限、会话关系一步步拿到高权限”这件事。BloodHound CE 是社区版Docker 部署很快官方镜像拉下来五分钟左右就能跑起来。这里把我从部署、采集、查路径到排查问题的完整过程整理出来包含 Docker Compose 配置、SharpHound 采集命令、Cypher 查询思路和 7 个实战避坑点适合 AD 安全运维、红队测试人员和刚接触域权限模型的后端工程师参考。1. 先搞懂 BloodHound CE 解决什么问题1.1 攻击路径分析到底在找什么传统 AD 风险评估常做两件事检查弱口令、检查高危组里有哪些人。这些当然有用但最大盲区是“间接路径”。举例域内一台普通员工电脑本地管理员账号恰好密码和某服务账号一致而该服务账号在另一台服务器上有本地管理员权限那台服务器又因为某服务以域管身份运行最终域管权限被间接控制。这种链式关系靠人工翻组策略和 ACL 会非常痛苦BloodHound 做的就是把这些关系变成图节点是用户、组、计算机、域边是 Session、MemberOf、GenericAll、AdminTo 等关系。有了图最短路径、可达性、高危节点一眼就能看出来。1.2 为什么社区版值得用旧版 BloodHound 用的是桌面客户端加 Neo4j部署和升级略繁琐。CE 改成 Web UI 和 API 后Docker 化非常干净数据层仍然用 Neo4j但交互层不再依赖本机安装包。CE 免费覆盖路径分析和查询的核心功能对中小型 AD 环境几千用户、几十台服务器完全够用。企业版多了自动化编排和更多数据源接入但多数团队其实用不到。CE 还能通过 API 上传数据、跑自定义查询甚至被脚本调度方便嵌入评估流程。1.3 部署前必须想清楚的三个问题数据敏感问题AD 用户、会话、ACL 属于高度敏感数据如果部署环境暴露到公网风险极大我强烈建议只在内网或隔离网段部署。存储位置问题Neo4j 数据默认写入 Docker 卷备份和销毁要考虑清楚。测试环境大胆删生产环境的卷要单独规划磁盘上限。采集器版本问题SharpHound 和 BloodHound CE 之间存在版本对应关系新版 CE 通常要求新版采集器部署前先把版本对齐。这三个问题想清楚后面基本顺风顺水。2. 环境准备给 Docker 部署腾出安全位置2.1 检查服务器资源和 Docker 版本Neo4j 是内存大户。我的建议是 2 核 4G 起步但跑大域节点数量超过 5 万会吃力最好 4 核 8G。上面说的“五分钟启动”是在资源充足、镜像已缓存的前提下。准备阶段先跑几条命令确认环境docker version docker compose version free -h df -hDocker Compose 旧版用docker-compose命令新环境用docker compose本文按新版写。如果系统自带的是 v1建议升级或者把命令换成docker-compose也行。还要注意不要用 root 账号直接运行避免权限失控。检查完版本后顺手确认/var/lib/docker所在分区剩余空间Neo4j 数据量增长很快留出 10G 以上比较稳妥。2.2 网络端口与数据卷规划CE 对外主要暴露两个端口Web 端口默认 8080和 Neo4j 端口Bolt 7687、HTTP 7474。实际使用中Web 端口必须对外开放给分析人员Bolt 端口最好只对特定内网网段开放因为它是数据库直连接口权限很大。云主机别忘了安全组本地防火墙也要放行。数据卷方面我习惯把 Neo4j 的数据挂到命名卷并单独挂一个 logs 卷这样容器重建时数据还在排错也能看到日志。BloodHound 的配置文件同样挂成卷避免升级后丢失配置。2.3 镜像选择与版本锁定的坑镜像不要用 latest这句话我说过很多次。latest 在新版本发布后会突然变掉尤其 BloodHound 和 Neo4j 版本之间经常需要联动某一天重新部署就起不来了。正确做法是在 compose 文件里写固定版本号比如 Neo4j 写 5.x 的具体小版本BloodHound 写自己测试过的版本。拉镜像可以用官方仓库但不同网络的下载速度差异很大建议在低峰期拉取必要时提前导入离线环境。另外注意 CE 和 SharpHound 有兼容矩阵部署前查一眼官方发布说明比启动后再排查省时间。3. 五分钟部署docker compose 快速拉起 BloodHound CE3.1 编写 compose 文件我会先建一个独立目录来放配置mkdir -p ~/bloodhound-ce cd ~/bloodhound-ce然后创建docker-compose.yml。下面是简化版核心思路是 Neo4j 和 BloodHound 两个服务数据卷分开。特别注意环境变量里的密码首次启动后如果要改需要一起改 Neo4j 和 CE 的配置否则连接失败。services: neo4j: image: neo4j:5-community container_name: bh-neo4j restart: unless-stopped environment: NEO4J_AUTH: neo4j/YourStrongPassword NEO4J_dbms_memory_pagecache_size: 512M NEO4J_dbms_memory_heap_max__size: 1G volumes: - neo4j_data:/data - neo4j_logs:/logs ports: - 7474:7474 - 7687:7687 bloodhound: image: your-registry/bloodhound-ce:6.x # 替换为官方镜像地址 container_name: bh-ce restart: unless-stopped environment: NEO4J_USER: neo4j NEO4J_PASSWORD: YourStrongPassword NEO4J_URI: bolt://neo4j:7687 NEO4J_DB: neo4j ports: - 8080:8080 depends_on: - neo4j volumes: - bh_config:/etc/bloodhound volumes: neo4j_data: neo4j_logs: bh_config:注意NEO4J_dbms_memory_heap_max__size里有两个下划线这是 Neo4j 环境变量映射的写法少一个都不生效。depends_on只能保证服务按顺序启动不能保证 Neo4j 已就绪所以第一次启动后要等一小会儿。3.2 启动与初始化管理员账号启动命令很简单docker compose pull docker compose up -d docker compose logs -f看到 Neo4j 日志出现“Remote interface available”并且 BloodHound 日志没有连接错误后访问http://服务器IP:8080。首次打开会要求创建一个管理员账号这个账号只存在 CE 应用里和 Neo4j 的 neo4j 用户不同。填好邮箱和密码后会进入主界面。如果页面提示数据库未初始化或连接失败优先检查日志里的 NEO4J_URI 是否写成localhost。容器内访问 Neo4j 应该用服务名neo4j而不是localhost这是新人最常见的问题。3.3 启动失败排查的一线经验我遇到比较多的启动失败有三类。第一类端口被占用Neo4j 的 7474 或 Web 的 8080 被别的进程占了启动后容器反复重启用docker ps能看到 Restarting 状态查docker compose logs定位。第二类密码里的特殊字符在 YAML 里没正确处理比如带!、$时会被解析出问题建议密码里只保留字母数字和常用符号或者用环境变量文件传递。第三类内存不足Neo4j 直接 OOM容器退出。这时候调小pagecache和heap同时给服务器加 swap。排查时按docker compose ps、logs、events三步走基本上都能定位。4. 数据采集端SharpHound 使用与数据导入4.1 SharpHound 采集命令参数解读BloodHound 本身不采集数据数据靠 SharpHound 在域内收集后上传。SharpHound 常用参数如下--CollectionMethod Default默认采集对象信息、ACL、会话速度快适合第一次摸底。--CollectionMethod All全量采集包括对象属性、域信任、容器等数据最全但慢。--Loop循环采集适合跟踪会话变化。--ZipPrefix输出文件前缀。--OutputDirectory输出目录。--Domain指定域跨域场景必用。--Stealth避免部分敏感操作降低被发现概率。实际使用中我通常先跑一次 Default看覆盖情况再针对目标跑 All。普通域用户权限就能采集大部分数据但如果 ACL 枚举不全需要看账号是否具备读取目标对象 ACL 的权限。4.2 全量采集与定向采集的取舍全量采集数据最完整但会产生大量会话和属性信息在大域里可能让 Neo4j 卡顿。定向采集适合已有明确目标比如只想知道“谁能登录某个服务器”用--CollectionMethod Session加--ComputerFile指定计算机列表就够了。另外一个取舍是速度默认采集在几千用户的域里一般几分钟到十几分钟全量可能几十分钟。我自己的做法是第一天跑全量做基线后续每天跑定向采集看会话变化避免把数据塞爆。4.3 数据导入 CE 的两种方式第一种是界面上传登录 CE 后点击右上角上传按钮把 SharpHound 生成的 zip 拖进去后台会自动解析。解析完成后主界面会出现对象和边统计。第二种是 API 上传适合脚本集成。大致请求结构如下curl -X POST \ -H Authorization: Bearer $TOKEN \ -H Content-Type: application/x-zip-compressed \ --data-binary results.zip \ http://server:8080/api/v1/file-upload具体接口路径以你部署版本为准。上传后执行一次“分析”操作相当于重建图数据才会在路径搜索里生效。不要传完就立刻搜等状态变成“分析完成”再操作否则结果不完整。5. 实战攻击路径分析从预置查询到 Cypher 查询5.1 用图搜索找最短路径CE 的搜索框就是路径分析入口。输入两个节点例如CORP\alice和CORP\DOMAIN ADMINS类型分别选用户和组然后点“Shortest Paths”它会展示所有能连通的最短路径。这个功能看起来简单实际很考验输入准确性。域名和账号名大小写不敏感但反斜杠不能写错如果搜索不到可以先分别搜两个节点确认节点存在再查路径。最短路径找到后再逐段看边的类型AdminTo、GenericAll、GenericWrite、ForceChangePassword这些明显是可控关系HasSession表示会话劫持可能每种边对应不同的利用或修复方式。5.2 预置查询的价值和盲区CE 内置了一组高频查询比如“域管组成员”、“拥有域管会话的机器”、“Kerberoastable 用户”、“可执行黄金票据的账户”等。这些查询是官方沉淀的最佳实践但不要照单全收。以 Kerberoastable 用户为例查询会把所有注册了 SPN 的普通用户列为潜在风险可实际上很多服务账号本来就要注册 SPN不能一刀切。预置查询更准确的价值是“定位异常”比如某个普通员工账号注册了 SPN或者某个高权限组在一个非管理服务器上有会话这类问题靠手工翻很难发现。5.3 手写 Cypher 找准核心风险一个完整案例预置查询不够时就得写 Cypher。这里举一个我实际用过的案例找出所有对“域管组”有GenericAll或GenericWrite权限的主体。这样就能定位“谁可以直接改域管组成员”连间接路径都绕过去。MATCH p(n)-[r:GenericAll|GenericWrite]-(g:Group) WHERE g.name ~ (?i).*DOMAIN ADMINS.* RETURN n.name AS principal, r.typename AS right, g.name AS group如果结果很少再扩大范围把WriteDacl、WriteOwner加进去。另一个常用查询是找拥有HasSession关系的域管账号MATCH (c:Computer)-[:HasSession]-(u:User) WHERE u.name ~ (?i).*ADMIN.* RETURN c.name AS computer, u.name AS user这个结果直接指向“哪些机器上能看到域管会话”是横向移动的高价值入口。写 Cypher 的关键是别把条件写太宽否则结果几万条没法看。先用小范围试确认语法没问题再放开条件。5.4 如何把分析结果翻译成修复建议路径图只是中间产物最终要变成可落地的修复项。我的习惯是给每条路径标上“脆弱点”而不是只标“终点”。比如一条路径里有个普通用户对某服务器拥有AdminTo随后该服务器上有域管会话修复优先顺序是先移除不必要的本地管理员权限再限制域管在该服务器上登录最后再说改密码。边类型决定修复方式ACL 类边要从 ADUC 或 PowerShell 中清理权限HasSession边要关掉不必要的交互登录MemberOf边要梳理组嵌套。每次分析结束我建议把结果导出成 CSV内部留存时按对象和边类型打标签方便下一次对比。6. 避坑指南BloodHound CE 实战中的七个高频问题6.1 容器健康检查通过但页面打不开这个问题我遇到过好几次。容器状态正常日志也干净但浏览器就是访问不了。第一步先在内网另一台机器上curl一下 Web 端口如果通说明是浏览器或代理问题。如果不通检查防火墙和安全组尤其云服务器。另外如果部署在 Docker 的 bridge 网络里映射了127.0.0.1:8080:8080外部自然访问不到需要改成0.0.0.0:8080:8080或具体网段。这是第一个要排查的。6.2 Neo4j 数据膨胀和数据清理BloodHound 导入的数据尤其是 Loop 模式重复采集会让 Neo4j 数据文件快速膨胀。我见过一个 1000 用户的测试域数据卷涨到 20G。清理思路有两种简单粗暴是删除卷重建测试环境推荐保留现场则先登录 Neo4j 执行全删MATCH (n) DETACH DELETE n;然后重新导入一份干净数据。顺带提一句全删后 CE 的已存自定义查询还在因为它们存在应用配置卷里。定期重建数据卷是我控制存储的最好办法。6.3 SharpHound 与 CE 版本不匹配CE 的新版本会调整边的类型定义和属性结构老版本 SharpHound 导入后可能出现“unknown relationship type”或节点属性缺失。排查方法是看 CE 的版本日志和上传解析日志通常会提示哪个类型不识别。解决办法就是升级采集器或降低 CE 版本别无他法。部署时先记录版本号采集端和平台端保持一致能省掉大量重复采集。6.4 中文域名的乱码问题国内不少环境有中文组织单位或中文用户显示名。SharpHound 采集时 JSON 默认是 UTF-8一般不会乱码但如果你用旧版脚本二次转换就容易变成乱码。碰到乱码时不要慌先在采集端直接打开生成的 json 看原始编码如果不是 UTF-8重新用最新版 SharpHound 导出。界面里查询中文名称时正则最好带上(?i)避免大小写不匹配。这不算大坑但能让你少白屏几次。6.5 图形搜索条件写错导致白屏CE 的搜索框和 Cypher 查询对格式都很敏感。比如路径搜索里输入corp\alice反斜杠在后续 JSON 传输中容易出问题可能白屏解决办法是先在浏览器控制台看报错再用域\用户名的完整名字重试。另一个常见错误是在搜索框里写了namealice这样的过滤条件CE 搜索框不是完整查询输入框它有自己的语法。查询超时也可能表现成白屏这时候去调 Neo4j 内存参数而不是反复刷新。6.6 重复采集导致关系重复Loop 模式会产生时间戳不同的重复数据CE 默认按最新数据聚合但有时候界面仍显示多条相同边。分析时先用latest时间过滤或者采集时每次换输出目录避免新旧数据混在一起。如果已经乱了最简单的处理是清空 Neo4j 再导一次数据量不大时比写复杂 Cypher 去重更高效。还有个小技巧采集完马上把 zip 文件名加上日期这样后面导入时能快速区分新旧批次不会两眼一抹黑。6.7 备份恢复与容器迁移容器迁移的核心是保住 Neo4j 数据卷和 CE 配置卷。我的备份做法是先docker compose stop再用 tar 打包两个卷目录恢复时确保目录属主一致。如果图数据特别大可以在 Neo4j 容器里用neo4j-admin dump导到文件再在新环境 load。比起迁移整个服务器这种做法要稳得多。还有个小建议自定义查询脚本放在单独目录别只存在 CE 配置卷里否则容器重置会全部丢失。7. 从工具到流程一套可持续的 AD 攻击面评估习惯7.1 固定版本和基线化管理我现在部署任何依赖数据层的工具都先定版本。BloodHound CE 和 Neo4j 的版本组合我会写进部署文档连同 SharpHound 版本号一起记录。每次评估开始前先导出一份“当前边类型和节点数量”的基线评估结束后对比基线能明显看出风险变化。版本升级前在测试环境跑一次完整采集和路径分析再决定是否更新生产环境。这个习惯帮我过避免很多次半夜升级翻车的情况。7.2 把查询沉淀成团队知识库实战中总结出的 Cypher 查询不要放在个人笔记里我建议整理成一个公开风格的内部 Cheatsheet。比如“哪些主体可以对特权组写 ACL”、“哪些机器有高危会话”、“哪些用户注册了异常 SPN”这三个大类每个大类配上固定查询模板和修复说明。下次再评估时直接复用模板只改域名和对象名效率能翻倍。低级错误也会少很多。7.3 最后一次提醒数据安全和你自己的边界BloodHound 分析的是 AD 权限关系本质是敏感数据。整个部署环境应该建在受控网络里访问账号按需分配评估结束及时清理。我见过有人把分析平台长期放在一个“看起来没人用”的内网服务器上最后数据被无关人员翻到非常被动。工具本身没有立场但使用者要有边界。建议每次项目结束后用脚本自动删除旧数据卷保留结果报告即可平台保持最小化运行。这就是我对 BloodHound CE 最想补充的经验。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑