
非公開のNginx Rift ASLRラボ、エクスプロイトチェーン、デモ録画
CVE-2026-42945 のRCE(リモートコード実行)概念実証です。これは、2008年に導入されたNGINXの ngx_http_rewrite_module における深刻なヒープバッファオーバーフローです。このバグにより、rewrite および set ディレクティブを使用しているサーバーに対して、認証なしのリモートコード実行が可能になります。
このフォークは、NGINXのオーバーフローと一般的な同一ホスト上のLFI/任意ファイル読み取りプリミティブを組み合わせたASLRバイパスチェーンで、元のPoCを拡張しています。ファイル読み取りプリミティブを使用して、nginxワーカーのマップ、libc、稼働中の /proc/<worker>/mem を取得し、リモートで system() アドレスと利用可能なヒープターゲットを導出します。
このラボの初期バージョンでは、nginxワーカーを意図的にクラッシュさせてサービスにコアダンプを書き出させ、そのコアダンプをファイル読み取りプリミティブ経由で取得・解析し、ヒープターゲットを含むASLR依存のプロセス状態を復元していました。このリポジトリでは、coreless は「読み取り可能なクラッシュコアダンプなし」を意味する省略形にすぎません。現在のデフォルトパスは、そのクラッシュコア依存をライブのprocfsメモリ読み取りに置き換えています。一方、保存されているレガシー core-guided パスは、引き続き生成されたワーカーのコアダンプを使用します。
この脆弱性は、他の3件のメモリ破壊問題(CVE-2026-42946、CVE-2026-40701、CVE-2026-42934)とともに、NGINXソースをワンクリックでオンボードした後、depthfirst のセキュリティ分析システムによって自律的に発見されました。
自分のコードでもこのような問題を見つけたいですか? 同じシステムを https://depthfirst.com/open-defense で試してください。
NGINXのスクリプトエンジンは2パス方式を採用しています。まず必要なバッファサイズを計算し、次にデータをコピーします。rewrite の置換文字列に ? が含まれるとメインエンジンで is_args フラグが設定されますが、長さ計算パスは新しくゼロ初期化されたサブエンジン上で実行されます。そのため:
is_args = 0 のため、生のキャプチャ長を返します。is_args = 1 のため、ngx_escape_uri を NGX_ESCAPE_ARGS 付きで呼び出し、エスケープ可能な各バイトを3バイトに展開します。このコピーにより、攻撃者が制御するURIデータで過小サイズのヒープバッファがオーバーフローします。攻撃では、クロスリクエストヒープフェンシュイを利用して隣接する ngx_pool_t の cleanup ポインタを破壊し(URIバイトにはヌルバイトを含められないため、POSTボディでスプレーします)、それを偽の ngx_pool_cleanup_s に向けさせ、プール破棄時に system() を呼び出させます。
このバグの詳細は、技術資料 をご覧ください。
| 製品 | 影響を受けるバージョン | 修正バージョン |
|---|---|---|
| NGINX Open Source | 0.6.27 – 1.30.0 | 1.31.0, 1.30.1 |
| NGINX Plus | R32 – R36 | R36 P4, R35 P2, R32 P6 |
ベンダー公式アドバイザリ: https://my.f5.com/manage/s/article/K000160932



このフォークは元の開示PoCをそのまま保持しつつ、より現実的な問いに焦点を当てた第2の研究トラックを追加しています:
ASLRが有効な実環境のx86_64 Linux VMに対して、ハードコードされたDocker/ラボのオフセットに頼らずにこのバグを悪用できるでしょうか?
この研究フォークにおける答えは、重要な制約はあるものの「はい」 です。動作するチェーンはASLRを無効化せず、元のハードコードされたヒープ/libcアドレスも使用しません。代わりに、同じポートでHTTPアクセス可能なプリミティブを介して実行時状態を導出し、リモートで取得した開示データから最終的なヒープターゲットを選択します。
現在、ASLR有効なエクスプロイトトラックが2つあり、corelessパスが現時点で最良のPoCとして扱われています:
nginx_rifter.py: クリーンで自己完結型のアセスメント兼統合エクスプロイトエントリポイントです。デフォルトのエクスプロイト手法は現在、coreless の /proc/<nginx-worker>/mem チェーンになっています。nginx_rifter_core_v2_1.py: レガシーのcore-guided版 nginx_rifter.py を保存したものです。以前VMで検証されたクラッシュコア研究パスの再現に役立ちますが、もはや推奨PoCではありません。tools/proc_mem_coreless_exploit.py: 初期のスタンドアロンcoreless研究ハーネスです。そのロジックは nginx_rifter.py に統合されました。このツールは生の実験リプレイ用に残されています。ターゲットのトポロジーは意図的に同一ポートです:
/api/.../lfi.php?file=.../phpinfo.php現在のcoreless proc-memパスは、次の高水準の手順を実行します:
/proc/<pid>/maps、マップされたlibcファイルを読み取ります。system() アドレスを計算します。/proc/<worker>/mem からマップ済み範囲を読み取ります。レガシーのcore-guidedパスも同様のベースアドレス導出を行い、その後ワーカーを意図的にクラッシュさせ、生成されたコアファイルをLFI経由で読み取り、そのコアからスプレーされた偽cleanupスロットを探し出します。これは有用な研究上の橋渡しでしたが、デフォルトのデプロイではあまり一般的でないコアダンプポリシーとファイルシステム権限に依存しています。
これは元の決定的なDockerデモとは異なります。x86_64 VMパスは通常のLinux ASLRを有効のままにし、実行のたびにプロセス固有のアドレスを再計算します。Docker corelessパスもASLRを有効のままにし、通常とは異なる読み取り可能コアの要件を排除しますが、対象クラスについて検証する必要があるprocfs権限の動作に依存します。
このフォークは管理された研究ラボです。ASLR有効チェーンは、普遍的な本番環境の前提とは言えない強い条件に依存しています:
/proc/<pid>/maps、マップされたlibc、および大きなマップ済みオフセットでの /proc/<pid>/mem を読み取れる必要があります。/proc/<pid>/maps、マップされたlibc、生成されたワーカーコアを読み取れる必要があります。phpinfo() と /proc/<pid>/maps だけでPIE/libcのベースアドレスは復元できますが、このエクスプロイトに必要な正確なヒープオブジェクト/ウィンドウをそれだけで復元することはできません。旧チェーンでは、その最終的な開示に読み取り可能なクラッシュコアを使用していました。現在のデフォルトチェーンは、代わりに /proc/<worker>/mem を使用します。これはコアダンプポリシーを変更せずにライブワーカーメモリを公開するため、同一UIDデプロイにおける現実的な任意ファイル読み取りの結果に近いものです。
残る重要な制限:
/proc/<pid>/mem はptraceで制限されています。Dockerラボと公式 nginx:stable イメージモデルに対する同一UIDチェックでは機能しましたが、デフォルトのprocfs保護では異なるUIDのアプリプロセスは失敗するはずです。現在のクリーンなエントリポイントは nginx_rifter.py です。これは、HTTPアクセス可能なローカルファイル読み取りプリミティブを備えた既知の脆弱なnginxデプロイを、認可されたテスターがどのように評価するかに近づけた、アセスメント優先のツールです。
初期のデモランナーと比較して、nginx_rifter.py は次の点でワークフローを改善しています:
--exploit が明示的に指定されない限り、クラッシュさせるエクスプロイトは実行しません。HOST:PORT として指定し、ファイル読み取りプリミティブは --file-read-template でモジュール化されています。/proc/self/status、/proc/self/maps、同一UIDワーカーのprocfs到達可能性を含みます。system()、ビルドID、バイナリハッシュ、OS詳細、proc-mem/core設定を発見します。rewrite + set ルート候補にフラグを立てます。nginx_rifter.py に統合されています。デフォルトの手法はcoreless proc-memです。現在の nginx_rifter.py は自己完結型です。アセスメントやエクスプロイトのために、以前のデモPoCバージョンや tools/proc_mem_coreless_exploit.py をインポートしたり、外部コマンドとして実行したりすることはありません。
旧版のcore-guided nginx_rifter.py 実装は nginx_rifter_core_v2_1.py として保存されています。
新しい artifacts/nginx_rifter_v3_coreless_exploit_20260519.gif は、統合されたv3 nginx_rifter.py のcorelessエクスプロイトパスを示しています。demo4.gif は、以前のオールインワンcore-guidedツールによるアセスメントと明示的エクスプロイトのフローを示しています。初期の nginx-aslr-demo.gif は、元のASLR有効エクスプロイトデモとして残っています。
Ubuntu 24.04.3 LTSでテスト済み。
元のASLR無効Docker再現手順:
./setup.sh — コンテナをビルドします。docker compose -f env/docker-compose.yml up — 脆弱なNGINXサーバーを起動します。python3 poc.py --shell — シェルを取得します。ローカルDocker再現手順については、LAB.md を参照してください。
レガシーASLR有効VM core-guidedチェーン:
./nginx_rifter_core_v2_1.py --target <target-host>:19321 --exploit --cmd id --fast
アセスメント優先v3ツール:
./nginx_rifter.py --target <target-host>:19321
nginx_rifter.py は、現在の実世界指向アセッサー兼統合PoCエントリポイントです。デフォルトモードではクラッシュを伴うエクスプロイトパスを実行しません。HTTPファイル読み取りプリミティブのプロファイリング、範囲指定/バイナリ読み取りの確認、OS/nginx/libcのフィンガープリント、nginxワーカーとASLR関連マップの発見、同一UID /proc/<worker>/mem の読み取り可能性のテスト、pid/コマンドライン/設定読み取りによるnginx設定パスの復元試行、脆弱な rewrite + set ルート候補へのフラグ付け、そして現在のcorelessチェーンの実現可能性マトリクスの出力を行います。
現在の nginx_rifter.py は自己完結型です。アセスメントやエクスプロイトのために、以前のデモPoCバージョンやスタンドアロンのproc-mem研究ハーネスをインポートしたり、外部コマンドとして実行したりすることはありません。
カスタムLFI/ダウンロード形式の場合:
./nginx_rifter.py --target <target-host>:19321 \
--file-read-template 'http://{host}:{port}/download?path={path_url}{range_query}'
エクスプロイトの実行は明示的です:
./nginx_rifter.py --target <target-host>:19321 --exploit --cmd id --fast
# Discovery-only exploit smoke test, no spray/probe
./nginx_rifter.py --target <target-host>:19321 --exploit --derive-only --cmd id
デフォルトのエクスプロイト手法はcoreless proc-memです。以下のオプションは、coreless Dockerプルーフで最も信頼性が高かったため、デフォルトで既に選択されています:
--exploit-method proc-mem
--target-len 6
--max-region 268435456
レガシーの読み取り可能コアモードは比較用に引き続き利用できますが、その旧パスを再現するにはバージョン付きスクリプトの方が明確です:
./nginx_rifter_core_v2_1.py --target <target-host>:19321 --exploit --cmd id --fast
レガシーの録画向けターミナルデモ:
./demo_ctf_exploit_v1_9.py --host <target-host>:19321 --cmd id --clear
demo_ctf_exploit_v1_9.py は、core-guidedラボパス向けの旧オペレーター向けランナーです。現在推奨されるPoCエントリポイントは nginx_rifter.py です。
デフォルトのファイル読み取りプリミティブは、このフォークのPHPルートです:
/lfi.php?file=<path>&offset=<n>&length=<n>
別の既知の脆弱なCTFアプリケーションやテストプラットフォームの場合、ファイル読み取りベクトルはモジュール化されています:
./nginx_rifter.py --target <target-host>:19321 --exploit --cmd id \
--target-profile generic \
--file-read-template 'http://{host}:{port}/download?path={path_url}{range_query}'
テンプレートは {host}、{port}、{path_url}、{offset}、{length}、{range_query} をサポートします。genericプロファイルはこのフォークのラボ固有のnginx設定アサーションをスキップしますが、デフォルトエクスプロイトには同じ基盤となる機能(読み取り可能なnginxワーカーの /proc マップ、読み取り可能なlibc、読み取り可能な /proc/<worker>/mem)が依然として必要です。phpinfo() はオプションです。無効にするには --phpinfo-path '' を使用します。
現実性に関する注意: LFI/ファイル読み取りバグクラスと同一ホスト上のnginx/PHP-FPMデプロイモデルは現実的です。proc-memチェーンは、ワーカーのコアダンプを有効にしたり読み取ったりする必要がないため、以前のクラッシュコアチェーンよりも現実的です。それでも、これは普遍的なデフォルト本番環境の前提ではありません。同一UIDのプロセスレイアウト、procfs/Yamaポリシー、コンテナの名前空間設定、ファイル読み取りプリミティブの品質によって、/proc/<worker>/mem に到達できるかどうかが決まります。
LFIなしの研究プローブ:
python3 tools/non_lfi_leak_probe.py --target <target-host>:19321
python3 tools/non_lfi_active_response_probe.py --target <target-host>:19321
これらはネガティブな研究プローブであり、エクスプロイトのエントリポイントではありません。LFI、phpinfo、procfs、コア、デバッガアクセス、ハードコードされたライブASLRベースを使用せずに、パッシブな反射シンクと初期の遅延レスポンスのオーバーリード形状をテストします。
追加のラボノートと実行ログは docs/ にあります。特に:
docs/CTF_PLAN.mddocs/CTF_FINDINGS.mddocs/CTF_TESTS.mddocs/CTF_EXPERIMENT_LOG.mddocs/DEMO_POC_IMPROVEMENTS.mddocs/KNOWN_LAYOUT_PATTERNS.mddocs/VAGRANT_ESXI.mddocs/CORELESS_ASLR_PLAN.mddocs/CORELESS_ASLR_FINDINGS.mddocs/NON_LFI_ASLR_BYPASS_LOG.mddocs/DEMO_RECORDING_WORKFLOW.md