toneillcodes/HoundTrainer
GitHub: toneillcodes/HoundTrainer
BloodHound 自定义节点类型与 Cypher 查询的批量管理工具,支持从 CSV 创建模型并上传至 BloodHound 实例。
Stars: 12 | Forks: 1
# 概述
HoundTrainer 是一个用于在 BloodHound 中管理自定义节点类型和 Cypher 查询的工具。
## 快速开始与前置条件
HoundTrainer 需要 Python 3.x。
Pandas 对于模型创建是可选的,如果导入不可用,脚本将回退到标准库进行 CSV 解析。
1. 克隆仓库
```
$ git clone https://github.com/toneillcodes/HoundTrainer.git
$ cd HoundTrainer
```
2. 安装依赖
```
$ pip install -r requirements.txt
```
## 用法
```
$ python houndtrainer.py -h
usage: houndtrainer.py [-h] {create,get,list,upload,export,delete,deleteall} ...
Manage custom types and cypher queries in BloodHound.
positional arguments:
{create,get,list,upload,export,delete,deleteall}
create Create a schema model from CSV definitions.
get Retrieve a specific resource
list List custom node or cypher resources
upload Upload custom node or cypher resources
export Export custom node or cypher resources
delete Delete a custom node or cypher resource
deleteall Delete all custom node or cypher resources
options:
-h, --help show this help message and exit
$
```
## 操作
* [create](#create-operation)
* [list](#list-operation)
* [get](#get-operation)
* [upload](#upload-operation)
* [export](#export-operation)
* [delete](#delete-operation)
* [deleteall](#deleteall-operation)
注意:对于 Cypher 操作,当未提供 ```--scope``` 参数时,使用的默认 scope 是 'owned'。
### Create(创建)操作
#### 创建自定义节点类型模型
根据 CSV 定义创建模型
```
Kind Name,Icon Name,Color
ExampleUser,user,#4D93D9
ExampleRole,user-group,#47D359
```
解析 CSV(--csv)并生成 JSON(--file)
```
$ python houndtrainer.py create --type model --csv examples\example-model.csv --file examples\example-model.json
Success: Data written to examples\example-model.json
[INFO] Successfully wrote model from 'examples\example-model.csv' to file 'examples\example-model.json'.
[INFO] Done.
$
```
参考:
* [examples/example-model.csv](examples/example-model.csv)
* [examples/example-model.json](examples/example-model.json)
### List(列出)操作
#### 列出自定义节点类型
列出自定义节点类型
```
$ python houndtrainer.py list --type node --url http://127.0.0.1:8080
[INFO] Listing all custom types...
Enter JWT:
[INFO] ID: 280, Kind Name: ExampleUser
[INFO] ID: 281, Kind Name: ExampleRole
[INFO] Done.
$
```
未找到自定义节点类型时的列出输出
```
$ python houndtrainer.py list --type node --url http://127.0.0.1:8080
[INFO] Listing all custom types...
Enter JWT:
[INFO] No custom kinds found.
[INFO] Done.
$
```
#### 列出 Cypher 查询
包含 Cypher 查询的列出输出
```
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
[INFO] Listing all cypher queries under scope: 'owned'...
Enter JWT:
[INFO] ID: 14, Query: Test Query
[INFO] Done.
```
未找到 Cypher 查询时的列出输出
```
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
[INFO] Listing all cypher queries under scope: 'owned'...
Enter JWT:
[INFO] No cypher queries found.
[INFO] Done.
$
```
### Get(获取)操作
#### 获取自定义节点类型
通过 kind 名称(--name)检索自定义节点类型详情
```
$ python houndtrainer.py get --type node --url http://127.0.0.1:8080 --name ExampleUser
[INFO] Listing custom type for kind_name 'ExampleUser'...
Enter JWT:
[INFO] ID: 280, Name: ExampleUser, type: font-awesome, Name: user, Color: #4D93D9
[INFO] Done.
$
```
#### 获取 Cypher 查询
通过 ID(--id)检索 Cypher 查询详情
```
$ python houndtrainer.py get --type cypher --url http://127.0.0.1:8080 --id 14
[INFO] Retrieving cypher query for ID: '14'...
Enter JWT:
[INFO] ID: 14, Name: Test Query, Created_At: 2025-11-29T15:05:37.546016Z, Updated_At: 2025-11-29T18:02:40.993889Z, User_id: 0f916532-08f7-47f4-bf1b-37b2317cce1b, Description: Testing, Query: "match(a:ExampleUser)\nwhere a.objectid = 'Bob'\nreturn a"
[INFO] Done.
$
```
### Upload(上传)操作
#### 上传自定义节点类型模型
上传 example-model.json
```
$ python houndtrainer.py upload --type node --url http://127.0.0.1:8080 --file examples\example-model.json
[INFO] Uploading model from file: examples\example-model.json...
Enter JWT:
[INFO] Model uploaded successfully.
[INFO] Operation 'upload' for type 'node' with file examples\example-model.json was successful.
[INFO] Done.
$
```
确认上传成功
```
$ python houndtrainer.py list --type node --url http://127.0.0.1:8080
[INFO] Listing all custom types...
Enter JWT:
[INFO] ID: 282, Kind Name: ExampleUser
[INFO] ID: 283, Kind Name: ExampleRole
[INFO] Done.
$
```
参考:
* [examples/example-model.json](examples/example-model.json)
#### 上传单个 Cypher 查询
检查 Cypher 查询列表
```
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
[INFO] Listing all cypher queries under scope: 'owned'...
Enter JWT:
[INFO] No cypher queries found.
[INFO] Done.
```
上传示例 Cypher 查询文件 ```examples\example-cypher.json```
```
$ python houndtrainer.py upload --type cypher --url http://127.0.0.1:8080 --file examples\example-cypher.json
[INFO] Uploading query JSON from file: examples\example-cypher.json...
Enter JWT:
[INFO] Cypher query uploaded successfully.
[INFO] Operation 'upload' for type 'cypher' with file examples\example-cypher.json was successful.
[INFO] Done.
```
检查 Cypher 查询列表
```
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
[INFO] Listing all cypher queries under scope: 'owned'...
Enter JWT:
[INFO] ID: 17, Query: Test
[INFO] Done.
$
```
参考:
* [examples/example-cypher.json](examples/example-cypher.json)
#### 上传 Cypher 查询包(ZIP)
上传 Cypher 查询包
```
$ python houndtrainer.py upload --type cypher --url http://127.0.0.1:8080 --file examples\example-cypher-pack.zip
[INFO] Uploading query zip from archive: examples\example-cypher-pack.zip...
Enter JWT:
[INFO] Query ZIP uploaded successfully.
[INFO] Operation 'upload' for type 'cypher' with file examples\example-cypher-pack.zip was successful.
[INFO] Done.
$
```
检查 Cypher 查询列表
```
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
[INFO] Listing all cypher queries under scope: 'owned'...
Enter JWT:
[INFO] ID: 22, Query: Test
[INFO] ID: 23, Query: Another Test
[INFO] ID: 24, Query: Find Helpdesk Admins
[INFO] ID: 25, Query: Find DA Users
[INFO] Done.
$
```
### Export(导出)操作
#### 导出自定义节点类型
通过 kind 名称(--name)导出自定义节点类型
```
$ python houndtrainer.py export --type node --url http://127.0.0.1:8080 --name ExampleRole --file examples\example-custom-type.json
[INFO] Listing custom type for kind_name 'ExampleRole'...
Enter JWT:
Success: Data written to examples\example-custom-type.json
[INFO] Successfully wrote 'node' data to file 'examples\example-custom-type.json'.
[INFO] Done.
$
```
参考:
* [examples/example-custom-type.json](examples/example-custom-type.json)
#### 导出所有自定义节点类型
将所有自定义节点类型导出到一个 JSON 文件中
```
$ python houndtrainer.py export --type node --url http://127.0.0.1:8080 --all --file examples\example-custom-types.json
[INFO] Exporting all custom types...
[INFO] Listing all custom types...
Enter JWT:
[INFO] kindName found: ExampleUser.
[INFO] kindName found: ExampleRole.
[INFO] Successfully exported 'node' data to file 'examples\example-custom-types.json'.
[INFO] Done.
$
```
参考:
* [examples/example-custom-type.json](examples/example-custom-type.json)
#### 导出 Cypher 查询
通过 ID(--id)导出 Cypher 查询
```
$ python houndtrainer.py export --type cypher --url http://127.0.0.1:8080 --id 16 --file examples\example-cypher.json
[INFO] Exporting cypher query ID '16'...
Enter JWT:
Success: Data written to examples\example-cypher.json
[INFO] Successfully wrote 'cypher' data to file 'examples\example-cypher.json'.
[INFO] Done.
$
```
参考:
* [examples/example-cypher.json](examples/example-cypher.json)
#### 导出所有 Cypher 查询
将所有 Cypher 查询导出为 ZIP(--file)
```
$ python houndtrainer.py export --type cypher --url http://127.0.0.1:8080 --all --file examples\example-cypher-pack.zip
[INFO] Exporting cypher queries for scope 'owned'...
Enter JWT:
[INFO] Saving cypher archive as: 'examples\example-cypher-pack.zip'
[INFO] Successfully exported 'cypher' data to file 'examples\example-cypher-pack.zip'.
[INFO] Done.
$
```
### Delete(删除)操作
#### 通过 kind 名称删除自定义节点类型
通过 kind 名称(--name)删除自定义节点类型
```
$ python houndtrainer.py delete --type node --url http://127.0.0.1:8080 --name ExampleUser
[INFO] Deleting custom type: ExampleUser
Enter JWT:
[INFO] Deleted custom type: ExampleUser
[INFO] Successfully completed delete for node.
[INFO] Done.
$
```
确认删除
```
$ python houndtrainer.py list --type node --url http://127.0.0.1:8080
[INFO] Listing all custom types...
Enter JWT:
[INFO] ID: 283, Kind Name: ExampleRole
[INFO] Done.
$
```
#### 通过 ID 删除 Cypher 查询
通过 ID(--id)删除 Cypher 查询
```
$ python houndtrainer.py delete --type cypher --url http://127.0.0.1:8080 --id 14
[INFO] Deleting cypher query ID: '14'
Enter JWT:
[INFO] Deleted custom type: 14
[INFO] Successfully completed operation 'delete' for cypher.
[INFO] Done.
$
```
确认删除
```
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
[INFO] Listing all cypher queries under scope: 'owned'...
Enter JWT:
[INFO] No cypher queries found.
[INFO] Done.
$
```
### Deleteall(删除所有)操作
#### 删除所有自定义节点类型
删除所有自定义类型
```
$ python houndtrainer.py list --type node --url http://127.0.0.1:8080
[INFO] Listing all custom types...
Enter JWT:
[INFO] ID: 280, Kind Name: ExampleUser
[INFO] ID: 281, Kind Name: ExampleRole
[INFO] Done.
$
$ python houndtrainer.py deleteall --type node --url http://127.0.0.1:8080
[INFO] Running operation 'deleteall' for type 'node'.
Enter JWT:
[INFO] Operation deleteall requires confirmation.
Enter 'Y' to continue and 'N' to cancel: Y
[INFO] Deleting all custom types...
[INFO] Listing all custom types...
[INFO] Deleting custom type: ExampleUser
[INFO] Deleted custom type: ExampleUser
[INFO] Deleting custom type: ExampleRole
[INFO] Deleted custom type: ExampleRole
[INFO] Successfully completed operation 'deleteall' for type 'node'.
$
$ python houndtrainer.py list --type node --url http://127.0.0.1:8080
[INFO] Listing all custom types...
Enter JWT:
[INFO] No custom kinds found.
[INFO] Done.
$
```
#### 删除所有 Cypher 查询
```
$ python houndtrainer.py deleteall --type cypher --url http://127.0.0.1:8080
Enter JWT:
[INFO] Deleting all custom types...
[INFO] Listing custom types...
[INFO] Deleting custom type: ExampleUser
[INFO] Deleted custom type: ExampleUser
[INFO] Deleting custom type: ExampleSecurityUser
[INFO] Deleted custom type: ExampleSecurityUser
[INFO] Deleting custom type: ExampleGroup
[INFO] Deleted custom type: ExampleGroup
[INFO] Deleting custom type: ExampleClass
[INFO] Deleted custom type: ExampleClass
[INFO] Done.
$
$ python houndtrainer.py list --type cypher --url http://127.0.0.1:8080
Enter JWT:
[INFO] Listing custom types...
[INFO] No custom kinds found.
[INFO] Done.
$
```
## 认证
* 此脚本使用 JWT 进行认证,并期望在运行时提供该值。
* 要(合法地)获取 JWT,请登录您的 BHE 或 CE 实例,并在您选择的浏览器中查看“开发者工具”中的“网络”选项卡。
* 此方法符合 SpecterOps 对于快速 API 调用的建议
https://bloodhound.specterops.io/integrations/bloodhound-api/working-with-api#use-a-jwt%2Fbearer-token
## API 参考
所有操作使用以下端点
| 操作类型 | 端点 |
| ---- | ---- |
| node| custom-nodes |
| cypher | saved-queries |
## 待办事项
* ~~将所有自定义类型详情打印到 STDOUT~~ 已于 11/29/25 添加
* ~~将节点数据输出到文件~~ 已于 11/29/25 添加
* 支持使用 API 密钥进行认证
* 能够为 get/export 操作传递 ID 或 Kind Name 列表
* 验证操作以验证图标和 OG schemas
## 致谢
* [c0kernel](https://github.com/C0KERNEL):感谢其在测试、文档更新和建议方面的帮助。
标签:Azure AD, BloodHound, Cypher查询, HTTP/HTTPS抓包, Python, Web报告查看器, 二进制发布, 安全管理, 开源工具, 态势感知, 攻击路径规划, 无后门, 权限分析, 活动目录, 网络安全, 自定义节点, 隐私保护