
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_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 的攻击路径 |
主要攻击路径模式:
(: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
