A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Segurança

Buffer overflow no Windows

Sab

5

Nov

2005


23:55

(2 votos, média 5.00 de 5) 


Outras coisas que vão dar trabalho: a MSCONF.DLL está carregada. Isto ocorre porque ela foi chamada e carregada pelo RUNDLL32. Sabemos disto porque a linha de comando inicial dos arquivos .CNF é "rundll32.exe msconf.dll,OpenConfLink %l". Também podemos supor que a KERNEL32.DLL esteja na memória porque as funções desta DLL estão na tabela de importação da KERNEL32.DLL. Por sua vez, as funções da KERNEL32.DLL também estão na tabela de importação da MSCONF.DLL. Procurando o que possa ser o mais viável devemos analisar o seguinte: estamos hackeando o NetMeeting 2.1. Isto significa que dependemos de uma versão do produto e uma versão da MSCONF.DLL. Por outro lado, as versões do RUNDLL32 ou da KERNEL32 dependem do sistema operacional ou dos upgrades feitos neste sistema. Portanto, se quisermos fazer referência a um endereço de memória virtual absoluto, é melhor que este endereço pertença à MSCONF. Caso contrário, corremos o risco de cutucar no lugar errado! Isto é um problema se quisermos que o exploit funcione em todas as versões do sistema operacional alvo.

Bem, neste caso, é bom dar uma verificada como outros programas obtêm seus endereços. Como o objetivo é usar funções de Internet para botar o código do exploit para funcionar, será preciso usar a WSOCK32.DLL ou a WININET.DLL. A WININET proporciona maior funcionalidade com menos código, portanto é melhor começar com ela. A WININET não está carregada no espaço do RUNDLL32, o que nos obriga a carregá-la. Mas, vamos com calma. Antes disto é preciso explicar como ganhar o controle do EIP e como apontar o código para ele.

Dominando o EIP

Descobrimos que, através de um buffer overflow de um determinado tamanho, poderíamos modificar o endereço de retorno de alguma função e desviar o fluxo de execução para algum ponto da nossa escolha. Neste caso, o normal seria proceder mais ou menos assim:

     Endereço = .....256 pontos....1234xyz

Como o tamanho do buffer é de 256 bytes (descobre-se isto por tentativa, aumentando-se ou diminuindo-se o comprimento da linha Endereço = até chegar no comprimento exato que causa o estrago), a linha acima vai preencher o buffer com 256 caracteres ponto (.), escrever por cima de EBP 0x34333231 e preencher o EIP com 0x00ZZYYXX se a string terminar com um NULL. Isto permite que apontemos para qualquer posição da pilha porque, adivinhe só, temos a permissão de colocar um NULL na posição final!

Em alguns casos, isto funciona muito bem. Em outros, o buffer, ou é muito pequeno para esta tarefa, ou é primeiro é bagunçado por uma porção de inserções e operações de string. Em muitos casos, colocar o código DEPOIS do endereço de retorno é uma idéia melhor. Por exemplo:

     Endereço = .....256 pontos....1234wxyzOCÓDIGOSEGUEAQUI>>>

Neste caso, com frequência obtém-se muito mais espaço de trabalho mas, em compensação, perde-se o benefício de poder usar um caracter NULL para compor o endereço de salto na pilha. Mesmo assim, neste exemplo, para construir o exploit, a única alternativa viável é colocar o código após o endereço de retorno porque o material antes do endereço de retorno é destruído antes de termos a chance de trabalhar com ele. Terminamos fazendo um salto para 0xZZYYXXWW, onde WW, XX, YY e ZZ não podem ser caracteres inválidos. E onde vamos parar? Onde quisermos smile

Antes de mais nada, ative o seu debugger de tempo real e insira uma string de exploit que cause a falha. Alguma coisa que aponte para um péssimo endereço (por exemplo, ajuste 0xZZYYXXWW para 0x34333231. Como não há código nesta área da memória, a falha de página é instantânea). Agora é só rodar e deixar que o debugger entre em ação. Examine o estado e veja o que é possível fazer. No caso deste exploit, vemos que ESP é o único registrador que aponta para alguma coisa perto do código do exploit. Na verdade, ele aponta para a localização onde invadimos o EBP armazenado mais 16 bytes.

Bem, o que estamos querendo fazer? Queremos forçar um salto para dentro da pilha. Na verdade, simplesmente saltar para ESP seria suficiente. Um modo esperto de conseguir isto é fazer com que 0xZZYYXXWW aponte para um trecho de código na memória que faça um "jmp esp", um "call esp" ou qualquer coisa do gênero. Mas, para complicar a situação, este trecho precisa ser um código onde nenhum dos bytes do endereço seja um byte "ruim", especialmente um 0x00. Encontramos o código mágico na MSCONF.DLL, carregada em 0x6A600000, deslocamento 2A76:

     .00002A76: 54                           push   esp
     .00002A77: 2404                         and    al,004
     .00002A79: 33C0                         xor    eax,eax
     .00002A7B: 8A0A                         mov    cl,[edx]
     .00002A7D: 84C9                         test   cl,cl
     .00002A7F: 740F                         je    .000002A90   
     .00002A81: 80E930                       sub    cl,030  ;"0"
     .00002A84: 8D0480                       lea    eax,[eax][eax]*4
     .00002A87: 0FB6C9                       movzx  ecx,cl
     .00002A8A: 42                           inc    edx
     .00002A8B: 8D0441                       lea    eax,[ecx][eax]*2
     .00002A8E: EBEB                         jmps  .000002A7B
     .00002A90: C20400                       retn   00004

Olhando para este código, onde está o salto para ESP? Não está, porque não faz mesmo. Ele apenas retorna para ESP. Acontece um PUSH ESP, o jmps 2A7B acontece uma vez e, depois, o JE 2A90 entra em ação e nos leva para um RET. Na verdade, é isto que faz o salto para ESP. Até aqui, tudo conforme o planejado. A MSCONF.DLL está carregada e podemos esperar que este código esteja no mesmo lugar o tempo todo porque só há uma versão da MSCONF.DLL que tem um endereço base fixo. Neste caso, nosso endereço 0xZZYYXXWW é 0x6A602A76. Nada de NULLs, caracteres proibidos ou outro tipo de enrosco. O EIP foi dominado e o processador é nosso!

Informações adicionais