
SYN IPv4 con opciones IP, un objetivo de laboratorio por ejecución, para la investigación de CVE-2026-98432. Analizador de desplazamiento de cabecera, pruebas de regresión y una autopsia de un auto-explotador defectuoso.
Una sonda de objetivo único para CVE-2026-98432, el use-after-free de TCP IPv4 del kernel de Linux corregido en octubre de 2026.
Construye un SYN IPv4 que transporta opciones IP (24 bytes NOP por defecto, lo que eleva IHL a 11), lo envía a un host y lee la respuesta por desplazamiento de cabecera en lugar de por coincidencia de patrones. La lógica de paquetes también funciona sin conexión: una ejecución en seco imprime y vuelve a analizar el paquete construido, el analizador hexadecimal procesa tráfico capturado, y la suite de pruebas no necesita ni root ni red.
No hay manejo de listas de objetivos, ni integración con Shodan, ni modo por lotes. Una dirección por ejecución, y la CLI rechaza cualquier cosa fuera de rangos de laboratorio a menos que pases --allow-public. La herramienta asume que eres dueño del objetivo o tienes permiso por escrito para probarlo.
python3 -m pip install -e ".[test]"
Python 3.9 o superior. Solo biblioteca estándar.
Ejecución en seco, sin privilegios, sin paquete enviado:
synipopt --dry-run --target 192.0.2.10
Analiza el paquete del registro del script original, el que reportó como SYN-ACK:
synipopt --analyze-hex "$(cat docs/fixtures/original-log-packet.hex)"
Sondea una VM de laboratorio y compara los SYN con opciones frente a los SYN simples:
sudo synipopt --target 192.168.56.101 --dport 443 --retries 3 --compare --log probe.jsonl
Construcción por defecto, 64 bytes en el cable:
0x01Un SYN que transporta opciones es lo que coloca ireq->ireq_opt en el socket de petición. El kernel compila el bloque de opciones, y el relleno de NOP puro se compila a un bloque vacío, por lo que un SYN-ACK a la construcción por defecto vuelve sin opciones IP. Las opciones que transportan carga útil, como record route, se reflejan. Medido durante el desarrollo contra un socket en escucha:
| Opciones del SYN | Cabecera IP del SYN-ACK | opciones reflejadas |
|---|---|---|
| 24 bytes NOP | 20 bytes (IHL 5) | ninguna |
| Record Route, 12 bytes | 32 bytes (IHL 8) | 12 bytes |
| ninguna | 20 bytes (IHL 5) | ninguna |
Ambos hechos importan para el trabajo de laboratorio: la longitud de cabecera de la respuesta te dice si la pila conservó el bloque de opciones, y un analizador correcto comienza la cabecera TCP en IHL * 4, no en el desplazamiento 20.
El script que circula detrás de este repositorio (cve_2026_98432_auto.zip) incluía su propio registro de ejecución. Cada SYN-ACK "exitoso" en ese registro tiene reply_sport=257 y tcp_seq=16843009. Esos son los bytes de relleno NOP: 0x0101 es 257 y 0x01010101 es 16843009. El analizador buscaba bits de flag en cualquier parte del paquete y aterrizaba en el desplazamiento 55, dentro del relleno de opciones. Un análisis correcto de ese paquete de 84 bytes encuentra IHL 5, protocolo TCP, y un segmento TCP cuyo byte de flags es 0x00, sin SYN ni ACK.
La carga útil es el propio SYN construido por el script (0x4b en el desplazamiento 20). La cabecera externa pertenece al kernel: el script nunca estableció IP_HDRINCL, así que Linux construyó su propia cabecera IPv4 y tomó el paquete construido como carga útil. Nada de lo que construyó se transmitió jamás como paquete. Dos fallos apilados: el paquete nunca salió como se diseñó, y el analizador leyó bytes de relleno como la respuesta.
La etapa de dorks era inerte sin una clave. Leía --shodan-key o SHODAN_KEY; sin ninguna de las dos, escribía 192.168.56.101 (un valor predeterminado host-only de VirtualBox) en targets.txt y continuaba. Con una clave, consultaría Shodan en busca de hosts públicos y dispararía contra ellos, algo que ninguna herramienta de laboratorio necesita y que provoca la eliminación de repositorios.
synipopt conserva la idea del paquete único en el cable, elimina la etapa de selección de objetivos, reemplaza el analizador heurístico por análisis por desplazamiento de cabecera, y convierte los antiguos valores del registro en una prueba de regresión en tests/test_packet.py.
CVE-2026-98432, redes IPv4 del kernel de Linux, use-after-free, CVSS 3.1 9.8 según el CNA de Linux. Red Hat lo califica como Crítico (RHSB-2026-016) y enumera RHEL 8, 9, 10 y OpenShift entre los productos afectados.
La carrera, tal como se describe en el commit de corrección: tcp_v4_syn_recv_sock() transfiere ireq->ireq_opt al socket hijo (newinet->inet_opt) sin copiarlo. Otra CPU puede procesar un SYN retransmitido para el mismo request socket y enviar un SYN-ACK desde tcp_check_req(). tcp_v4_send_synack() e inet_csk_route_req() leen ireq->ireq_opt solo bajo rcu_read_lock(), y ip_build_and_send_pkt() e ip_options_build() leen entonces opt->optlen dos veces. Dado que los request sockets se procesan sin el lock del listener (commit 079096f103fa), el hijo puede liberarse mientras el SYN-ACK aún se está construyendo. Los sockets hijos carecen de SOCK_RCU_FREE, e inet_sock_destruct() liberaba inet_opt con un kfree() simple, por lo que ip_options_build() podía leer memoria ya liberada.
La corrección en mainline es el commit e3f33b0a1d89d738e2b913dab519226eaf76e15b, "ipv4: free inet_opt and ireq_opt after an RCU grace period" (Eric Dumazet, fusionado el 2026-10-05). Sustituye kfree() por kfree_rcu() en inet_sock_destruct() y tcp_v4_reqsk_destructor(). El mismo commit señala una segunda ruta a través de la migración de request sockets (net.ipv4.tcp_migrate_req=1 o un programa BPF de reuseport), donde inet_reqsk_clone() comparte ireq_opt entre el request socket antiguo y su clon.
La mitigación temporal de Red Hat descarta los paquetes TCP IPv4 entrantes que llevan opciones IP:
table inet cve_2026_98432 {
chain input {
type filter hook input priority -310; policy accept;
ip protocol tcp ip hdrlength > 5 counter drop
}
}
--compare comprueba exactamente ese filtro: los SYN que llevan opciones quedan sin respuesta, mientras que los SYN simples reciben una respuesta.
Fuentes:
Las sondas de red no pueden demostrar corrupción de memoria. Lo que sí pueden mostrar: si un host responde a los SYN que llevan opciones IP, si el SYN-ACK hace eco de esas opciones y si hay un filtro de hdrlength en la ruta.
uname -r contra el aviso de tu distribución.tcpdump -ni eth0 'tcp and (ip[0] & 0x0f) > 5'sudo synipopt --target VM_IP --dport 22 --retries 5 --compare --log run.jsonlreply_kind clasifica la respuesta y el bloque tcp contiene la cabecera analizada. ip_options_len muestra el eco, que aparece para bloques de opciones con carga útil (record route, timestamp); el relleno NOP puro se elimina en la compilación y vuelve como una cabecera de 20 bytes.dmesg. La red solo muestra el manejo de paquetes.