
CVE-2026-32740 Next.js/sharp のリークから memcpy-GOT に至る RCE チェーンに対する Fortbridge の非公開 PoC
ハードコードされた Next.js/sharp イメージスタックにおける CVE-2026-32740 を、任意アドレス書き込みと検証済みの /usr/bin/id コールバックに変換する実用的な概念実証です。
これは Fortbridge の非公開研究リポジトリです。同梱のラボ、または明示的にテストを許可された他のシステムに対してのみ使用してください。
このエクスプロイトは、ターゲットの HTTP アップロードおよび画像最適化ルートのみを使用します:
g_module_open_full のコピーを使用します。これは dlopen をラップしてファイルパスからネイティブ共有ライブラリをロードする GModule ルーチンです。エクスプロイトはそのランタイムアドレスを、復元された libvips ベースにハードコードされたプロファイルオフセット 0x3e995e を加えたものとして計算します。ライブラリをロードするとそのコンストラクタが実行されます。/usr/bin/id を実行するコンストラクタを持つ小さな共有オブジェクトをコンパイルします。その ELF を、画像名 x.jpg、メディアタイプ image/jpeg として公開アップロードルート経由で送信します。memcpy@GOT - 16 にリダイレクトする 116x33 の 4 タイル AVIF を生成します。uploads/x.jpg を格納し、memcpy@GOT を導出された GModule ローダーで置き換えます。次の行は、ライブラリパスがすでに RDI に入った状態でそのローダーを呼び出します。/usr/bin/id の出力を返します。試行ごとのトークンにより、古いコールバックが成功としてカウントされるのを防ぎます。返された uid=... 行が証明となります。元の libvips 相対検証実行は
evidence/libvips-gmodule-rce-10x.json に記録されています。
10 個の新規プロセスすべてが、10 個の異なるランダム化された libvips ベースと 10 個の独立して導出されたローダーアドレスで、有効な /usr/bin/id 出力を返しました。
正確な Ubuntu 実行データは
evidence/libvips-gmodule-pie-rce-10x.json にあります。
正確な Debian 13 APT 実行データは
evidence/debian13-apt-libvips-gmodule-rce-10x.json にあります。
完全なエクスプロイトを、新たに起動した 10 個の Ubuntu Node プロセスと 10 個の Debian Node プロセスに対してテストしました。20 回の実行すべてがコマンド実行に到達し、ターゲットの /usr/bin/id 出力を返しました。また、エクスプロイトはランダム化された libvips ベースごとに異なる GModule ローダーアドレスを計算しました。
最終ペイロードを作成する前に、エクスプロイトは複数回の ASLR リーク試行を必要とする場合があります。各試行はリーク AVIF をアップロードし、最適化ルートを通して送信し、返された PNG を調べて 1 つのプロファイルと 1 つの libvips ベースを特定する 4 つのポインタを確認します。Ubuntu では 3 回から 23 回の試行が必要でした。Debian では 3 回から 15 回でした。不完全または曖昧な証拠は、プロファイルを推測するのではなく、別の試行を引き起こします。
このプロジェクトには 96 個の自動回帰テストもあります。これらはコードレベルのチェックであり、96 回の追加エクスプロイト実行ではありません。プロファイル検証、返されたポインタの分類、ヒープキャリブレーション、アドレス計算、ペイロード構築、および証拠がサポート対象のターゲットと一致しない場合の安全な失敗をカバーしています。
両方の x86-64 ターゲットは Next.js 15.5.23、sharp 0.34.4、バンドルされた libvips 8.17.2、バンドルされた libheif 1.20.2、ASLR、および NX を使用しています。ネイティブランタイムは異なります:
| プロファイル | Node | glibc | libstdc++ | セレクタ関係 |
|---|---|---|---|---|
| Ubuntu | 25.8.1, PIE ET_DYN | 2.43-2ubuntu2.4 | 6.0.35 | 0x6000 - 0x690 = 0x5970 |
| Debian 13 | Debian APT 20.19.2, PIE ET_DYN | 2.41-12+deb13u4 | 6.0.33 | 0x6000 - 0x3a0 = 0x5c60 |
完全なビルド ID と SHA-256 値は
profiles/native_stack_profiles_pie.json にあります。
Debian パッケージ、アーティファクト、ルートスモーク、および 5 ライフタイムのレイアウト測定は
evidence/debian13-profile-derivation.json に記録されています。
Debian ターゲットは標準ディストリビューションパッケージ
nodejs=20.19.2+dfsg-1+deb13u3 を使用しており、Node はソースからコンパイルされていません。
チェーンはランダム化された Node ベースを必要としません。その制御ターゲットは libvips 内部の g_module_open_full ルーチンであり、そのランダム化されたベースは返されたピクセルから復元されます。各バージョン付きプロファイルは、エクスプロイトに必要なビルド固有の定数をハードコードしています:
memcpy@GOT オフセット、および g_module_open_full オフセットとその検証用命令バイト;ランダム化された libvips ベース、結果として得られるランタイムローダーアドレス、および最終的な 2 バイトセレクタはハードコードされていません。これらは各ターゲットプロセスについて、返されたピクセルと選択されたプロファイルから導出されます。
エクスプロイトは、プロファイルが不正な場合、または返されたピクセルがサポート対象のプロファイル/ベースのペアを正確に 1 つ選択しない場合、フェイルクローズします。ストックプロファイルはまた、完全な返されたヒープレコードを必要とします。プロファイルは正確な互換性の主張であるため、オペレータは使用前にターゲットアーティファクトをオフラインで検証する必要があります。
ローダー ABI は重要です。上書きされた呼び出しは、RDI にライブラリパス、RSI に画像行ポインタ、RDX に 58 バイトのコピー長を渡します。この正確にプロファイルされた GModule ルーチンは、ESI からのサポートされたフラグビットのみを使用し、成功したロードパスでは RDX を逆参照しません。オフラインハーネスが、測定実行で使用される前にそのエントリポイントと命令シグネチャを検証しました。
libaom-av1 エンコーダ付きの ffmpegcc として利用可能な C コンパイラ唯一の Python 依存関係をインストールします:```bash python3 -m venv .venv . .venv/bin/activate python3 -m pip install -r requirements.txt
AV1 エンコードのサポートを確認します:```bash
ffmpeg -hide_banner -encoders | grep libaom-av1
このラボは意図的に任意のアップロードを受け付け、選択されたファイルを sharp に渡します。信頼できないネットワークに公開しないでください。```bash cd lab npm ci npm run build npm run start
ターゲットは `http://127.0.0.1:3000` で利用可能になります。
最初の PIE プロファイルで使用される Node アーティファクトを中心に Ubuntu ラボイメージをビルドするには:```bash
./scripts/build_ubuntu2604_container.sh
docker run --rm --network host \
fortbridge/libheif-grid-nextjs-rce:ubuntu2604
ダイジェストロックされた Ubuntu 26.04 イメージは、プロファイルに記録された正確な Node 25.8.1 PIE アーティファクトをビルドし、その SHA-256 を検証してから、クリーンなランタイムステージにコピーします。Node の公式 Linux バイナリは ET_EXEC である一方、このプロファイルは意図的に PIE 実行ファイルをテストするため、ソースビルドが必要です。
Debian のサポートされている APT パッケージを使用して Debian ターゲットを再現するには:```bash
./scripts/build_debian13_container.sh
docker run --rm --network host
fortbridge/libheif-grid-nextjs-rce:debian13
イメージはダイジェストで固定された Debian 13 slim ベースからビルドされます。npm はビルダーステージにのみ存在し、最終ターゲットは Debian APT から Node をインストールし、同じアプリケーションとルートを実行します。
## エクスプロイトを実行する