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.
ATENÇÃO: Nem todos esses podem ser badchars! Às vezes, os badchars fazem com que o próximo byte também seja corrompido ou até mesmo afetem o resto da string. Utilize o Follow in Dump
do ESP
para verificar de forma manual.
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