
Exploit remoto do Sistema de Arquivos de Rede do Windows para CVE-2022-30136
autor: Ricardo Narvaja
Apenas para fins de demonstração. O exploit completo funciona em sistemas Windows Server vulneráveis.
Consulte o artigo Análise da CVE-2022-30136 “Vulnerabilidade do Windows Network File System”.
Eu queria escrever este artigo para demonstrar a análise que fiz durante o desenvolvimento do exploit “Windows Network File System Remote” do Core Impact, que abusa da vulnerabilidade CVE-2022-30136.
A vulnerabilidade de execução remota de código no Windows Network File System é um erro de cálculo de tamanho que ocorre ao criar a resposta do servidor em uma COMPOUND REQUEST usando a versão 4.1 do NFS.
O servidor calcula um tamanho menor do que o necessário para alocar o pool e, em seguida, ao copiar os dados para gerar a resposta, estoura o buffer.
A função Nfs4SvrXdrpGetEncodeOperationResultByteCount em nfssvr.sys é chamada para cada operação e retorna um tamanho menor do que o necessário (4 bytes a menos para cada operação).
Foi feito um patch para Nfs4SvrXdrpGetEncodeOperationResultByteCount.
Essa função é chamada durante cada OPERATION de uma COMPOSE REQUEST para que retorne os bytes necessários para cada uma delas com base no OPCODE. O valor retornado é então adicionado ao cabeçalho e a outras partes da resposta. Depois, calcula o tamanho final de toda a resposta a ser alocada e então copia para ela a resposta.
Em cada caso, podemos ver que o valor do tamanho retornado para cada operação é quatro bytes menor na versão vulnerável do que na versão corrigida.
Eu criei o POC para Windows Server 2019.
Abaixo está a versão vulnerável do nfssvr.sys usada para este POC, seguida pela versão corrigida para o Windows Server 2019:

A próxima imagem mostra o CASE 26 no diff:

No exemplo do CASE 26, podemos ver que a constante adicionada ao valor calculado é 0x2c na versão vulnerável e 0x30 na versão corrigida.
O mesmo pode ser visto em cada caso correspondente a cada OPCODE. A versão vulnerável sempre retorna um tamanho quatro bytes menor do que a corrigida.
Não vamos mostrar todos os casos porque o patch é semelhante para todos os OPCODES.
O pai de Nfs4SvrXdrpGetEncodeOperationResultByteCount é Nfs4SvrXdrEncodeCompoundResults. Ele lê o número de operações enviadas na COMPOUND REQUEST.
Neste POC, o valor é 0x34 (52d). Quando meu POC se conecta ao servidor na porta 2049 (a porta padrão do NFS), preciso definir um breakpoint condicional para parar.


Neste caso, ele para quando number_of_operations=0x34.

O pool com a tag ARGS é alocado aqui.

Em seguida, criarei uma estrutura chamada TAG_ARGS_0x10e0 para reverter os campos.

Ele copia o number_of_operations para r13 e faz um loop na função vulnerável uma vez por operação, até que o contador alcance o valor de r13.

Ele mostra que o primeiro package_OPCODE = 0x35, que corresponde a SEQUENCE na primeira operação obrigatória em uma COMPOUND REQUEST. Na imagem abaixo, a seta aponta para esse OPCODE no meu pacote.

Aqui podemos ver os argumentos da função vulnerável.


Dentro da função vulnerável, ela lê o OPCODE e vai para o CASE correspondente.

Três é subtraído do valor original do OPCODE (53).

E salta para o CASE 50, retornando 0x28 como o tamanho necessário para esta operação.


Podemos ver no diff como a versão corrigida retorna 0x2c.

Esse valor retornado é adicionado ao valor anterior de outros campos da resposta para calcular o tamanho das operações. Neste caso, esse valor é 0X40c.

Abaixo podemos ver os valores sendo adicionados:

Quando sai do loop, o tamanho total é calculado. Neste caso, o tamanho total é 0x1310.

Podemos deduzir a diferença entre a versão vulnerável e a versão corrigida calculando o tamanho, usando a fórmula: number_of_operations * 4.
Neste caso, a alocação na versão corrigida será 0x34 * 4 = 0x68 maior do que na versão vulnerável.

Depois disso, ele adiciona 0x24. Esse valor é calculado de forma semelhante nas versões vulnerável e corrigida.

Em seguida, adiciona a constante 0xf em ambos os casos.

Até este ponto, o tamanho neste exemplo foi 0x1340.

Em seguida, chega a rpcxdr_OncRpcBufMgrpAllocate.

Em seguida, passa para r15.
