Nesse laboratório você vai usar seus conhecimentos sobre a pilha de execução para entender como são realizados ataques do tipo buffer overflow. Este tipo de ataque se aproveita da ausência de verificação de "final de array" em C para sobrescrever a pilha de execução, alterando o endereço de retorno lá presente, e possivelmente outras informações.
Vamos utilizar o programa bufbomb.c para testar alguns exemplos. Para isso, busque aqui o arquivo bufferbomb.tar. Coloque-o em uma pasta onde possa criar uma subpasta para este laboratório e em seguida execute:
tar xvf bufferbomb.tarIsso deve criar uma pasta
bufferbomb
com os arquivos:
bufbomb.c
- código a ser "atacado"
buf.c
- manipulação do buffer
hex2raw.c
- função auxiliar para criar as strings de entrada
Makefile
- configuração da compilação e ligação
make bufbomb
O programa bufbomb é bastante simples, e basicamente chama a função getbuf
,
definida no arquivo buf.c
.
Execute ./bufbomb
escrevendo um texto qualquer quando o programa ficar a espera
de entrada, e veja o que acontece.
Agora vamos interferir no funcionamento de bufbomb
fornecendo uma string
de valores "apropriados".
Veja que a função getbuf
declara um array de char e chama Gets
para preencher esse array.
O programa auxiliar hex2raw
cria um arquivo binário contendo uma sequência de valores
dados na entrada em formato hexadecimal, isto é, se o arquivo se
contiver:
00 00 00 00 00 00 00 01e escrevermos:
./hex2raw < se >se.rawPodemos depois executar:
./bufbomb <se.rawpara fornecer a
bufbomb
a sequência de bytes equivalente ao conteúdo do arquivo mostrado.
Como o programa não testa o tamanho dessa sequência, podemos dar como entrada uma string
arbitrariamente grande.
Essa é a base do ataque de buffer overflow: sobrescrever a pilha de execução, alterando os endereços de retorno que estão empilhados para apontarem para um outro código que o intruso deseja que seja executado. (Nos primeiros ataques, esse outro código estava tipicamente presente nessa mesma string fornecida como entrada. Ao longo do tempo, os sistemas foram ficando mais protegidos, e não permitem a execução de instruções na área da pilha. Uma outra forma de ataque que se tornou bastante comum é desviar o controle para alguma função já existente no próprio código mas que não seria normalmente chamada.)
Vamos construir strings apropriadas para algumas tarefas:
bufbomb.c
.
Veja que existe uma função danger
, normalmente chamada pela função
protect
, que determina se o usuário tem as credenciais apropriadas
para executar a chamada.
Você irá criar uma string de bytes que desviará o controle para danger
sem passar por protect
.
Para isto, a string dada como entrada para bufbomb
deve sobrescrever a
pilha de execução, colocando o endereço de danger
no lugar do endereço
de retorno de getbuf
.
Você vai ter que criar uma sequência de bytes com tamanho suficiente para ocupar
desde o início do espaço ocupado por buf
até o endereço de retorno de getbuf
.
Os valores nas posições que não correspondem ao endereço de retorno de
getbuf
podem ser preenchidos com qualquer valor.
Desenhe a pilha a partir da chamada a getbuf
, na main
.
Verifique que string você precisa escrever para sobrescrever o endereço de
retorno de getbuf
.
Use
objdump -d bufbomb >bufbomb.32d
para descobrir o endereço de danger
e lembre-se que esse endereço deve aparecer
em little-endian.
Verifique também no "desassembly" da função getbuf
onde começa, na pilha de execução,
o array buf
. É comum o compilador alocar um pouco mais de espaço na pilha para poder
alinhá-la em um endereço múltiplo de 16.
Crie um arquivo stringinvasora
contendo uma sequência de valores hexa, por exemplo
(quebras de linha não fazem diferença):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 86 04 08 1a 2a 3a 4a 00 00 00 00 00 00 00 00 0a 0b 0c 0dCrie agora o programa auxiliar
hex2raw
, executando
make hex2rawUtilize
hex2raw
para gerar sua string e depois forneça o arquivo resultante
a bufbomb:
./hex2raw < stringinvasora > stringinvasora.raw ./bufbomb < stringinvasora.rawVocê verá se seu programa fez o que você queria pelas mensagens, mas para observar o seu efeito, crie um arquivo chamado
vitima
(pode ser até uma pasta)
dentro da pasta bufferbomb
.
obs: Caso sua sequeência de bytes esteja bem contruída, seu programa irá chamar
danger
e depois deve gerar uma segmentation fault.
Não se preocupe, iremos mudar isso no item seguinte.
danger
, pois não há um endereço de retorno no lugar esperado por ela.
Corrija isto.
Estenda a sua sequência de bytes de maneira a preencher a pilha com um endereço de retorno
no local esperado por danger
.
Use o endereço da função smoke
, fazendo com que o controle vá para ela
depois da execução de danger
.
(Como smoke
chama exit()
, o programa agora deve terminar
elegantemente.)
danger
e fizz
.
Gere uma sequência de bytes que faça getbuf
``retornar'' para a função
fizz
.
Veja o código de fizz
e tente colocar na pilha o parâmetro que ela
espera, para que ela imprima a linha: fizz! You called fizz....