Buffer Overflow
Ataque do tipo Buffer Overflow acontece quando um programa reserva blocos de espaço pré-definidos e limitado de memória (buffer) para armazenar dados e esse espaço reservado recebe mais dados do que é capaz de comportar. Isso ultrapassa os limites do buffer e sobrescreve a memória adjacente.
Linguagens modernas como Python, PHP, Ruby, Java e C# não são vulneráveis a esse tipo de ataque, pois utilizam Memory Safe, ou seja, não permitem que variáveis acessem regiões de memória não alocados ou alocadas por ponteiros/variávies diferentes.
Linguagens não seguras como C e C++ possuem contramedidas como ASLR (Address Space-Layout Randomization), Stack Canaries e CFI (Control Flow Integrity)
Anatomia na Memória RAM
Abaixo segue o básico da sua divisão, indo do low address para o high address:
PARTE DA MEMÓRIA
DESCRIÇÃO
text segment
Região read-only que armazena textos como códigos e comandos utilizados por outros programas. O texto correspondente ao nosso código fonte, por exemplo, fica armazenado aqui
data (initialized / unitialized)
Aqui ficam as variáveis inicializadas e não inicializadas do software
heap
Região destinada ao armazenamento dinâmico de grandes informações, gerenciada pelas funções malloc, realloc e free. O que estará armazenado aqui depende da estrutura do programa sendo executado
stack
Região onde ficam armazenadas (com tamanho dinâmico) as variáveis e funções locais do nosso programas. Esta é uma pilha que funciona no esquema LIFO (Last In First Out), contendo endereços de funções que devem ser invocadas e parâmetros/variáveis a serem utilizadas
Os primeiros endereços de memória (números em hexadecimal) ficam em baixo (0x00000000) e os últimos endereços ficam no topo (fxffffffff). Conforme o stack vai utilizando mais memória, são utilizados os endereços de baixo, ou seja, o stack cresce na direção do heap (de cima pra baixo), enquanto o heap cresce na direção do stack (de baixo pra cima).
Buffer Overflows geralmente acontecem no stack, mas apesar de ser pouco comum, é possível que overflows também ocorram em outras regiões de memória como o heap.
Quando o programa é executado, uma instrução assembly jump é invocada apontando para o endereço de retorno desta função return, é assim que a função main sabe o que deve ser executado após executar nossa função func, ela executará o que estiver em return.
Heap
Armazena a memória alocada dinamicamente e começa com um endereço de memória baixa e vai utilizando endereços maiores a cada nova inserção.
Stack (Pilha)
A Stack trabalha com a estrutura LIFO (Last In First Out), ou seja, o último a entra na pilha, irá entrar no topo, e este será o primeiro a sair. A Stack começa com o endereço de memória mais alta e a cada nova inserção, vai inserindo em um endereço menor, fazendo o inverso da Heap. O rsp indica o endereço do topo da pilha e rbp é a base da Stack.
Segue abaixo alguns exemplos de inserção e remoção no topo da Pilha.
msfvenom
Gerando execve.
Procurando offset
pattern_create + pattern_offset
Aqui iremos utilizar duas ferramentas que fazem parte do Metasploit, o pattern_create.rb para gerar o payload que será enviado e o pattern_offset.rb que retorna o offset a partir do resultado obtido com o payload enviado).
Com a saída do comando acima, jogue a string no executável e certique-se o mesmo irá "crashar". Caso seja negativo, aumente o valor de <lenght_crash>. Ao travar o software, verifique o valor de EIP (através do Immnuity Debugger) e execute o comando abaixo para saber o offset correto.
pattern_create + mona
Semelhante a forma anterior, iremos utilizar o pattern_create para gerar nossa string, mas após utilizamos para "crashar" a aplicação, não iremos utilizar o pattern_offset, mas sim o mona. Após enviar o payload para o sistema, vá até o Immunity Debugger e então execute:
Após isso, procure pelo primeiro resultado de offset, logo abaixo a linha [+] Examing registers.
Bad Chars
Alguns caracteres são considerados como bad chars, pois a aplicação não os reconhece, então não podem ser utilizados em nosso shellcode. Geralmente, os badchars são \x00, \x0a e \x0d, mas isso não é uma regra geral, pois vai de aplicação para aplicação.
Abaixo, segue todos os caracteres em hex. Já removemos o char \x00, que provavelmente irá causar erros:
Caso queira gerar, execute um dos códigos abaixo, ambos desenvolvidos em Python:
mona
Antes de utilizarmos o mona, vamos definir qual o seu diretório de trabalho. Para isso, iremos criar o diretório c:\mona e depois executar o seguinte comando no Immunity Debugger:
Agora vamos gerar um arquivo com badchars semelhante ao que vimos acima, porém usando o mona no Immnunity Debbuger ao invés do python, e já excluindo o \x00, que provavelmente irá provocar algum erro.
Note na saída do comando que será gerado um arquivo chamado bytearray, que iremos utilizar para comparar o nosso ESP, através do comando:
Irá ser aberta então, uma janela com os bad chars localizados.
Remova agora os bad chars localizados execute novamente o processo pelo mona até que o resultado seja Unmodified.
Trabalhando com Opcode
Primeiro vamos ver os Módulos que não tem proteção ASLR com o Immunity Debugger, utilizando o mona.
Após localizar qual (ou quais) dll's não possuem possuem proteções ASLR, vamos utilizar o nasm_shell para localizar um JMP ESP.
Supondo que o resultado seja 00000000 FFE4 jmp esp, então vamos pegar o FFE4 e procurá-lo no mona.
Por boas práticas, é sempre bom colocar um endpoint no local encontrado, para confirmar se o EIP realmente está redirecionando corretamente para ESP.
Procurando o JMP ESP
Como sabemos, não é possível pegarmos o valor exato de ESP (já que este é dinâmico), então precisamos localizar algum JMP para o ESP (que tem um valor estático), e então chamá-lo. Note que passamos o parâmetro -cpb para informamos os badchars e evitarmos problemas. Esse programa que estamos utilizando é o mona, que é uma extensão do Immunity Debugger.
Reinicie a execução do binário antes de executar o comando abaixo.
O valor encontrado aqui, ficará no lugar do BBBB, que geralmente é utilizado para testar se podemos sobrescrever EIP. Supomos que encontramos o valor 0x625011af, então o valor irá ficar assim (note a inversão da ordem): \xaf\x11\x50\x62
Gerando Shellcode com msfvenom
Note que abaixo estamos definindo somente \x00 como Bad Char, porém pode ter mais. E também estamos definindo no parâmetro -f que é para funcionar em aplicação desenvolvidas em C. Também estamos utilizando o parâmetro exitfunc=thread, que serve para não "crashar" o serviço ao sair dele, pois por padrão o msfvenom mata o processo ao finalizar.
Sites
Last updated
Was this helpful?