
Exploit de prova de conceito para CVE-2022-37969, uma escalada de privilégio local do driver do Windows Common Log File System. Demonstra heap spray, roubo de token e gravação arbitrária no kernel para obter privilégios de SYSTEM.
autores: Ricardo Narvaja & Daniel Kazimirow (Solid)
Apenas para fins de demonstração. O exploit completo funciona em sistemas Windows 11 21H2 vulneráveis.
PoC funcional baseado em informações publicadas anteriormente pela Zscaler
Confira o writeup Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation.
Passo a passo da exploração:
O cenário utilizado aqui foi Windows 11 21H2 (OS Build 22000.918) clfs.sys v10.0.22000.918
O primeiro passo é criar um arquivo chamado MyLog.blf na pasta pública (%public%), usando a função CreateLogFile():



Em seguida, cria vários arquivos de log com nomes aleatórios usando um loop.
E dentro do loop, chama nossa função getBigPoolInfo():

Ele chama a função NtQuerySystemInformation(), com 0x42 (66 decimal) como primeiro argumento, isso retornará em v5 as informações sobre os raids feitos no bigpool, cuja estrutura é do tipo SYSTEM_BIGPOOL_INFORMATION.

Temos que chamar essa função duas vezes. A primeira retornará um erro, mas nos dará o tamanho correto do buffer para chamar a segunda vez e obter as informações desejadas.

v5 receberá as informações da estrutura SYSTEM_BIG_POOL_INFORMATION.

O número de alocações no bigpool é armazenado no primeiro campo chamado Count, no segundo campo há um array de estruturas SYSTEM_BIGPOOL_ENTRY.

Então percorremos todas as estruturas em busca da tag "Clfs" e do tamanho 0x7a00.

Armazena em um array chamado kernelAddrArray o VirtualAddress, que é o primeiro campo de cada estrutura que possui a tag CLFS e tamanho 0x7a00. A partir de agora, os pools que atendem ambas as condições serão chamados de “pools certos”.

Além de armazenar cada pool certo no array, armazena o último pool certo encontrado no conteúdo da variável a2, que é usada como argumento da função.

Dessa forma, a2 sempre aponta para o último pool certo com a tag CLFS e tamanho 0x7a00 criado.
A variável v26 sempre armazena o pool certo anterior encontrado, pois é igual a v24 (v26=v24), antes de chamar getBigPoolinfo(), mas v24 é atualizado ao sair dessa chamada com o último pool certo encontrado, e v26 permanece com o pool certo anterior encontrado.

Em seguida, subtrai ambos os endereços e, caso o resultado seja negativo, inverte os operandos para que seja sempre positivo.

Dessa forma, em v32 será armazenada a diferença entre o VirtualAddress dos dois últimos pools certos encontrados.
Depois faz algo semelhante; neste caso, v23 é inicialmente zero, então faz v23 = v32 na primeira vez.

Na próxima vez no loop, v23 ainda tem o mesmo valor e não é zero, então interrompe e vai para cá.

V32 tem a última diferença e v23 a anterior; se forem iguais, sai e incrementa um, mas redefine o contador para zero.
A ideia é encontrar 6 comparações consecutivas de tags CLFS e tamanho 0x7a00 cujas diferenças sejam iguais, e essa diferença será 0x11000. Veremos ao executar que quando encontrar 6 (pois começa do zero) consecutivos com distâncias iguais, dará esse valor de diferença entre eles.


Ali vemos que ele encontrou 6 consecutivos e saiu do loop de criação de arquivos de log.
Na pasta "public" podemos ver os arquivos criados

Nossa função craftFile() abre o arquivo original (MyLog.blf) e o modifica para acionar o bug.

Após modificar o arquivo, é necessário alterar o CRC32, caso contrário, receberemos um erro de arquivo corrompido.
Esse valor está localizado no offset 0x80C do arquivo.