KingOfTheNOPs/TailscaleHound

GitHub: KingOfTheNOPs/TailscaleHound

面向 Tailscale 网络的 BloodHound 数据收集器,将身份、设备和访问控制关系转化为可视化攻击路径图。

Stars: 43 | Forks: 2

# TailscaleHound TailscaleHound 是一个针对 Tailscale 的 BloodHound OpenGraph 收集器。它会收集 tailnet 用户、设备、组、标签、ACL、授权(grants)、SSH 规则、路由、app connector、服务、邀请、webhook 以及相关的控制平面元数据,然后生成一个与 BloodHound 兼容的 OpenGraph JSON 文件。 其目标是将 Tailscale 的访问关系以图表路径的形式直观呈现出来: ``` MATCH p=(u:TS_User)-[:TS_IsMemberOf]->(s)-[:TS_AclSource|TS_GrantSource]->(r)-[:TS_AclTargetsDevice|TS_GrantTargetsDevice]->(d:TS_Device) RETURN p ``` ## 特性 - 通过 Tailscale API 进行远程收集。 - 从 `tailscale status --json` 的输出中进行本地收集。 - 通过 `TS_AZUserSyncedToUser` 进行 Azure 混合攻击路径映射。 ## 当前覆盖范围 TailscaleHound 目前定义了 39 种节点类型和 64 种关系类型。 主要节点类型包括: | 领域 | 节点类型 | | --- | --- | | Tailnet | `TS_Network`, `TS_IDP`, `TS_ExternalTailnet` | | 身份标识 | `TS_User`, `TS_ExternalUser`, `TS_Group`, `TS_AutoGroup`, `TS_Tag`, `TS_ExternalTag`, `TS_Wildcard` | | 设备 | `TS_Device`, `TS_ExternalDevice`, `TS_Route`, `TS_Cidr`, `TS_HostAlias` | | 策略 | `TS_ACL`, `TS_Grant`, `TS_SSHRule`, `TS_ACLTest`, `TS_SSHTest`, `TS_PortSpec` | | 状态 | `TS_Posture`, `TS_DefaultSrcPosture`, `TS_NodeAttr`, `TS_Attr` | | Tailnet 对象 | `TS_APIKey`, `TS_AuthKey`, `TS_ClientKey`, `TS_FederatedKey`, `TS_UnknownKey`, `TS_Service`, `TS_AppConnector`, `TS_Webhook`, `TS_UserInvite`, `TS_DeviceInvite` | 主要关系类别包括: | 领域 | 关系示例 | | --- | --- | | 身份与角色 | `TS_IsMemberOf`, `TS_IsOwnerOf`, `TS_IsAdminOf`, `TS_IsNetworkAdminOf`, `TS_IsITAdminOf` | | 设备 | `TS_RegisteredDevice`, `TS_HasTag`, `TS_EnabledRoute`, `TS_IsExitNode` | | ACL 与授权 | `TS_AclSource`, `TS_AclTargetsDevice`, `TS_GrantSource`, `TS_GrantTargetsRoute`, `TS_RequiresPosture` | | SSH | `TS_SSHRuleSource`, `TS_SSHRuleTargetsDevice`, `TS_SSHRuleTargetsSelf`, `TS_SSHRuleAllowsUser` | | Funnel 与服务 | `TS_HasFunnelCapabilities`, `TS_HasFunnelEnabled`, `TS_HasService`, `TS_ServiceRunsOn`, `TS_ServiceHasTag` | | 混合身份标识 | `TS_AZUserSyncedToUser` | ## 安装 ``` git clone https://github.com/KingOfTheNOPs/TailscaleHound.git cd TailscaleHound python3 -m venv .venv source .venv/bin/activate pip3 install -r requirements.txt ``` 你可以通过根启动器运行该收集器: ``` python3 TailscaleHound.py --help ``` 或者在本地安装该包,以使用 `tailscalehound` 控制台入口点: ``` pip3 install -e . tailscalehound --help ``` ## 认证 ### Tailscale OAuth Client 同样支持使用 OAuth client 凭据: ``` python3 TailscaleHound.py \ --ts-client-id "$TAILSCALE_CLIENT_ID" \ --ts-oauth-secret "$TAILSCALE_OAUTH_SECRET" \ --output ./tailscalehound-output ``` 要生成 OAuth token,请以 Owner、Admin、IT Admin 或 Network Admin 的身份登录 [Tailscale](https://login.tailscale.com/)。依次前往 settings -> Trust Credentials -> + Credential... ![替代文本](https://static.pigsec.cn/wp-content/uploads/repos/cas/7d/7d264887b66d787cc03a8df5747b179a65959275b49a0251d8f59d6b39bc6d3e.png) 授予该密钥对所有资源的只读权限 ![替代文本](https://raw.githubusercontent.com/KingOfTheNOPs/TailscaleHound/main/Images/oauth-readonly.png) ### Tailscale API Key 当你希望远程收集器直接从 Tailscale API 拉取数据时,请使用 Tailscale API key: ``` python3 TailscaleHound.py \ --ts-api-key "$TAILSCALE_API_KEY" \ --output ./tailscalehound-output ``` 我不推荐使用此选项,但如果你需要 [Tailscale API Key](https://tailscale.com/docs/reference/tailscale-api),请以 Owner、Admin、IT Admin 或 Network Admin 的身份登录 [Tailscale](https://login.tailscale.com/)。依次前往 settings -> Keys -> Generate access tokens... ### 本地 Tailscale Status 本地收集从 Tailscale client 的状态 JSON 开始。这对于快速查看设备/会话状态非常有用。当无法使用 API 访问时,你也可以提供导出的 Tailscale Access Policy 文件,以添加与远程收集相同的 ACL、授权、SSH、组、标签、状态以及 app connector 图表扩充信息。 ``` tailscale status --json > tailscale-status.json python3 TailscaleHound.py \ --status-file tailscale-status.json \ --access-policy-file access-policy.json \ --output ./tailscalehound-output ``` ### 可选的 Admin-Panel 扩充 该收集器使用的公共 API 路径无法获取某些有用的字段。如果你提供了 `tailcontrol` cookie,TailscaleHound 将尝试使用 admin-panel 的机器、用户、密钥、身份提供者、计费和设置数据来扩充图表。 因此,我建议创建/授予一个具有 Auditor 角色的用户,以便在运行此工具时能够拥有对网络的完全可见性。要向用户授予此角色,请使用 Owner、Admin 或 IT Admin 账户登录并转到 [Users](https://login.tailscale.com/admin/users) 面板,点击用户旁边的 `...` 并选择 `Edit Role`。为他们授予 Auditor 角色,使其能够以只读方式访问管理控制台。 ![替代文本](https://raw.githubusercontent.com/KingOfTheNOPs/TailscaleHound/main/Images/auditor-role.png) 要获取 tailcontrol cookie,请打开浏览器并通过按 F-12 启动 DevTool 控制台中的“网络”(Network)标签页。登录 [Tailscale](https://login.tailscale.com) 并查找任何对 `/admin/api` endpoint 的网络调用,例如 `self`、`tailnets` 等。 ![替代文本](https://raw.githubusercontent.com/KingOfTheNOPs/TailscaleHound/main/Images/devtool-api-endpoints.png) 选择其中一个调用(例如 `machines`),并在 Headers 标签页下的 Cookie 部分获取你的 `tailcontrol` cookie。 ![替代文本](https://raw.githubusercontent.com/KingOfTheNOPs/TailscaleHound/main/Images/devtool-tailcontrol-cookie.png) 使用 tailcontrol cookie 和 OAuth 凭据来枚举 Tailscale 环境: ``` python3 TailscaleHound.py \ --ts-client-id "$TAILSCALE_CLIENT_ID" \ --ts-oauth-secret "$TAILSCALE_OAUTH_SECRET"\ --tailcontrol "$TAILCONTROL_COOKIE" \ --output ./tailscalehound-output ``` 请将此 cookie 视为凭据。它非常敏感,不应被提交到代码库、粘贴到日志中或与他人共享。 除了收集器使用的公共 API 响应之外,admin-panel 扩充目前还会添加或填充以下字段: | 领域 | 附加字段 | | --- | --- | | 用户 | `UserID`, `StableID`, `IsAdmin`, `IsOwner`, `OrgTailnetID`, `DomainName`, `SharedDomain`, `CanEditBilling`, `NeedsOnboarding`, `UseBusinessPricing`, `NoLongerProvisioned` | | 设备 | `StableID`, `FQDN`, `MachineName`, `OSVersion`, `ParsedOSVersion`, `IPNVersion`, `Creator`, `Domain`, `AvailableUpdateVersion`, `AutomaticNameMode`, `AutoUpdatesEnabled`, `CanNat`, `Endpoints`, `ExtraIPs`, `AllowedTags`, `InvalidTags`, `AdvertisedIPs`, `AcceptedShareCount`, `ShareID`, `HasExitNode`, `AdvertisedExitNode`, `AllowedExitNode`, `HasSubnets`, `SSHUsernames`, `OtherSSHUsernamesAllowed`, `FunnelEnabled`, `NeverExpires` | | 密钥 | `Creator`, `Invalid`, `AuthKey`, `ApiKey`, `OAuthClient`, OAuth `Scopes` | | Tailnet 设置 | 管理员设置(例如身份提供者元数据),以及 `StripeSubscription` 和 `StripeBillingUsage` | ## BloodHound 设置 ### 1. 上传 OpenGraph Schema 通过 OpenGraph Extension Management 将 `schema.json` 上传到 BloodHound,或者使用辅助脚本: ``` python3 helper-scripts/upload_schema.py \ --url https://bloodhound.example.com \ --username admin \ --secret "$BLOODHOUND_SECRET" ``` 该 schema 使用: - 命名空间:`TS` - Environment 类型:`TS_Network` - 常用查询入口:`MATCH (n:TS_User) RETURN n` ### 2. 上传自定义节点类型 可选的 `custom_types.json` 文件用于配置 TailscaleHound 节点类型的显示图标和颜色。 ``` python3 helper-scripts/upload_custom_icons.py \ --url https://bloodhound.example.com \ --username admin \ --secret "$BLOODHOUND_SECRET" ``` ### 3. 上传保存的查询 TailscaleHound 在 `SavedQueries/` 目录下提供了内置的保存查询。 ``` python3 helper-scripts/upload_saved_queries.py \ --url https://bloodhound.example.com \ --username admin \ --secret "$BLOODHOUND_SECRET" ``` ### 4. 上传收集器输出 收集器需要指定 `--output`,并在需要时创建该目录,将生成的文件写入其中。 远程收集输出: ``` /tailscalehound_remote_opengraph__output.json /tailscalehound_remote_acl__policy.json ``` 本地收集输出: ``` /tailscalehound_local_opengraph__output.json ``` 通过 BloodHound 文件导入功能上传生成的 OpenGraph JSON。 你也可以使用辅助脚本上传一个或多个生成的 JSON 文件: ``` python3 helper-scripts/upload_ingest_files.py \ --url https://bloodhound.example.com \ --username admin \ --secret "$BLOODHOUND_SECRET" \ ./tailscalehound-output/tailscalehound_local_opengraph__output.json ``` 该辅助程序会启动一个 BloodHound 文件上传任务,上传每个 JSON 文件,结束任务,然后打印任务状态,直到数据导入达到完成或失败的终止状态。使用 `--poll-interval` 和 `--poll-timeout` 可以调整等待时间。 ## 使用方法 ### 远程收集 ``` python3 TailscaleHound.py \ --ts-api-key "$TAILSCALE_API_KEY" \ --output ./tailscalehound-output \ --verbose ``` 远程收集会拉取用户、设备、路由、密钥、webhook、DNS 设置、日志设置、服务、邀请、联系人、tailnet 设置以及可用的 ACL 策略。 设备注册关系是根据 Tailscale 设备的 `user` 字段推导出来的。Tailscale 将该字段描述为注册该节点的用户;对于未打标签的节点,该用户即为设备所有者。TailscaleHound 将此建模为 `(:TS_User)-[:TS_RegisteredDevice]->(:TS_Device)`,而不是将其视为活动会话。 ### 本地收集 ``` tailscale status --json > tailscale-status.json python3 TailscaleHound.py \ --status-file tailscale-status.json \ --access-policy-file access-policy.json \ --output ./tailscalehound-output \ --verbose ``` 本地收集可以观察到从其他 tailnet 共享过来的设备。当用户仅通过外部设备出现时,TailscaleHound 会将该身份建模为 `TS_ExternalUser`,并通过 `(:TS_ExternalUser)-[:TS_RegisteredDevice]->(:TS_ExternalDevice)-[:TS_InExternalTailnet]->(:TS_ExternalTailnet)` 将其间接链接到外部 tailnet。在共享设备上观察到的标签通过 `TS_HasExternalTag` 被划定为 `TS_ExternalTag` 范围;它们不会与本地 `TS_Tag` 策略节点合并。本地状态输出中的合成 `tagged-devices` 身份不会被作为用户节点输出;被打标签的 tailnet 设备通过其 `TS_HasTag` 关系来表示。 ### 混合 Azure 映射 如果 BloodHound 中已经存在 Azure 和 TailscaleHound 数据,TailscaleHound 可以通过将 `AZUser.userPrincipalName` 与 `TS_User.LoginName` 进行匹配,来创建 `AZUser -> TS_User` 桥接关系。 ``` python3 TailscaleHound.py \ --hybrid-attacks Windows \ --bh-url https://bloodhound.example.com \ --bh-user admin \ --bh-password "$BLOODHOUND_SECRET" \ --output ./tailscalehound-output ``` 你可以添加 `--opengraph ./tailscalehound-output/tailscalehound_remote_opengraph__output.json`,以便在 TailscaleHound 数据被导入 BloodHound 之前构建桥接。 混合攻击路径示例: ![alt text](/Images/hybrid-attack-1.png) ![alt text](/Images/hybrid-attack-2.png) ## 示例查询 请参考 [保存的查询](SavedQueries) 以获取完整的查询列表: 列出 Tailscale 用户: ``` MATCH (n:TS_User) RETURN n ``` 查找由用户注册的设备: ``` MATCH p=(u)-[:TS_RegisteredDevice]->(d) WHERE (u:TS_User OR u:TS_ExternalUser) AND (d:TS_Device OR d:TS_ExternalDevice) RETURN p ``` 通过共享的外部设备查找外部用户: ``` MATCH p=(u:TS_ExternalUser)-[:TS_RegisteredDevice]->(d:TS_ExternalDevice)-[:TS_InExternalTailnet]->(t:TS_ExternalTailnet) RETURN p ``` 查找在共享外部设备上观察到的标签: ``` MATCH p=(d:TS_ExternalDevice)-[:TS_HasExternalTag]->(t:TS_ExternalTag) RETURN p ``` 通过 ACL 和授权查找基于组的设备访问权限: ``` MATCH p=(u:TS_User)-[:TS_IsMemberOf]->(s)-[:TS_AclSource|TS_GrantSource]->(r)-[:TS_AclTargetsDevice|TS_GrantTargetsDevice]->(d) RETURN p ``` 查找对设备的直接用户访问权限: ``` MATCH p=(u:TS_User)-[:TS_AclSource|TS_GrantSource]->(r)-[:TS_AclTargetsDevice|TS_GrantTargetsDevice]->(d) RETURN p ``` 查找 SSH 规则路径和允许的 SSH 用户: ``` MATCH p1=(u:TS_User)-[:TS_IsMemberOf]->(s)-[:TS_SSHRuleSource]->(r:TS_SSHRule)-[:TS_SSHRuleTargetsDevice]->(d:TS_Device) MATCH p2=(r)-[:TS_SSHRuleAllowsUser]->(ssh:TS_SSHUser) RETURN p1, p2 ``` 查找已启用 Funnel 的设备: ``` MATCH p=(d:TS_Device)-[:TS_HasFunnelEnabled]->(n:TS_Network) RETURN p ``` 查找从 Azure 到 Tailscale 的设备访问权限: ``` MATCH p=(az:AZUser)-[:TS_AZUserSyncedToUser]->(u:TS_User)-[:TS_IsMemberOf]->(s)-[:TS_AclSource|TS_GrantSource]->(r)-[:TS_AclTargetsDevice|TS_GrantTargetsDevice]->(d) RETURN p ``` ## 可遍历关系 BloodHound 的寻路功能使用 `schema.json` 中的 `is_traversable` 标志。TailscaleHound 目前将以下关系类型标记为可遍历: ``` TS_AZUserSyncedToUser TS_AclSource TS_AclTargetsAppConnector TS_AclTargetsDevice TS_AclTargetsExitNode TS_AclTargetsRoute TS_GrantSource TS_GrantTargetsAppConnector TS_GrantTargetsDevice TS_GrantTargetsExitNode TS_GrantTargetsRoute TS_HasFunnelCapabilities TS_HasFunnelEnabled TS_HasTag TS_IsAdminOf TS_IsITAdminOf TS_IsMemberOf TS_IsNetworkAdminOf TS_IsOwnerOf TS_RegisteredDevice TS_SSHRuleSource TS_SSHRuleTargetsDevice TS_SSHRuleTargetsSelf ``` ACL 测试、SSH 测试、端口、状态要求、默认状态、webhook、邀请、服务、计费管理员、auditor、app connector 运行时位置、自动批准者、密钥创建元数据以及外部 tailnet 元数据目前均被建模为不可遍历的上下文。 ## 环境变量 TailscaleHound 会加载 `.env` 文件和进程环境变量。CLI 参数的优先级高于环境变量。 ``` TAILSCALEHOUND_OUTPUT=./tailscalehound-output TAILSCALE_API_KEY=tskey-example TAILSCALE_TAILNET=example.com TAILCONTROL_COOKIE=optional_tailcontrol_cookie # TAILSCALE_API_KEY 的 OAuth 替代方案 TAILSCALE_CLIENT_ID=your_oauth_client_id TAILSCALE_OAUTH_SECRET=your_oauth_client_secret # 远程凭证的本地收集替代方案 TAILSCALEHOUND_STATUS=./tailscale-status.json TAILSCALEHOUND_ACCESS_POLICY=./access-policy.json # 辅助脚本和混合映射使用的 BloodHound 值 BLOODHOUND_URL=https://bloodhound.example.com BLOODHOUND_USERNAME=admin BLOODHOUND_SECRET=your_secret_here ``` 受支持的主要收集器变量包括 `TAILSCALEHOUND_OUTPUT`、`TAILSCALEHOUND_STATUS`、`TAILSCALEHOUND_ACCESS_POLICY`、`TAILSCALEHOUND_ACCESS_POLICY_FILE`、`TAILSCALE_API_KEY`、`TAILSCALE_CLIENT_ID`、`TAILSCALE_OAUTH_SECRET`、`TAILSCALE_TAILNET`、`TAILSCALE_API_BASE_URL`、`TAILCONTROL_COOKIE`、`TAILSCALE_TAILCONTROL`、`TAILSCALEHOUND_INCLUDE_NETWORK_LOGS`、`TAILSCALEHOUND_INSECURE`、`TAILSCALEHOUND_VERBOSE` 和 `TAILSCALEHOUND_DEBUG`。 混合映射还支持 `TAILSCALEHOUND_HYBRID_ATTACKS`、`BLOODHOUND_URL`、`BLOODHOUND_USERNAME` 和 `BLOODHOUND_SECRET`。`TAILSCALEHOUND_FILE` 是可选的,用于导入前或离线混合映射。 ## 输出文件 | 文件 | 用途 | | --- | --- | | `/tailscalehound_remote_opengraph__output.json | 远程 API OpenGraph 输出 | | `/tailscalehound_local_opengraph__output.json` | 本地状态 OpenGraph 输出,在提供时会使用 Access Policy 数据进行扩充 | | `/tailscalehound_remote_acl__policy.json` | 来自远程收集的原始 ACL 策略快照 | | `/tailscale_hybrid_paths_.json` | 从 Azure 到 Tailscale 的桥接输出 | ## 辅助脚本 | 脚本 | 用途 | | --- | --- | | `helper-scripts/upload_schema.py` | 从 `schema.json` 上传 OpenGraph 扩展 schema | | `helper-scripts/upload_ingest_files.py` | 上传一个或多个 BloodHound 收集的 JSON 文件以进行导入 | | `helper-scripts/upload_custom_icons.py` | 从 `custom_types.json` 上传自定义 BloodHound 节点类型图标 | | `helper-scripts/upload_saved_queries.py` | 从 `SavedQueries/` 同步保存的 Cypher 查询 | | `helper-scripts/sync_azuser_tailscale.py` | 从现有的 BloodHound `AZUser` 数据创建 `TS_AZUserSyncedToUser` 关系 | | `helper-scripts/clear_database.py` | 清除 BloodHound 收集的图表数据和导入历史 | | `helper-scripts/fetch_admin_machines.py` | 手动获取 admin-panel 机器响应以进行研究扩充 | ## 限制 - 本地收集无法从状态数据中推断出服务或邀请关系。使用 `--status-file` 时,ACL、授权、SSH、状态和 app connector 关系需要提供 `--access-policy-file`。 - Tailscale API 覆盖范围取决于 token 的权限以及可用的 tailnet 计划/功能。 - 某些 admin-panel 扩充依赖于未公开的 endpoint,并且可能会在不发出警告的情况下发生更改。 - 策略关系是根据配置建模的。运行时访问是否成功可能仍然取决于状态检查、设备状态、路由通告、网络可达性或 Tailscale 功能状态。 - 标签所有权和自动批准者目前被表示为上下文,而不是直接可遍历的攻击路径。 ## 路线图 - [ ] 根据Tailscale用户角色权限扩展角色建模。 - [ ] 为标签分配和自动批准添加显式的权限关系。 - [ ] 改进状态合规性分析。 - [ ] 扩展第三方身份提供者映射。
标签:BloodHound, Tailscale, Web报告查看器, 攻击路径分析, 数据泄露, 网络安全, 逆向工具, 隐私保护