Imagem: UnsplashConforme descrito em um
artigo anterior sobre o
CVE-2019-0726 , às vezes, pesquisar detalhes sobre uma vulnerabilidade já conhecida leva à descoberta de uma nova vulnerabilidade. E, em alguns casos, há mais de uma nova vulnerabilidade.
O artigo analisou duas funções da biblioteca dhcpcore.dll: o UpdateDomainSearchOption mencionado anteriormente e uma análise mais detalhada do DecodeDomainSearchListData que ele chama. Como sempre acontece ao procurar vulnerabilidades, mesmo que conclusões importantes no final se resumam a uma ou duas funções, no processo de análise, você deve observar uma quantidade muito maior de código. E, às vezes, os olhos se apegam a insignificâncias que não estão relacionadas à tarefa atual, mas que podem ter um significado independente ou serem úteis mais tarde. Suponha que, no momento, não haja tempo para prestar atenção a eles, mas esses insignificantes sejam adiados no subcórtex e, se após um certo período de tempo, houver uma oportunidade de retornar a eles e verificar suas suposições, eles novamente aparecerão em consciência.
E assim aconteceu desta vez. Ao estudar a função DhcpExtractFullOptions, responsável por processar todas as opções especificadas na resposta DHCP do servidor, em particular, chamando UpdateDomainSearchOption, duas matrizes na pilha de 256 elementos cada uma chamam a atenção imediatamente:

Ao mesmo tempo, a presença de qualquer verificação que restrinja os valores dos iteradores dessas matrizes não é perceptível. Como naquele momento estávamos analisando outra vulnerabilidade, essa informação não era relevante. Portanto, resta apenas lembrar esse lugar no código para retornar a ele mais tarde.
Análise
Algumas semanas se passaram e, novamente, lembramos da função DhcpExtractFullOptions que havia atraído atenção anteriormente. Nós nos voltamos para ele no desmontador, vasculhamos trechos de código anteriormente incompletos e tentamos entender por que estamos usando duas matrizes estáticas que nos intrigaram.
No início da execução da função, matrizes e seus iteradores são zerados:

A função analisa todas as opções no pacote recebido do servidor DHCP, coleta informações delas e as processa. Além disso, de acordo com os resultados da análise, ela também grava o evento correspondente no serviço ETW (Event Tracing for Windows). É no registro de eventos que os buffers de nosso interesse participam. Juntamente com muitos outros dados, eles são transferidos para o procedimento EtwEventWriteTransfer. O trabalho de preparar todos os dados para o log é bastante volumoso e não importa muito para a vulnerabilidade que estamos considerando, para que possamos fazer sem ilustrações.
É mais importante determinar como esses buffers são preenchidos. O preenchimento ocorre no loop de análise de opções. Primeiro, uma função com o nome falante ParseDhcpv4Option é chamada para a opção atual recebida para processamento, que preenche os campos do objeto dhcp_pointers com base nos dados recebidos ou anota uma opção desconhecida quando encontra um identificador de opção com um valor para o qual não há manipulador.

Ao retornar de ParseDhcpv4Option, o valor identificador da atual option_tag é gravado no próximo elemento da matriz all_tags, a primeira das matrizes de interesse para nós. Se a função encontrou uma opção desconhecida e, consequentemente, não definiu o sinalizador is_known_option, o valor do identificador também será gravado no próximo elemento da segunda matriz - unknown_tags. Naturalmente, os nomes significativos das variáveis neste artigo já foram obtidos através da análise do código.
Portanto, a matriz all_tags armazena tags de todas as opções da mensagem recebida, e a matriz unknown_tags armazena tags apenas para opções desconhecidas do analisador. Ao mesmo tempo, não há nenhuma verificação dos valores de índice dessas matrizes. Conseqüentemente, os valores desses índices podem exceder 256 e levar à gravação além dos limites alocados na pilha para matrizes de memória. Para preencher demais a primeira matriz, basta enviar um pacote com o número de opções superior a 256 do servidor DHCP O mesmo vale para a segunda matriz, com a única diferença: as opções que o cliente não pode processar devem ser enviadas.
Operação
Vamos agora tentar usar um exemplo prático para garantir que nossas conclusões estejam corretas. Para começar, prestamos atenção ao fato de que as tags de opção ocupam um byte, enquanto os elementos da matriz são do tipo int, ou seja, são de quatro bytes. Assim, temos um estouro no qual controlamos cada quarto byte, e o restante é redefinido para zero ao substituir.

Para testar nossa suposição, a maneira mais fácil é substituir o cookie de segurança na função em questão, o que gerará uma exceção relacionada à verificação de segurança. Vamos simular uma situação em que o servidor DHCP envia um número suficiente de opções para reescrever. Seja 0x1a0 (416) opções com o identificador 0xaa e tamanho zero. Assim, cada opção ocupa dois bytes e o tamanho total do pacote com todos os cabeçalhos é de 1100 a 1200 bytes. Esse valor está dentro do
MTU para Ethernet, portanto, há motivos para acreditar que a mensagem não será fragmentada, o que permitirá evitar possíveis efeitos adversos.
Enviamos o pacote formado da maneira descrita em resposta a uma solicitação do cliente DHCP e capturamos a exceção no processo svchost.exe correspondente na máquina cliente:

Como você pode ver no rastreamento da pilha, o cookie da pilha e o endereço de retorno da função foram reescritos pelos identificadores das opções do nosso pacote.
Obviamente, criar uma exploração funcional para esse erro exigirá muito esforço do invasor. Nos sistemas modernos, o estouro de buffer na pilha é uma vulnerabilidade bastante complexa e trabalhosa devido a todos os mecanismos de defesa existentes. Por outro lado, não se deve esquecer que todos esses mecanismos protegem contra a substituição do endereço de retorno e manipuladores de exceção, ou proíbem a execução de código em regiões de memória não destinadas a isso ou interferem na previsão de endereço. Por exemplo, eles não podem ajudar de forma alguma contra a substituição dos armazenados na pilha entre o buffer excedido e o endereço de retorno das variáveis locais. E a função DhcpExtractFullOptions em questão contém várias variáveis potencialmente perigosas nesse intervalo.
Novamente, escrevemos para a Microsoft sobre o erro detectado. Após uma breve correspondência e uma análise do aplicativo, que levou cerca de uma semana, obtemos a resposta de que um identificador CVE está sendo preparado para a vulnerabilidade descrita, uma correção está planejada para lançamento em março e as informações sobre a vulnerabilidade já estão disponíveis na Microsoft, foram relatadas por alguém anteriormente. De maneira geral, o fato não é surpreendente, porque o erro está literalmente na superfície, e os buffers que não contêm verificações de limites dos índices sempre atraem a atenção primeiro e podem ser detectados com frequência pelas ferramentas de análise automática.
Em março, como foi anunciado, foi lançada uma atualização para corrigir o erro descrito, que recebeu o identificador
CVE-2019-0697 . O pesquisador relatado anteriormente era Mitch Adair, o mesmo funcionário da Microsoft que descobriu a vulnerabilidade DHCP
CVE-2019-0547 corrigida em janeiro.
Postado por Mikhail Tsvetkov, especialista em análise de aplicativos da Positive Technologies.