Explotación del heap de paquetes NAT de VirtualBox Slirp
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
TL;DR
- VirtualBox incluye un fork fuertemente modificado de Slirp cuyos buffers de paquetes (mbufs) residen en un asignador de zonas personalizado con metadatos en línea y callbacks por puntero a función (
pfFini,pfDtor). - Un invitado puede reescribir el confiable
m->m_lencon una longitud de encabezado IP controlada por el atacante, lo que invalida todas las comprobaciones de límites posteriores y proporciona primitivas tanto de infoleak como de overwrite. - Abusando de paquetes UDP con checksum
0yip_lensobredimensionado, el invitado puede exfiltrar mbuf tails y los metadatos de chunks vecinos para obtener las direcciones del heap y de la zona. - Proveer opciones IP manipuladas fuerza a
ip_stripoptions()amemcpy()demasiados datos in-place, por lo que el atacante puede sobrescribir elstruct itemheader del siguiente mbuf y apuntar su campozonea datos totalmente controlados. - Liberar el mbuf corrupto desencadena
zone->pfFini()con argumentos suministrados por el atacante; apuntarlo amemcpy@pltproporciona una primitiva arbitraria de copy/write que puede dirigirse hacia entradas GOT u otros datos de control dentro del binario de VirtualBox no-PIE.
Anatomía del asignador de paquetes
VirtualBox asigna cada trama Ethernet entrante desde una zona por interfaz llamada zone_clust. Cada chunk de datos de 0x800 bytes va precedido por un encabezado en línea:
struct item {
uint32_t magic; // 0xdead0001
void *zone; // uma_zone_t pointer with callbacks
uint32_t ref_count;
LIST_ENTRY(item) list; // freelist / used list links
};
Cuando se libera un mbuf, la pila de llamadas m_freem -> ... -> slirp_uma_free() confía en el encabezado inline:
uma_zfree_arg()recomputaitem = (struct item *)mem - 1y debería validaritem->zone, peroAssert()está omitido en compilaciones release.slirp_uma_free()cargazone = item->zoney ejecuta incondicionalmentezone->pfFini(zone->pData, data_ptr, zone->size)seguido dezone->pfDtor(...).
Por lo tanto, cualquier write-what-where en el encabezado del mbuf se traduce en una llamada indirecta controlada durante free().
Infoleak a través de m->m_len override
Al inicio de ip_input(), VirtualBox añadió:
if (m->m_len != RT_N2H_U16(ip->ip_len))
m->m_len = RT_N2H_U16(ip->ip_len);
Porque la asignación ocurre antes de verificar el encabezado IP, un guest puede anunciar cualquier longitud hasta 0xffff. El resto de la pila (ICMP, UDP, manejadores de fragmentación, etc.) asume que m->m_len es fiable y lo usa para decidir cuántos bytes copiar del mbuf.
Use paquetes UDP con checksum 0 (que significa “no checksum”). El NAT fast-path reenvía m->m_len bytes sin inspeccionar la integridad de la payload, así que inflar ip_len hace que Slirp lea más allá del buffer real y devuelva residuos del heap al guest o a un helper externo cooperante más allá del NAT. Debido a que el tamaño del chunk es 2048 bytes, el leak puede incluir:
- El
struct iteminline del siguiente mbuf, revelando el orden del freelist y el puntero realzone. - Heap cookies como los campos
magic, que ayudan a crear cabeceras de apariencia válida al realizar corrupciones más adelante.
Sobrescribir cabeceras de chunks vecinos con IP options
La misma longitud falsa puede convertirse en un primitivo de overwrite forzando que el paquete pase por ip_stripoptions() (se dispara cuando el encabezado IP tiene options y la carga útil es UDP/TCP). El helper calcula una longitud de copia a partir de m->m_len y luego llama a memcpy() para desplazar el transport header sobre las opciones eliminadas:
- Proporcionar un
ip_lengrande de modo que la longitud de movimiento computada se extienda más allá del mbuf actual. - Incluir un pequeño número de IP options para que Slirp entre en la ruta de stripping.
- Cuando
memcpy()se ejecuta, lee desde el mbuf siguiente y escribe sobre la payload y el inline header del mbuf actual, corrompiendomagic,zone,ref_count, etc.
Porque el allocator mantiene los paquetes de la misma interfaz contiguos en el freelist, este overflow golpea determinísticamente el siguiente chunk tras un modesto heap grooming.
Forjar uma_zone_t para secuestrar pfFini
Una vez que el struct item adyacente es corruptible, el exploit procede de la siguiente forma:
- Usar direcciones de heap leaked para construir una estructura falsa
uma_zonedentro de un mbuf totalmente controlado por el guest. Rellenar:
pfFinicon la entrada PLT dememcpy().pDatacon el puntero de destino deseado (p.ej. entrada GOT, slot de vtable, array de punteros a funciones).sizecon el número de bytes a copiar.- Opcional:
pfDtorcomo llamada de segunda etapa (p.ej. para invocar el puntero a función recién escrito).
- Sobrescribir el campo
zonedel mbuf objetivo con el puntero a la estructura falsa; ajustar los punteroslistpara que la contabilidad del freelist permanezca lo bastante consistente como para evitar crashes. - Liberar el mbuf.
slirp_uma_free()ahora ejecutamemcpy(dest=pData, src=item_data, n=size)mientras el mbuf aún contiene datos controlados por el guest, produciendo una escritura arbitraria.
Puesto que el binario Linux de VirtualBox es non-PIE, las direcciones PLT para memcpy y system son fijas y pueden usarse directamente. El guest también puede almacenar cadenas como /bin/sh dentro de otro mbuf que permanezca referenciado cuando la llamada secuestrada se ejecute.
Heap grooming via fragmentation
La zona por-interfaz de Slirp tiene 3072 chunks de profundidad y inicialmente se talla como un array contiguo cuyo freelist se recorre desde direcciones altas hacia abajo. Se puede lograr adyacencia determinista mediante:
- Inundar el NAT con muchos fragmentos
IP_MFde tamaño constante para que el código de reensamblado asigne secuencias de mbufs predecibles. - Reciclar chunks específicos enviando fragments que expiren, forzando frees de vuelta al freelist en orden LIFO.
- Usar el conocimiento del recorrido del freelist para colocar el futuro mbuf víctima justo después del mbuf que llevará el overflow de IP options.
Este grooming asegura que el overflow golpee el struct item objetivo y que la uma_zone falsa permanezca dentro de los límites del leak primitive.
From arbitrary write to host code execution
Con el memcpy-on-free primitive:
- Copiar una cadena
/bin/shcontrolada por el atacante y un buffer de comandos en un mbuf estable. - Usar el primitive para sobrescribir una entrada GOT o un callsite indirecto (p.ej. un puntero a función dentro del estado del dispositivo NAT) con la entrada PLT de
system(). - Disparar la llamada sobrescrita. Puesto que VirtualBox ejecuta el dispositivo NAT dentro del proceso del host, el payload se ejecuta con los privilegios del usuario que ejecuta VirtualBox, permitiendo un guest-to-host escape.
Payloads alternativos incluyen plantar una mini ROP chain en la memoria heap y copiar su dirección en un callback invocado frecuentemente, o reapuntar pfFini/pfDtor ellos mismos a gadgets encadenados para escrituras repetidas.
Referencias
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


