
Un PoC para CVE-2018-7249
Se descubrió un problema en secdrv.sys tal como se distribuye en Microsoft Windows Vista, Windows 7, Windows 8 y Windows 8.1 anteriores a KB3086255, y tal como se distribuye en Macrovision SafeDisc. Dos llamadas cuidadosamente sincronizadas al IOCTL 0xCA002813 pueden provocar una condición de carrera que deriva en un use-after-free. Cuando se explota, un atacante sin privilegios puede ejecutar código arbitrario en el kernel.
La vulnerabilidad fue reportada a Microsoft y, dado que no afecta a una máquina Windows actualizada (solo a versiones anteriores a KB3086255), no tomarán ninguna medida. Fue probada y explotada con éxito en Windows 7 x86.
También relacionada con CVE-2018-7250.

Esto documenta mi pequeña investigación sobre el controlador secdrv.sys. Todos los comportamientos descritos del controlador fueron obtenidos mediante ingeniería inversa y podrían ser incorrectos / inexactos.
El offset 0x4 del búfer de entrada al IOCTL (0x0CA002813) contiene un número que denominaré TYPE. La función principal del manejador de este IOCTL (0x0CA002813), sub_11A88, recibe 3 tipos diferentes: 0x96, 0x97 y 0x98.
Después de que el IOCTL de tipo 0x96 asignara un nuevo bloque y lo inicializara, pero no por completo, copia el bloque al modo usuario. 16 bits del bloque recién asignado no fueron inicializados y contienen datos de asignaciones PagedPool anteriores. Los bits no inicializados se copian luego al modo usuario en .text:00011BE9 mediante la instrucción REP MOVSD. Código PoC aquí.
Cuando se llama al IOCTL de tipo 0x97, encuentra el bloque necesario, que fue previamente asignado con el tipo 0x96, mediante su etiqueta. Si la asignación ya fue liberada por el IOCTL de tipo 0x97, DeviceIoControl devuelve un error. La vulnerabilidad aquí es que la asignación utilizada por el tipo 0x97 puede liberarse DURANTE su operación (ya que no se utilizan mecanismos de sincronización), quedando así en un estado de use-after-free si se gana la carrera. Si un atacante consigue liberar el bloque durante la operación del IOCTL de tipo 0x97 (usando el tipo 0x98) y asignar un nuevo bloque, controlado por él, en exactamente la misma ubicación de memoria, puede sobrescribir un puntero a otra estructura, que contiene un puntero a función que puede utilizarse para finalmente secuestrar el flujo de ejecución del controlador y ejecutar código arbitrario en el anillo 0. Debido a que la rutina de cifrado se ejecuta sobre un búfer proporcionado por el usuario, que puede ser de gran tamaño, el cifrado puede tardar mucho tiempo en ejecutarse, lo que proporciona una ventana de tiempo perfecta para que el IOCTL de tipo 0x98 libere el bloque mientras aún está en uso. Las ventanas de tiempo pueden ser tan largas (¡más de 1 segundo!) que la carrera puede ganarse de forma fiable al primer intento. El use-after-free comienza en .text:00011B68, y la llamada real, que será secuestrada para saltar al shellcode, ocurre en .text:00011B86.
Los pasos llevados a cabo para explotar esta vulnerabilidad con éxito son los siguientes:
OS: Windows 7 Kernel Version 7600 MP (1 procs) Free x86 compatible Built by: 7600.16385.x86fre.win7_rtm.090713-1255 VM: 4GB RAM, 1 CPU Hardware: Windows 10 Pro 64 bit, Placa base Gigabyte Z370 HD3, 16GB RAM, Intel i5-8400 2.80GHz (6 CPUs)