Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
virtualbox_e1000_0day — Escape de invitado a anfitrión de VirtualBox E1000 | Kitploit
Herramientas/GitHubGitHub/mortenoir1/virtualbox_e1000_0day
Análisis de VulnerabilidadesExplotaciónPruebas de PenetraciónSeguridad de HardwareExplotación de Binarios
GitHubmortenoir1/virtualbox_e1000_0day

virtualbox_e1000_0day

Escape de invitado a anfitrión de VirtualBox E1000

Ver Repositorio
1.4k19622hace 7 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Por qué

Me gusta VirtualBox y no tiene nada que ver con por qué publico una vulnerabilidad 0day. La razón es mi desacuerdo con el estado contemporáneo de la infosec, especialmente de la investigación de seguridad y el bug bounty:

  1. Esperar medio año hasta que una vulnerabilidad sea parcheada se considera aceptable.
  2. En el campo del bug bounty se considera aceptable:
    1. Esperar más de un mes hasta que una vulnerabilidad enviada sea verificada y se tome la decisión de comprarla o no.
    2. Cambiar la decisión sobre la marcha. Hoy descubres que el programa de bug bounty comprará bugs en un software, una semana después llegas con bugs y exploits y recibes "no interesados".
    3. No tener una lista precisa del software en el que el bug bounty está interesado en comprar bugs. Cómodo para los programas de bug bounty, incómodo para los investigadores.
    4. No tener límites inferiores y superiores precisos de los precios de las vulnerabilidades. Hay muchas cosas que influyen en un precio, pero los investigadores necesitan saber en qué vale la pena trabajar y en qué no.
  3. Delirio de grandeza y marketing de mierda: nombrar vulnerabilidades y crear sitios web para ellas; hacer mil conferencias en un año; exagerar la importancia del propio trabajo como investigador de seguridad; considerarte "un salvador del mundo". Baja de la nube, Su Alteza.

Estoy agotado de los dos primeros, por lo que mi movimiento es la divulgación completa. Infosec, por favor avanza.

Información General

Software vulnerable: VirtualBox 5.2.20 y versiones anteriores.

SO anfitrión: cualquiera, el bug está en una base de código compartida.

SO invitado: cualquiera.

Configuración de la VM: predeterminada (el único requisito es que la tarjeta de red sea Intel PRO/1000 MT Desktop (82540EM) y el modo sea NAT).

Cómo protegerse

Hasta que salga la compilación de VirtualBox parcheada, puedes cambiar la tarjeta de red de tus máquinas virtuales a PCnet (a cualquiera de las dos) o a Paravirtualized Network. Si no puedes, cambia el modo de NAT a otro. La primera opción es más segura.

Introducción

Un dispositivo de red virtual predeterminado de VirtualBox es Intel PRO/1000 MT Desktop (82540EM) y el modo de red predeterminado es NAT. Nos referiremos a él como E1000.

El E1000 tiene una vulnerabilidad que permite a un atacante con privilegios de root/administrador en un invitado escapar al ring3 del anfitrión. Luego, el atacante puede usar técnicas existentes para escalar privilegios al ring 0 a través de /dev/vboxdrv.

Detalles de la Vulnerabilidad

E1000 101

Para enviar paquetes de red, un invitado hace lo que hace una PC común: configura una tarjeta de red y le suministra paquetes de red. Los paquetes son tramas de la capa de enlace de datos y otros encabezados de nivel superior. Los paquetes suministrados al adaptador se envuelven en descriptores Tx (Tx significa transmitir). El descriptor Tx es una estructura de datos descrita en la hoja de datos del 82540EM (317453006EN.PDF, Revision 4.0). Almacena metainformación como el tamaño del paquete, la etiqueta VLAN, los indicadores de segmentación TCP/IP habilitados, etc.

La hoja de datos del 82540EM contempla tres tipos de descriptores Tx: legacy, contexto y datos. Legacy está obsoleto, creo. Los otros dos se usan juntos. Lo único que nos importa es que los descriptores de contexto establecen el tamaño máximo de paquete y activan la segmentación TCP/IP, y que los descriptores de datos contienen las direcciones físicas de los paquetes de red y sus tamaños. El tamaño de paquete del descriptor de datos debe ser menor que el tamaño máximo de paquete del descriptor de contexto. Normalmente, los descriptores de contexto se suministran a la tarjeta de red antes que los descriptores de datos.

Para suministrar descriptores Tx a la tarjeta de red, un invitado los escribe en Tx Ring. Este es un búfer circular que reside en la memoria física en una dirección predefinida. Cuando todos los descriptores se han escrito en Tx Ring, el invitado actualiza el registro TDT MMIO del E1000 (Transmit Descriptor Tail) para indicar al anfitrión que hay nuevos descriptores que procesar.

Entrada

Considera el siguiente arreglo de descriptores Tx:``` [context_1, data_2, data_3, context_4, data_5]

Asignemos sus campos de estructura de la siguiente manera (los nombres de los campos son hipotéticos para que sean legibles por humanos, pero se asignan directamente a la especificación 82540EM):```
context_1.header_length = 0
context_1.maximum_segment_size = 0x3010
context_1.tcp_segmentation_enabled = true

data_2.data_length = 0x10
data_2.end_of_packet = false
data_2.tcp_segmentation_enabled = true

data_3.data_length = 0
data_3.end_of_packet = true
data_3.tcp_segmentation_enabled = true

context_4.header_length = 0
context_4.maximum_segment_size = 0xF
context_4.tcp_segmentation_enabled = true

data_5.data_length = 0x4188
data_5.end_of_packet = true
data_5.tcp_segmentation_enabled = true

Aprenderemos por qué deberían ser así en nuestro análisis paso a paso.

Análisis de la causa raíz

Procesamiento de [context_1, data_2, data_3]

Supongamos que los descriptores anteriores se escriben en el Tx Ring en el orden especificado y el registro TDT es actualizado por el invitado. Ahora el anfitrión ejecutará la función e1kXmitPending en el archivo src/VBox/Devices/Network/DevE1000.cpp (la mayoría de los comentarios se omiten y se omitirán en aras de la legibilidad):```c static int e1kXmitPending(PE1KSTATE pThis, bool fOnWorkerThread) { ... while (!pThis->fLocked && e1kTxDLazyLoad(pThis)) { while (e1kLocateTxPacket(pThis)) { fIncomplete = false; rc = e1kXmitAllocBuf(pThis, pThis->fGSO); if (RT_FAILURE(rc)) goto out; rc = e1kXmitPacket(pThis, fOnWorkerThread); if (RT_FAILURE(rc)) goto out; }

e1kTxDLazyLoad leerá los 5 descriptores Tx del anillo Tx. Luego se llama a e1kLocateTxPacket por primera vez. Esta función itera a través de todos los descriptores para establecer un estado inicial, pero no los maneja realmente. En nuestro caso, la primera llamada a e1kLocateTxPacket manejará los descriptores context_1, data_2 y data_3. Los dos descriptores restantes, context_4 y data_5, se manejarán en la segunda iteración del bucle while (cubriremos la segunda iteración en la siguiente sección). Esta división del arreglo en dos partes es crucial para desencadenar la vulnerabilidad, así que averigüemos por qué.

e1kLocateTxPacket se ve así:```c
static bool e1kLocateTxPacket(PE1KSTATE pThis)
{
...
    for (int i = pThis->iTxDCurrent; i < pThis->nTxDFetched; ++i)
    {
        E1KTXDESC *pDesc = &pThis->aTxDescriptors[i];
        switch (e1kGetDescType(pDesc))
        {
            case E1K_DTYP_CONTEXT:
                e1kUpdateTxContext(pThis, pDesc);
                continue;
            case E1K_DTYP_LEGACY:
                ...
                break;
            case E1K_DTYP_DATA:
                if (!pDesc->data.u64BufAddr || !pDesc->data.cmd.u20DTALEN)
                    break;
                ...
                break;
            default:
                AssertMsgFailed(("Impossible descriptor type!"));
        }

El primer descriptor (context_1) es de tipo E1K_DTYP_CONTEXT, por lo que se llama a la función e1kUpdateTxContext. Esta función actualiza un contexto de segmentación TCP si la segmentación TCP está habilitada para el descriptor. Esto es cierto para context_1, por lo que el contexto de segmentación TCP se actualizará. (Lo que realmente es la actualización del contexto de segmentación TCP no es importante, y lo usaremos solo para referirnos al código siguiente).

El segundo descriptor (data_2) es de tipo E1K_DTYP_DATA, por lo que se realizarán varias acciones innecesarias para la discusión.

Descargar herramienta