
poc para CVE-2024-38063 (RCE en tcpip.sys)
Este es un PoC (bastante inestable) para CVE-2024-38063, un RCE en tcpip.sys parcheado el 13 de agosto de 2024. Yo no encontré ni reporté esta vulnerabilidad; eso fue Wei.
pip3 install scapy
Modifica los campos en el script:
iface <- Si tienes varios adaptadores, necesitas elegir cuál usar para enviar paquetes. Por ejemplo, "eth0" en Linux o "Hyper-V Virtual Ethernet Adapter" en Windows. Si vas a usar tu interfaz predeterminada, déjalo vacío.ip_addr <- Dirección IP del sistema objetivo (IPv6)num_tries y num_batches <- Cuántos lotes de paquetes diferentes se envían. Más de ellos = más corrupciones de heap causadas + mayor probabilidad de activar la vulnerabilidad.mac_addr <- Déjalo vacío, a menos que scapy se queje de que no puede encontrar la dirección MAC. Consulta la sección de solución de problemas más abajo.Ejecuta el script:
python3 cve-2024-38063.py
La forma más fácil de reproducir la vulnerabilidad es usar bcdedit /set debug on en el sistema objetivo y reiniciar la máquina/VM. Esto hace que el controlador de adaptador de red predeterminado sea kdnic.sys, que está muy dispuesto a coalescer paquetes. Si intentas reproducir la vulnerabilidad en una configuración diferente, tendrás que conseguir que el sistema coalesca los paquetes que enviaste. Puedes leer la sección de solución de problemas a continuación para más detalles.
Puedes leer este gran análisis de la vulnerabilidad de Marcus si te interesan los detalles técnicos. Los detalles que he escrito a continuación pretenden servir como resumen, más que como un análisis técnico serio.
NET_BUFFER que contiene los datos del paquete en búfer. En el desplazamiento 0x30 también tenemos un campo de desplazamiento actual que indica hasta dónde se ha analizado el paquete. En esta etapa, el valor de desplazamiento generalmente será 0x28, lo que indica que la cabecera IPv6 se ha analizado pero nada más.tcpip!Ipv6pReceiveDestinationOptions, un error de análisis hará que se llame a tcpip!IppSendErrorList. Esta función llama a tcpip!IppSendError para cada objeto de paquete en la lista enlazada (empezando por el actual).tcpip!IppSendError tiene efectos secundarios. "Revierte" los datos del paquete en búfer al inicio y restablece el campo de desplazamiento actual a cero.0x8C). Esto significa que el controlador continuará analizando las cabeceras de extensión de otros paquetes en la lista enlazada, incluso si han sido "revertidos" en IppSendError.0x28.Ipv6pReceiveFragment. La función analiza la cabecera de extensión de fragmento y asume que el campo de desplazamiento del paquete será al menos 0x28 cuando calcula la longitud de los datos que no son de cabecera en el paquete restando 0x30 del valor de desplazamiento actual. Este valor se almacena luego en el objeto de reensamblaje cuyo propósito es reensamblar el paquete fragmentado.IppSendError. El valor de desplazamiento será cero y se incrementará a 8 en algún punto anterior de Ipv6pReceiveFragment. Al calcular el tamaño de los datos que no son de cabecera, el valor experimentará un underflow y será igual a 0xffd8 (la resta se hace en 16 bits).Ipv6pReassembleDatagram, donde se usa para calcular la longitud de un búfer de salida del paquete reensamblado. Sin embargo, todos los cálculos se hacen en 32 bits y hay una verificación de cordura de que la longitud total no exceda 0xFFFF, lo cual sí sucede en este caso.Ipv6pReassemblyTimeout, donde también se usa de la misma manera. Sin embargo, los cálculos aquí se hacen en 16 bits y se produce un desbordamiento de entero. Esto conduce a un desbordamiento de búfer al copiar datos en el búfer más adelante.Para activar Ipv6pReassemblyTimeout, el emisor del fragmento debe permanecer inactivo durante 1 minuto. Nuestra estrategia es entonces:
IppSendError, seguidas de un paquete de fragmentoIpv6pReceiveFragment y crear un nuevo objeto de reensamblaje con una longitud de datos de fragmento que sea un valor alto de 16 bitsIpv6pReassemblyTimeout se active.Ipv6pReassemblyTimeout y desencadenar un desbordamiento de búfer basado en heap.Los paquetes en el script se envían de forma masiva para que haya una mayor probabilidad de que se coalescan. La carga útil principal es bastante simple:
También establecemos manualmente los campos de límite de saltos (hop limit) y etiqueta de flujo (flow label) en la cabecera IPv6. Recuerda que los datos del paquete en búfer se restablecen debido a la vulnerabilidad. Esto significa que, al procesar el paquete de fragmento, la cabecera IPv6 se interpretará como datos de la cabecera de fragmento. El campo de límite de saltos en la cabecera IPv6 se interpretará como uno de los bits del campo id en la cabecera de fragmento. Al cambiarlo, aseguramos que la vulnerabilidad se active para múltiples fragmentos diferentes y que se causen múltiples corrupciones diferentes, aumentando la probabilidad de un crash (después de todo, es un PoC). El campo de etiqueta de flujo de la cabecera IP se interpretará como los campos de desplazamiento y "más indicador" de la cabecera de fragmento. Al establecerlo en 1, indicamos que hay más cabeceras por venir (por lo tanto, podemos activar Ipv6pReassemblyTimeout más adelante) y que el desplazamiento es cero (ya que es el primer paquete con ese id que llega).