
poc pour CVE-2024-38063 (RCE dans tcpip.sys)
Ceci est un PoC (plutôt instable) pour CVE-2024-38063, une RCE dans tcpip.sys corrigée le 13 août 2024. Je n'ai pas découvert et signalé cette vulnérabilité, c'est Wei.
pip3 install scapy
Modifiez les champs dans le script :
iface <- Si vous avez plusieurs adaptateurs, vous devez choisir celui à utiliser pour envoyer les paquets. Par exemple "eth0" sous Linux ou "Hyper-V Virtual Ethernet Adapter" sous Windows. Si vous comptez utiliser votre interface par défaut, laissez-le vide.ip_addr <- Adresse IP du système cible (IPv6)num_tries & num_batches <- Combien de lots de paquets différents envoyer. Plus il y en a = plus de corruptions du tas provoquées + plus de chances de déclencher la vulnérabilité.mac_addr <- Laissez vide, sauf si scapy se plaint de ne pas trouver l'adresse MAC. Voir ci-dessous dans la section de dépannage.Exécutez le script :
python3 cve-2024-38063.py
La façon la plus simple de reproduire la vulnérabilité est d'utiliser bcdedit /set debug on sur le système cible et de redémarrer la machine/VM. Cela fait du pilote d'adaptateur réseau par défaut kdnic.sys, qui est très enclin à fusionner les paquets. Si vous essayez de reproduire la vulnérabilité sur une configuration différente, vous devrez amener le système à fusionner les paquets que vous envoyez. Vous pouvez consulter la section de dépannage ci-dessous pour plus de détails.
Vous pouvez lire cette excellente analyse de la vulnérabilité par Marcus si vous êtes intéressé par les détails techniques. Les détails que j'ai écrits ci-dessous sont destinés à servir de résumé, plutôt que d'analyse technique sérieuse.
NET_BUFFER qui contient les données du paquet en mémoire tampon. À l'offset 0x30, nous avons également un champ d'offset courant qui indique jusqu'où le paquet a été analysé. À ce stade, la valeur de l'offset est généralement 0x28, indiquant que l'en-tête IPv6 a été analysé mais rien d'autre.tcpip!Ipv6pReceiveDestinationOptions, une erreur d'analyse entraînera l'appel de tcpip!IppSendErrorList. Cette fonction appelle tcpip!IppSendError sur chaque objet paquet de la liste chaînée (en commençant par l'actuel).tcpip!IppSendError a des effets secondaires. Il "ramène" les données du paquet mises en mémoire tampon au début et remet à zéro le champ d'offset courant.0x8C). Cela signifie que le pilote continuera à analyser les en-têtes d'extension des autres paquets de la liste chaînée, même s'ils ont été "ramenés" dans .Ipv6pReceiveFragment. La fonction analyse l'en-tête d'extension de fragment et suppose que le champ d'offset du paquet sera au moins 0x28 lors du calcul de la longueur des données hors en-tête du paquet en soustrayant 0x30 de la valeur d'offset courante. Cette valeur est ensuite stockée dans l'objet de réassemblage dont le but est de réassembler le paquet fragmenté.IppSendError. La valeur de l'offset sera zéro et sera augmentée à 8 plus tôt dans Ipv6pReceiveFragment. Lors du calcul de la taille des données hors en-tête, la valeur passera sous zéro et sera égale à 0xffd8 (la soustraction est effectuée sur 16 bits).Ipv6pReassembleDatagram, où elle est utilisée pour calculer la longueur d'un tampon de sortie du paquet réassemblé. Cependant, tous les calculs sont effectués sur 32 bits et il y a une vérification de cohérence pour que la longueur totale ne dépasse pas 0xFFFF, ce qui est le cas dans cette situation.Ipv6pReassemblyTimeout, où elle est également utilisée de la même manière. Cependant, les calculs ici sont effectués sur 16 bits et un dépassement d'entier se produit. Cela conduit à un débordement de tampon lors de la copie des données dans le tampon plus tard.Pour déclencher Ipv6pReassemblyTimeout, l'expéditeur du fragment doit être inactif pendant 1 minute. Notre stratégie est alors :
IppSendError, suivies d'un paquet fragmentéIpv6pReceiveFragment et créer un nouvel objet de réassemblage avec une longueur de données de fragment qui est une valeur élevée sur 16 bitsIpv6pReassemblyTimeout soit déclenché.Ipv6pReassemblyTimeout et déclencher un débordement de tampon basé sur le tas.Les paquets du script sont envoyés en rafale afin d'augmenter les chances qu'ils soient fusionnés. La charge utile principale est assez simple :
Nous définissons également manuellement les champs hop limit et flow label de l'en-tête IPv6. Rappelons que les données du paquet en mémoire tampon sont réinitialisées à cause de la vulnérabilité. Cela signifie que, lors du traitement du paquet fragmenté, l'en-tête IPv6 sera interprété comme des données d'en-tête de fragment. Le champ hop limit de l'en-tête IPv6 sera interprété comme l'un des bits du champ id de l'en-tête de fragment. En le modifiant, nous nous assurons de déclencher la vulnérabilité pour plusieurs fragments différents et de provoquer plusieurs corruptions différentes, augmentant ainsi les chances d'un crash (après tout, c'est un PoC). Le champ flow label de l'en-tête IP sera interprété comme les champs offset et "more indicator" de l'en-tête de fragment. En le définissant sur 1, nous indiquons qu'il y a d'autres en-têtes à venir (d'où la possibilité de déclencher Ipv6pReassemblyTimeout plus tard) et que l'offset est nul (puisque c'est le premier paquet avec un tel id qui arrive).
Ipv6pReassemblyTimeout exige que le paquet fragment d'origine soit envoyé en unicast.Si cela ne fonctionne pas, cela peut être parce que :
Ether(raw(sr1(IPv6(dst={your_dest_ip})/ICMPv6EchoRequest()))).src, mais cela ne fonctionne pas parfoistcpip!Ipv6pReceiveDestinationOptions -> tcpip!Ipv6pProcessOptions -> tcpip!IppSendErrorList est atteint ?tcpip!Ipv6pProcessOptions et vérifiez si est nul tout le temps. Si oui, alors les paquets ne sont pas fusionnés pour une raison quelconque.IppSendError0x28.[rcx]tcpip!Ipv6pReceiveFragment et vérifiez si [rcx+0x30] est égal à zéro. Si ce n'est pas le cas, alors la vulnérabilité n'a pas été déclenchée pour une raison quelconque.