
Um PoC para CVE-2018-7249
Foi descoberto um problema no secdrv.sys, conforme distribuído no Microsoft Windows Vista, Windows 7, Windows 8 e Windows 8.1 antes do KB3086255, e conforme distribuído no Macrovision SafeDisc. Duas chamadas cuidadosamente temporizadas ao IOCTL 0xCA002813 podem causar uma condição de corrida que leva a um use-after-free. Quando explorado, um atacante sem privilégios pode executar código arbitrário no kernel.
A vulnerabilidade foi reportada à Microsoft e, como não afeta máquinas Windows atualizadas (apenas versões anteriores ao KB3086255), eles não tomarão nenhuma providência. Foi testada e explorada com sucesso no Windows 7 x86.
Também relacionada ao CVE-2018-7250.

Este documento documenta minha pequena pesquisa sobre o driver secdrv.sys. Todos os comportamentos descritos do driver foram obtidos por engenharia reversa e podem estar incorretos/imprecisos.
O deslocamento 0x4 do buffer de entrada para o IOCTL (0x0CA002813) contém um número que chamarei de TIPO. A função principal de manipulação deste IOCTL (0x0CA002813), sub_11A88, recebe 3 tipos diferentes: 0x96, 0x97 e 0x98.
Após a alocação de um novo bloco pelo IOCTL tipo 0x96 e sua inicialização, mas incompleta, ele copia o bloco para o modo de usuário. 16 bits no bloco recém-alocado não foram inicializados e contêm dados de alocações anteriores de PagedPool. Os bits não inicializados são então copiados para o modo de usuário em .text:00011BE9 pela instrução REP MOVSD. Código PoC aqui.
Quando o IOCTL tipo 0x97 é chamado, ele encontra o bloco necessário, que foi previamente alocado com o tipo 0x96, por sua tag. Se a alocação já tiver sido liberada pelo IOCTL tipo 0x97, DeviceIoControl retorna um erro. A vulnerabilidade aqui é que a alocação usada pelo tipo 0x97 pode ser liberada DURANTE sua operação (já que nenhum mecanismo de sincronização é usado), sendo assim usada após liberada se a corrida for vencida. Se um atacante conseguir liberar o bloco durante a operação do IOCTL tipo 0x97 (usando o tipo 0x98) e alocar um novo bloco, controlado por ele, exatamente na mesma posição de memória, ele pode sobrescrever um ponteiro para outra estrutura, que contém um ponteiro de função que pode ser usado para, finalmente, sequestrar o fluxo de execução do driver e executar código arbitrário no ring 0. Como a rotina de criptografia é realizada em um buffer fornecido pelo usuário, que pode ser enorme, a criptografia pode levar muito tempo para ser executada, fornecendo assim uma janela de tempo perfeita para o IOCTL tipo 0x98 liberar o bloco enquanto ainda está em uso. As janelas de tempo podem ser tão longas (mais de 1 segundo!) que a corrida pode ser vencida de forma confiável na primeira tentativa. O use-after-free começa em .text:00011B68, e a chamada real, que será sequestrada para pular para o shellcode, ocorre em .text:00011B86.
As etapas tomadas para explorar com sucesso esta vulnerabilidade são as seguintes:
SO: 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, Motherboard Gigabyte Z370 HD3, 16GB RAM, Intel i5-8400 2.80GHz (6 CPUs)