
Ferramenta de exploração para o overflow de erro ICMP do EDK II UEFI PXE (CVE-2026-97631): forja pacotes ICMP falsificados, implanta um EFI_EVENT contrafeito e despeja a memória DXE via UART.
Ferramentas para o overflow de erro ICMP do driver EDK II PXE Base Code
(NetworkPkg/UefiPxeBcDxe, GHSA-99cj-7hg9-mp4m, CVSS 4.0 9.5).
Durante uma inicialização PXE, o driver copia uma mensagem de erro ICMP para um buffer
fixo de 504 bytes. Uma mensagem mais longa torna-se uma escrita linear além desse buffer, para o pool
DXE. Como o destino da escrita é o próprio endereço do buffer, o payload é
independente de posição: o byte i do datagrama cai em &Mode->IcmpError + i.
O overflow planta um EFI_EVENT falsificado; o núcleo DXE o despacha
através do caminho normal CoreSignalEvent; o payload restaura o evento a partir de um
snapshot, percorre intervalos de memória escolhidos pelo operador e retorna EFI_SUCCESS para que a
inicialização continue.
O raio de impacto permanece dentro da própria memória DXE do firmware. Sem escrita na flash, sem mecanismo de persistência, sem artefato no SO.
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
Payload:
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
O resultado tem 378 bytes, independente de posição, sem relocações.
O emissor e o receptor são POSIX (AF_PACKET, IP_HDRINCL, termios) e compilam
com make no Linux. O simulador compila com MSVC via Makefile.win:
cl /nologo /W3 /O2 /Iinclude /Fe:build\sim.exe sim\sim.c src\craft.c src\graft.c src\layout.c
build/sim.exe mapeia uma página de pool falsa, grava o overflow onde o memcpy vulnerável o faria, verifica se o IEVENT resultante despacharia o payload, chama o payload como código de máquina real e, em seguida, verifica:
26 verificações sobre layout, ABI, enquadramento e construção de pacotes. Isso prova que as partes concordam entre si. Não prova o endereço de pool de um firmware específico, que é uma alocação em tempo de execução.
Dois modos, usados em ordem.
Probe: apenas caminho legal, sem escrita fora dos limites.
pxeinj --target 10.0.0.50 --spoof 10.0.0.1 --sniff --probe --send
Um erro ICMP bem formado de 504 bytes. Mesmo spoof, mesma transação BOOTP embutida, tudo igual. Se o cliente continuar inicializando, o erro foi aceito e o loop de cópia vulnerável foi alcançado. Confirmação não destrutiva, e não precisa de endereço de pool.
Overflow: recusa-se a construir até que três coisas existam: a base do pool
(tools/fw_offsets.py), os bytes originais do evento (--shadow) e pelo menos um
intervalo.
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 contém um START-END por linha, em hexadecimal sem 0x; consulte
ranges.example.txt para o tamanho e o orçamento de tempo. O caminho de overflow v6 está
desativado: a sondagem funciona sobre v6, a escrita não, até que o limite de cópia v6
tenha sido rederivado a partir do código-fonte corrigido.
EFI_SUCCESS no caminho normal de notificação, então o boot prossegueSignalLink do evento é autoconsistente, então a travessia da lista não dispara asserçãoOs vestígios residuais são inerentes ao bug: o evento foi sinalizado em um momento em que normalmente não seria, a página do pool permanece suja, e se a plataforma mede o DXE com um TPM, o valor do PCR é o que era quando o boot começou. Qualquer coisa além disso não é uma propriedade deste bug.
--send é obrigatório; o padrão é uma execução de simulação--pool-base, --payload, --shadow
e uma lista de intervalos não vazia. Cada um deles tem uma forma específica de corromper
o firmware se for adivinhado, então nenhum é opcional--shadow deve conter uma assinatura EFI_EVENT no deslocamento esperado, o que
detecta um arquivo preenchido com zeros e um --event-off errado em uma única verificação, em vez de
no momento do dispatchMode->IcmpError é uma alocação em tempo de execução e difere por
build de firmware. Não pode ser derivado de um link map. tools/fw_offsets.py
fornece os deslocamentos; a base precisa ser medida no firmware alvo, por
exemplo a partir de um trace DEBUG_POOL, e então armazenada em cache.sizeof(EFI_PXE_BASE_CODE_MODE) e offsetof(..., IcmpError) mudam entre
versões do edk2. Os padrões em tools/fw_offsets.py são pontos de partida, não
valores em que se confiar.DpcHandle
na árvore alvo antes de confiar no deslocamento do overflow.CoreSignalEvent vai percorrer. A ferramenta se recusa a ser compilada
sem --shadow por esse motivo.