
Коллектор OpenGraph для BloodHound для GitHub, который отображает организационную структуру, разрешения и межоблачные пути атак в навигационный граф для аудита безопасности и реагирования на инциденты.

GitHound — это сборщик OpenGraph для BloodHound, предназначенный для GitHub. Он позволяет отобразить структуру и права доступа вашей организации в виде навигационного графа путей атак. Инструмент:
Моделирует ключевые сущности GitHub
Визуализация и анализ в BloodHound
С GitHound вы получаете чёткий, интерактивный граф ландшафта разрешений GitHub — идеально подходит для проверок безопасности, аудитов соответствия и быстрого расследования инцидентов.
Подробную документацию см. в BloodHound Docs - GitHound.
# 1. Загрузите сборщик
. ./githound.ps1
# 2. Создайте сессию с Personal Access Token
$session = New-GitHubSession -OrganizationName "YourOrgName" -Token (Get-Clipboard)
# 3. Запустите сбор
Invoke-GitHound -Session $session
# 4. Загрузите полученный файл githound_<orgId>.json в BloodHound
Если сбор был прерван, возобновите с того же места:
Invoke-GitHound -Session $session -Resume
GitHound поддерживает как сессии с Personal Access Token, так и сессии установки GitHub App. Существующий рабочий процесс для GitHub App с областью действия организации не изменился:
. ./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: заголовки JWT GitHub App, используемые для конечных точек на уровне приложения, таких как перечисление установокPatHeaders: необязательные заголовки Personal Access Token для путей сбора, требующих аутентификации пользовательским токеномДля перечисления установок, принадлежащих аутентифицированному GitHub App:
Get-GitHubAppInstallation -Session $session |
Select-Object TargetType, InstallationId, Login, Name, SuspendedAt
Разбор рабочих процессов теперь встроен в Invoke-GitHound при использовании -CollectAll. Сборщик будет:
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 от предприятия к этим пользователямСбор SAML предприятия через Git-HoundEnterpriseSamlProvider добавляет:
GH_SamlIdentityProviderGH_ExternalIdentityGH_HasSamlIdentityProvider от предприятия к провайдеруЭтот путь требует сессии на основе PAT, потому что GitHub предоставляет SAML предприятия через enterprise.ownerInfo.
Сбор команд предприятия через Git-HoundEnterpriseTeam добавляет:
GH_EnterpriseTeamGH_AssignedTo от команд предприятия к назначенным организациямGH_MemberOf от команд предприятия к видимым в организации узлам GH_Team с префиксом ent: с использованием сопоставления свойствmembers команд предприятия и рёбра GH_HasRole от пользователей к этим ролямСбор ролей предприятия через Git-HoundEnterpriseRole добавляет:
GH_EnterpriseRoleGH_Contains от предприятия к этим ролямGH_HasRole от непосредственно назначенных пользователей и команд предприятияowners по умолчанию, заполняемая из enterprise.ownerInfo.admins, если доступны данные администраторов предприятия на основе PATНа данный момент необработанные строки разрешений предприятия сохраняются в узле GH_EnterpriseRole в его свойстве permissions, а не разворачиваются в отдельные рёбра разрешений.
Сбор SCIM предприятия в настоящее время добавляет:
SCIM_UserSCIM_GroupSCIM_Provisioned от SCIM_User к GH_ExternalIdentitySCIM_Provisioned от SCIM_Group к GH_EnterpriseTeam, когда GitHub предоставляет group_id команды предприятияSCIM_MemberOf от SCIM_User к SCIM_GroupЭто даёт GitHound не зависящий от провайдера мост от общей схемы SCIM к нативной модели идентификации и команд предприятия GitHub.
Когда собранный GH_SamlIdentityProvider идентифицирует вышестоящий IdP, GitHound также может добавить рёбра корреляции SCIM с учётом провайдера в побочный вывод SCIM:
Okta_User -> SCIM_User
Okta_User.id = SCIM_User.externalIdOkta_Group -> SCIM_Group
Okta_Group.name = SCIM_Group.externalIdOkta_Group.oktaDomain = GH_SamlIdentityProvider.foreign_environmentidGitHound сохраняет уровень SCIM в отдельном побочном выводе, чтобы эти сопоставления оставались видимыми без смешивания нативных узлов SCIM с основным графом предприятия GitHub:
githound_<entId>.json содержит нативные данные предприятия GitHubgithound_scim_<entId>.json содержит нативные узлы SCIM и мостовые рёбра SCIMgithound_saml_<entId>.json содержит данные SAML и внешних идентификаторовgithound_hybrid_<entId>.json содержит межмодельные рёбра, такие как SAML_Implements, SAML_HasAccount и GH_SyncedTogithound_saml_<entId>.json также содержит нормализованную топологию SAML для поставщика услуг GitHub, включая SAML_TrustsIssuer и SAML_HasAssertionConsumerServiceНативная модель поставщика идентификации GitHub остаётся нетронутой в выводах GitHub/SAML:
GH_ExternalIdentityGH_HasExternalIdentityGH_MapsToUserНормализованный уровень SAML в githound_hybrid_<entId>.json теперь помещает SAML_HasAccount непосредственно на GH_User, при этом match_values выводятся из связанных свойств GH_ExternalIdentity, ориентированных на SAML, таких как saml_identity_name_id и saml_identity_username.
Заглушки 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> в следующем запросе на идентификатор объекта пользователя:
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_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

Найдите сущности GitHub, которые могут принять федеративные удостоверения Azure (отношения доверия OIDC):
// Все пути атак GitHub → Azure OIDC
MATCH p = (:GH_Repository|GH_Branch|GH_Environment)-[:GH_CanAssumeIdentity]->(:AZFederatedIdentityCredential)
RETURN p
// Пользователи с путями к Azure через GitHub Actions
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
Мы приветствуем и ценим ваш вклад! Чтобы сделать процесс гладким и эффективным, пожалуйста, следуйте этим шагам:
Обсудите вашу идею
Сделайте форк и создайте ветку
Сделайте форк этого репозитория в свой аккаунт.
Создайте тематическую ветку для вашей работы:
git checkout -b feat/my-new-feature
Реализуйте и протестируйте
Следуйте существующему стилю и шаблонам в репозитории.
Добавьте или обновите тесты/примеры для ваших изменений.
Убедитесь, что ваш код работает как ожидается:
# например, выполните dot-source сборщика и запустите его, или загрузите model.json в BloodHound
Отправьте Pull Request
Отправьте вашу ветку в ваш форк:
git push origin feat/my-new-feature
Откройте Pull Request против ветки main этого репозитория.
В описании 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.
Если не указано иное в файле лицензии более низкого уровня или заголовке лицензии, все файлы в этом репозитории выпущены под лицензией 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 |