
GitHound 是一款面向 GitHub 的 BloodHound OpenGraph 收集器,旨在将你组织的结构与权限映射为可导航的攻击路径图。它能够:
对关键 GitHub 实体建模
在 BloodHound 中可视化与分析
借助 GitHound,你能获得一份清晰、可交互的 GitHub 权限图谱,非常适合安全审查、合规审计以及快速的事件调查。
详细文档请参阅 BloodHound Docs - GitHound。
# 1. 加载收集器
. ./githound.ps1
# 2. 使用个人访问令牌创建会话
$session = New-GitHubSession -OrganizationName "YourOrgName" -Token (Get-Clipboard)
# 3. 运行收集
Invoke-GitHound -Session $session
# 4. 将生成的 githound_<orgId>.json 文件上传到 BloodHound
如果收集被中断,可以从断点处继续:
Invoke-GitHound -Session $session -Resume
GitHound 同时支持个人访问令牌会话和 GitHub 应用安装会话。 原有的组织范围 GitHub 应用工作流保持不变:
. ./githound.ps1
$session = New-GitHubJwtSession `
-OrganizationName "YourOrgName" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $installationId
Invoke-GitHound -Session $session -CollectAll
同一函数也可创建企业级会话:
. ./githound.ps1
$session = New-GitHubJwtSession `
-EnterpriseName "YourEnterpriseSlug" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $installationId `
-PersonalAccessToken $pat
企业级会话会在返回的 GitHound.Session 上保留多个认证上下文:
Headers:用于常规收集的 GitHub App 安装令牌头JwtHeaders:用于应用级端点(如安装枚举)的 GitHub App JWT 头PatHeaders:可选的个人访问令牌头,用于需要用户令牌认证的收集路径枚举属于认证 GitHub App 的安装项:
Get-GitHubAppInstallation -Session $session |
Select-Object TargetType, InstallationId, Login, Name, SuspendedAt
当使用 -CollectAll 时,工作流解析现已内置于 Invoke-GitHound 中。收集器将:
GH_Workflow 节点及工作流内容GH_WorkflowJob 和 GH_WorkflowStepGH_CanPwnRequest 和 GH_CanDispatchTogithound_<orgId>.json 输出中为断点续传/调试目的,中间的工作流分析检查点会被写入为 githound_WorkflowAnalysis_<orgId>.json。
GitHound 现在通过 Git-HoundEnterprise 提供了一个最简化的企业收集基础。该收集器当前会创建:
GH_EnterpriseGH_Organization 存根节点GH_Contains 边通过 Git-HoundEnterpriseUser 进行的企业用户收集会添加:
GH_UserGH_HasMember 边通过 Git-HoundEnterpriseSamlProvider 进行的企业 SAML 收集会添加:
GH_SamlIdentityProviderGH_ExternalIdentityGH_HasSamlIdentityProvider 边此路径需要基于 PAT 的会话,因为 GitHub 通过 enterprise.ownerInfo 暴露企业 SAML。
通过 Git-HoundEnterpriseTeam 进行的企业团队收集会添加:
GH_EnterpriseTeamGH_AssignedTo 边ent: 前缀 GH_Team 节点(通过属性匹配)的 GH_MemberOf 边members 角色以及从用户到这些角色的 GH_HasRole 边通过 Git-HoundEnterpriseRole 进行的企业角色收集会添加:
GH_EnterpriseRoleGH_Contains 边GH_HasRole 边enterprise.ownerInfo.admins 填充的默认 owners 角色目前,原始的企业权限字符串会保留在 GH_EnterpriseRole 节点的 permissions 属性中,而不会展开为专用的权限边。
企业 SCIM 收集当前会添加:
SCIM_UserSCIM_GroupSCIM_User 到 GH_ExternalIdentity 的 SCIM_Provisioned 边group_id 时,从 SCIM_Group 到 GH_EnterpriseTeam 的 SCIM_Provisioned 边SCIM_User 到 SCIM_Group 的 SCIM_MemberOf 边这为 GitHound 提供了从共享 SCIM 模式到 GitHub 原生企业身份与团队模型的、与提供商无关的桥接。
当收集到的 GH_SamlIdentityProvider 标识了上游 IdP 时,GitHound 还可以在 SCIM 侧车输出中添加提供商感知的 SCIM 关联边:
Okta_User -> SCIM_User(通过 Okta_User.id = SCIM_User.externalId 匹配)Okta_Group -> SCIM_Group(通过 Okta_Group.name = SCIM_Group.externalId 及 Okta_Group.oktaDomain = GH_SamlIdentityProvider.foreign_environmentid 匹配)GitHound 将 SCIM 层保留在其独立的侧车输出中,以便这些映射保持可见,而不会将 SCIM 原生节点混入主 GitHub 原生企业图:
githound_<entId>.json 包含企业级 GitHub 原生数据githound_scim_<entId>.json 包含 SCIM 原生节点和 SCIM 桥接边githound_saml_<entId>.json 包含 SAML 和外部身份数据githound_hybrid_<entId>.json 包含跨模型边,如 SAML_Implements、SAML_HasAccount 和 GH_SyncedTogithound_saml_<entId>.json 还包含针对 GitHub 服务提供者规范化的 SAML 拓扑,包括 SAML_TrustsIssuer 和 SAML_HasAssertionConsumerService原生 GitHub 身份提供商模型保留在 GitHub/SAML 原生输出中:
GH_ExternalIdentityGH_HasExternalIdentityGH_MapsToUser在 githound_hybrid_<entId>.json 中规范化的 SAML 层现在直接将 SAML_HasAccount 落在 GH_User 上,同时从关联的 GH_ExternalIdentity 的 SAML 属性(如 saml_identity_name_id 和 saml_identity_username)派生 match_values。
企业收集发出的 GH_Organization 存根被有意标记为 collected = false。它们代表从企业上下文中进行的结构性发现,计划后续通过常规组织收集进行丰富。
对于企业优先的编排,Invoke-GitHoundEnterprise 将收集支持的企业范围数据,枚举相关的组织安装项,然后对每个组织在选定检查点路径下的各自子目录中运行现有的 Invoke-GitHound 工作流。
示例:
$session = New-GitHubJwtSession `
-EnterpriseName "your-enterprise-slug" `
-ClientId $clientId `
-PrivateKeyPath $privateKeyPath `
-InstallationId $enterpriseInstallationId `
-PersonalAccessToken $pat
Invoke-GitHoundEnterprise -Session $session -CheckpointPath "./output/your-enterprise" -CollectAll
仅用于企业测试而不枚举关联组织:
Invoke-GitHoundEnterprise -Session $session -CheckpointPath "./output/your-enterprise" -EnterpriseOnly

详细文档请参阅 BloodHound Docs - GitHound Schema。
关键边类别:
主要攻击路径模式:
(:GH_User)-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_AdminTo|GH_CanPush]->(:GH_Repository)
找到目标用户的对象标识符:
MATCH (n:GH_User)
RETURN n
提示:选择表格布局
https://github.com/user-attachments/assets/1ddfd075-2a15-4aa9-bad7-74c43e6c82d6
将后续查询中的 <object_id> 值替换为用户的 object identifier:
MATCH p = (:GH_User {objectid:"<object_id>"})-[:GH_MemberOf|GH_AddMember|GH_HasRole|GH_HasBaseRole|GH_Owns*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository)
RETURN p

获取目标仓库的对象标识符:
MATCH (n:GH_Repository)
RETURN n
获取目标仓库的 object identifier 后,将后续查询中的 <object_id> 值替换为它:
MATCH p = (:GH_User)-[:GH_MemberOf|GH_HasRole|GH_HasBaseRole|GH_Owns|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_WriteRepoContents]->(:GH_Repository {objectid:"<object_id>"})
RETURN p

MATCH p = (:GH_User)-[:GH_HasRole|GH_HasBaseRole]->(:GH_OrgRole {short_name: "owners"})
RETURN p

MATCH p = (:AZUser)-[:GH_SyncedTo]->(:GH_User)
RETURN p

查找可以假定 Azure 联合身份(OIDC 信任关系)的 GitHub 实体:
// 所有 GitHub → Azure OIDC 攻击路径
MATCH p = (:GH_Repository|GH_Branch|GH_Environment)-[:GH_CanAssumeIdentity]->(:AZFederatedIdentityCredential)
RETURN p
// 通过 GitHub Actions 拥有通向 Azure 路径的用户
MATCH p = (:GH_User)-[:GH_HasRole|GH_MemberOf|GH_AddMember*1..]->(:GH_RepoRole)-[:GH_CanPush]->(:GH_Repository)-[:GH_CanAssumeIdentity]->(:AZFederatedIdentityCredential)
RETURN p
MATCH p = (:GH_Repository)-[:GH_HasSecret]->(:GH_OrgSecret)
RETURN p
MATCH p = (:GH_Repository)-[:GH_Contains]->(:GH_SecretScanningAlert)
RETURN p
我们欢迎并感谢你的贡献!为使过程顺利高效,请遵循以下步骤:
讨论您的想法
Fork 并创建分支
将本仓库 Fork 到您自己的账户。
为您的改动创建一个主题分支:
git checkout -b feat/my-new-feature
实现与测试
遵循仓库中现有的风格和模式。
添加或更新任何测试/示例以覆盖您的改动。
验证您的代码按预期运行:
# 例如 dot-source 收集器并运行,或在 BloodHound 中加载 model.json
提交 Pull Request
将您的分支推送到您的 Fork:
git push origin feat/my-new-feature
向本仓库的 main 分支提交 Pull Request。
在 PR 描述中,请包含:
审核与合并
感谢您帮助改进此扩展!🎉
Copyright 2025 Jared Atkinson
Licensed under the Apache License, Version 2.0
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
除非更低级别的 LICENSE 文件或许可证头另有说明,本仓库中的所有文件均按 Apache-2.0 许可证发布。许可证的完整副本可在顶层的 LICENSE 文件中找到。
| 类别 | 关键边 | 描述 |
|---|
| 包含关系 | GH_Contains, GH_Owns | 组织层级结构 |
| 角色分配 | GH_HasRole, GH_MemberOf, GH_HasBaseRole | 谁拥有哪些角色 |
| 仓库权限 | GH_AdminTo, GH_CanPush, GH_CanPull | 角色可执行的操 |
| 分支保护 | GH_BypassPullRequestAllowances, GH_RestrictionsCanPush | 分支级别访问控制 |
| 密钥 | GH_HasSecret | 密钥访问映射 |
| 跨云 | GH_CanAssumeIdentity, GH_SyncedTo | 通向 Azure/AWS 的攻击路径 |