
poc para CVE-2024-38063 (RCE no tcpip.sys)
Este é um PoC (um tanto instável) para CVE-2024-38063, uma RCE em tcpip.sys corrigida em 13 de agosto de 2024. Eu não encontrei e reportei esta vulnerabilidade, isso foi feito por Wei.
pip3 install scapy
Modifique os campos no script:
iface <- Se você tiver vários adaptadores, precisa escolher qual usar para enviar pacotes. Ex.: "eth0" no Linux ou "Hyper-V Virtual Ethernet Adapter" no Windows. Se for usar sua interface padrão, deixe vazio.ip_addr <- Endereço IP do sistema alvo (IPv6)num_tries & num_batches <- Quantos lotes de pacotes diferentes enviar. Mais deles = mais corrupções de heap causadas + maior chance de acionar a vulnerabilidade.mac_addr <- Deixe vazio, a menos que o scapy reclame que não consegue encontrar o endereço MAC. Veja abaixo na seção de solução de problemas.Execute o script:
python3 cve-2024-38063.py
A maneira mais fácil de reproduzir a vulnerabilidade é usando bcdedit /set debug on no sistema alvo e reiniciando a máquina/VM. Isso faz com que o driver do adaptador de rede padrão seja kdnic.sys, que é muito propenso a coalescer pacotes. Se você está tentando reproduzir a vulnerabilidade em uma configuração diferente, precisará colocar o sistema em uma posição onde ele coalescerá os pacotes enviados. Você pode ler a seção de solução de problemas abaixo para mais detalhes.
Você pode ler esta excelente análise da vulnerabilidade por Marcus se estiver interessado nos detalhes técnicos. Os detalhes que escrevi abaixo têm a intenção de servir como um resumo, em vez de uma análise técnica séria.
NET_BUFFER que contém dados de pacote em buffer. No offset 0x30 também temos um campo de offset atual que indica o quanto do pacote já foi analisado. Nesta fase, o valor do offset geralmente será 0x28, indicando que o cabeçalho IPv6 foi analisado, mas nada mais.tcpip!Ipv6pReceiveDestinationOptions, um erro de análise resultará na chamada de tcpip!IppSendErrorList. Esta função chama tcpip!IppSendError em cada objeto de pacote na lista encadeada (começando pelo atual).tcpip!IppSendError tem efeitos colaterais. Ele "reverte" os dados do pacote em buffer de volta ao início e redefine o campo de offset atual para zero.0x8C). Isso significa que o driver continuará a analisar cabeçalhos de extensão de outros pacotes na lista encadeada, mesmo que tenham sido "revertidos" em IppSendError.0x28.Ipv6pReceiveFragment. A função analisa o cabeçalho de extensão de fragmento e assume que o campo de offset do pacote será pelo menos 0x28 ao calcular o comprimento dos dados não-cabeçalho no pacote, subtraindo 0x30 do valor de offset atual. Este valor é então armazenado no objeto de remontagem cujo propósito é remontar o pacote fragmentado.IppSendError. O valor do offset será zero e aumentado para 8 em algum ponto anterior em Ipv6pReceiveFragment. Ao calcular o tamanho dos dados não-cabeçalho, o valor sofrerá underflow e será igual a 0xffd8 (a subtração é feita em 16 bits).Ipv6pReassembleDatagram, onde é usado para calcular o comprimento de um buffer de saída do pacote remontado. No entanto, todos os cálculos são feitos em 32 bits e há uma verificação de sanidade de que o comprimento total não excede 0xFFFF, o que acontece neste caso.Ipv6pReassemblyTimeout, onde também é usado da mesma maneira. No entanto, os cálculos aqui são feitos em 16 bits e ocorre um estouro de inteiro. Isso leva a um estouro de buffer ao copiar dados para o buffer posteriormente.Para acionar Ipv6pReassemblyTimeout, o remetente do fragmento deve ficar inativo por 1 minuto. Nossa estratégia é então:
IppSendError, seguidas de um pacote de fragmentoIpv6pReceiveFragment e criar um novo objeto de remontagem com comprimento de dados de fragmento que é um valor alto de 16 bitsIpv6pReassemblyTimeout seja acionado.Ipv6pReassemblyTimeout e acionar um estouro de buffer baseado em heap.Os pacotes no script são enviados em massa para que haja uma chance maior de serem coalescidos. O payload principal é bem simples:
Também definimos manualmente os campos hop limit e flow label no cabeçalho IPv6. Lembre-se de que os dados do pacote em buffer são redefinidos devido à vulnerabilidade. Isso significa que, ao processar o pacote de fragmento, o cabeçalho IPv6 será interpretado como dados do cabeçalho de fragmento. O campo hop limit no cabeçalho IPv6 será interpretado como um dos bits do campo id no cabeçalho de fragmento. Ao alterá-lo, garantimos que acionamos a vulnerabilidade para vários fragmentos diferentes e causamos várias corrupções diferentes, aumentando a chance de uma falha (já que este é um PoC, afinal). O campo flow label do cabeçalho IP será interpretado como os campos de offset e "more indicator" do cabeçalho de fragmento. Ao defini-lo como 1, indicamos que há mais cabeçalhos por vir (portanto, sendo capazes de acionar Ipv6pReassemblyTimeout mais tarde) e que o offset é zero (já que este é o primeiro pacote com tal id que está chegando).