Segurança de Aplicação

CVE-2012-5905 De Negação de Serviço à Execução de Código Remoto

Antes de qualquer coisa vale salientar que esse artigo é inteiramente didático e, apesar do aplicativo em questão apresentar vulnerabilidades que possam comprometer a segurança de sistemas, acredita-se que o mesmo não seja utilizado como serviço pelo fato de possuir outras vulnerabilidades públicas não corrigidas e o projeto não possuir continuidade. De qualquer forma o autor ou a Conviso® não se responsabilizam pela má utilização do material aqui contido.

Introdução

Encontrar vulnerabilidades e subverter sistemas é sem via de dúvidas algo extremamente divertido e que exige um conhecimento especializado tanto do ambiente quanto do alvo a ser explorado. Porém, o que para uns é pura diversão, para outros é meta de produtividade no serviço. A exploração completa de um software passa por uma fase complexa de análise com o intuito de transformar falhas corriqueiras (bugs) em potenciais vulnerabilidades. Porém, devido a pressão exercida por órgãos superiores (chefes, clientes etc) que desejam simplesmente ver quaisquer resultados, diversos especialistas divulgam suas descobertas como simples crash na aplicação e coloca como único princípio de risco a quebra da disponibilidade através de ataques de Negação de Serviço (DoS – Denial of Service), quando na verdade não foi possível fazer uma análise detalhada em busca de transformar um simples crash em uma vulnerabilidade. Então é registrado uma falha em um software, é definido um CVE-ID para ela[0] e os superiores ficam felizes, pois afinal de contas foi apresentado um resultado no prazo. Como exemplo do citado, temos um tópico anterior[1] onde o analista e pesquisador Ricardo Silva transforma um bug público registrado como Negação de Serviço em uma vulnerabilidade de execução remota de código potencialmente perigosa.  

Este artigo visa analisar o CVE-2012-5905[2] que indica um simples ataque de Negação de Serviço, e provar que a vulnerabilidade consistia em execução remota de código (RCE).

Análise do CVE-2012-5905

De acordo com o CVE-2012-5905, foi encontrado uma vulnerabilidade de buffer overflow no software KnFTPd[3] que permite um usuário autenticado indisponibilizar o serviço através de um ataque de negação de serviço através do comando FEAT

Para iniciar a análise foi feito uma simples avaliação no processo a partir da chamada à API WS2_32.recv(), responsável por ler informações em um socket. De acordo com a Figura 1, existem duas chamadas a essa API. Para não prolongar muito o artigo foi feito a análise somente da chamada que já se sabe ser a responsável pela recepção dos comandos.

 

 

 Figura 1: Lista de chamada

Na Figura 2 é possível ver a chamada à API WS2_32.recv() com um buffer de tamanho 0x1000 e com os dados recebidos armazenados no local apontado pelo registrador EBX. Em seguida o registrador EBX juntamente com o registrador ESI são utilizado como parâmetros da função localizada em knftpd.00401CA8, que será analisada a seguir.

 
 
 
Figura 2: Recebimento no socket

 

Na função localizada em knftpd.00401CA8, após o prólogo, é possível ver uma chamada para a função sscanf() com o parâmetro de formatação “%s” (vide Figura 3). Essa chamada é utilizada para obter o primeiro token do buffer recebido no socket. É importante lembrar que a formatação “%s” define como token qualquer sequência de caractere até uma quebra de linha, um espaço, uma tabulação ou o caractere nulo.

 
 
Figura 3: Parsing do comando FTP

 

Ainda na mesma rotina é possível notar a utilização da função strchr() com o objetivo de localizar o caractere de espaço (0x20 em hexadecinal) no buffer (Figura 4).

 
Figura 4: Obtenção do espaço separador
 
 
 
 
 
 

Tendo obtido o endereço do espaço no buffer recebido pelo socket, a função analisada utiliza o restante do buffer como parâmetro da função strcpy(), que é potencialmente insegura por não fazer qualquer verificação de limite na variável de destino. Como o usuário consegue manipular os dados de origem, é provável que este seja um exemplo de buffer overflow. código que apresenta a chamada à função strcpy() pode ser visto na Figura 5.

 
 

 

Figura 5: Chamada a função insegura strcpy()


Com isso já é possível escrever um código de prova de conceito (p0c) para que possamos analisar o comportamento da aplicação quando passarmos como parâmetro do comando uma cadeia de caracteres razoavelmente grande. O código foi escrito em Python e pode ser visto na Figura 6. O código em questão simplesmente autentica no sistema e passa um parâmetro grande para o comando FEAT.

Figura 6:  Código para prova de conceito#1.
 

É importante notar que a análise feita foi desde a leitura do socket através da API WS2_32.recv() até a chamada à função strcpy() e que em momento algum foi feito a checagem de qual comando foi passado. Com isso cogita-se que a vulnerabilidade esteja presente não no comando FEAT, mas sim em qualquer buffer que seja transmitido como duas palavras separadas por um espaço. Para comprovar isso experimente trocar o comando FEAT no código por qualquer outro comando FTP ou até mesmo por comandos que não existam no protocolo. 

Após a execução do código o resultado foi o visto na Figura 7. Como esperado, houve um transbordo do buffer e foi possível sobrescrever áreas da memória que posteriormente influenciarão em registradores como o EIP, responsável por armazenar o endereço da próxima instrução a ser executada.

 
Figura 7:  Controle de EIP (0x41414141)
 

No momento do estouro de memória, o registrado EBP ficou apontado para regiões do buffer que podemos manipular (Figura 8). Além disto, é possível notar que perdemos parte do começo de nosso buffer e que ainda podemos sobrescrever alguns bytes antes de tomarmos uma exceção de violação de acesso à memória (não estamos explorando por sobrescrita de SEH).

 
Figura 8: Visualização de ESP no dump
 
 

O próximo passo será descobrir em qual offset é sobrescrito o EIP em qual offset o registrado ESP aponta dentro da região que conseguimos manipular. Para isso podemos utilizar o script pattern_create.rb, presente no Metasploit Framework, que gera um cadeia de caracteres de forma que não exista uma sequência de padrão único, para substituir nossa sequência de A’s no exploit inicial. O resultado do comando e a alteração do código podem ser vistos na Figura 9 e na Figura 10.

 
Figura 9: Utilização do pattern_create do Metasploit Framework
 

 Como foi analisado que ainda possuíamos um espaço antes de atingir uma região da memória que geraria uma exceção, o buffer que inicialmente possuía 300 bytes passou a possuir 350 bytes.

 
Figura 10: Código para prova de conceito #2
 
 
 
 

 

Após a execução desse código, o programa parou a execução com os registradores no estado visto na Figura 11.

 
 
Figura 11: Registradores
 
 

Tendo o valor presente no registrador EIP e os bytes iniciais de onde o registrador ESP aponta é possível utilizar o script pattern_offset.rb para saber a posição exata desses valores dentro do buffer utilizado para a exploração da aplicação. O resultado, de acordo com a Figura 12 é o registrador EIP sendo sobrescrito a partir do offset 284 e o registrador EBP estando apontando para o buffer a partir do offset 292.

 
Figura 12: Utilização do pattern_offset.rb do Metasploit Framework

 Nossa melhor referência na análise é o registrador ESP, que aponta para uma região que podemos manipular. Porém, como o buffer só possui 350 bytes, ao referenciar este registrador só possuímos 58 bytes para nosso payload, o que não seria suficiente para uma exploração real; enquanto que temos quase 300 bytes no começo do buffer, o que seria suficiente para um payload completo ou pelo menos o primeiro estágio de um payload maior (multi-staged).

Para contornar essa limitação, utilizamos os 58 bytes para armazenar um EggHunter[4][5] que irá localizar o payload inserido no começo do buffer, e nosso endereço de retorno irá apontar para alguma rotina que altere o fluxo de execução com um endereço relativo ao registrador ESP. Dessa forma, o payload total deve possuir o formato da Figura 13 abaixo.

 
Figura 13: Formato do payload
 
 
 

Para uma simples demonstração antes de mostrar o payload final, o código do exploit foi alterado respeitando o formato descrito na Figura 13. O resultado do código pode ser visto na Figura 14.

 
 
Figura 14: Código para prova de conceito #3
 
 
 

O resultado da análise pode ser comprovada na Figura 15, onde é possível notar que, como esperado o registrador EIP é sobrescrito com o valor 0x42424242 equivalente a cadeia BBBB e o registrador ESP aponta para o começo da sequência dos caracteres D (0x44 em hexadecimal).

 
Figura 15: Análise do crash (registradores e memória)
 
 
 

Como dito anteriormente, o endereço de retorno deve ser sobrescrito para uma instrução que salta para onde o registrador ESP está apontando, por essa ser uma região manipulável. As instruções mais comuns para isso são PUSH ESP + RET ou um simples JMP ESP. O ideal seria achar essas instruções (ou equivalentes) dentro do próprio módulo do programa, pois assim o exploit final funcionaria independente de plataforma utilizada. Porém, a fim de reduzir o tempo de análise, a instrução obtida foi tirada do módulo USER32.DLL, o que torna o exploit funcional somente na plataforma utilizada (Microsoft Windows XP SP3 – English) e é necessário a adaptação em algumas situações. A Figura 16, apresenta a instrução que será utilizada durante a exploração.

 
Figura 16: JMP ESP em USER32
 
 
 
 
 

O payload final com nop-sled, shellcode, endereço de retorno e egghunter pode ser visto na Figura 17, e o exploit completo pode ser obtido em [6].

 
 
Figura 17:  Payload final
 
 
 

Conclusão

Este artigo demonstrou que, por razões diversas, muitas vezes a publicação de falhas em softwares não representam o real problema existente, ficando os fabricantes a mercê de ataques por não saber a situação real da segurança de seus produtos.

 
Referências
 



 

 

 

Maycon Vitali é alto, moreno, tem os olhos verdes, não é baiano e possui como um de seus principais objetivos a dominação mundial. Formado em Ciência da Computação e Mestre em Informática, Maycon atua como Pesquisador e Analista de Segurança da Informação na Conviso. Além disto, Maycon possui aproximadamente 10 anos de experiência em computação, o que não quer dizer muita coisa; palestrou em diversos eventos de segurança, o que não também quer dizer muita coisa; e possui certificação OSCE, o que também não …. blah! Vocês já sabem. 

 

Originalmente postado no Blog da Conviso Application Security – Siga-nos no Twitter @conviso Google+

About author

Articles

Uma equipe de profissionais, altamente conectados com as notícias, técnicas e informações sobre a segurança de aplicações.
Related posts
Code FightersSegurança de Aplicação

Como integrar o Semgrep no CI/CD e enviar os resultados para a Conviso Platform

Atualmente, é uma prática muito comum integrar verificações de segurança durante a fase de…
Read more
Segurança de Aplicação

Impactos Negativos Gerados pela Ausência de Logs e Monitoramento de Segurança

Primeiramente, os logs são registros de atividades gerados também por sistemas, aplicações e…
Read more
Segurança de Aplicação

Dockers e Containers

Containers são soluções cada vez mais populares na indústria de desenvolvimento de software.
Read more

Deixe um comentário