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
Segurança de Aplicação

O mercado de segurança de aplicações no Brasil

Quando a Conviso foi fundada, em 2008, desenvolvimento seguro de software era então um tema…
Read more
Segurança de Aplicação

Por que APIs podem ser um alto risco para as empresas

Quando olhamos para o mundo de desenvolvimento e sua evolução nos últimos anos, podemos dizer que…
Read more
MobileSegurança de AplicaçãoSem categoria

3 serviços de AppSec que não podem ser negligenciados no fim de ano

2020 tem sido um ano atípico, mas mesmo em anos incomuns, algo é certeiro: na correria de fim de…
Read more

Deixe um comentário