1 Estouro de Buffer (Buffer Overflow) Prof. Paulo Cesar F. de Oliveira, BSc, PhD
4 02/04/14 © P C F de Oliveira 2014
² Definições ² Buffer (array ou string)
² Área da memória onde a entrada do usuário é armazenada
² Estouro (Overflow) ² Entrada do usuário excede o tamanho máximo do
buffer ² Sobrescrevendo outras áreas da memória e
corrompendo-as
Capítulo 03 Estouro Buffer
5 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer ² O que é?
² Evento que ocorre quando:
² Buffer de dados de comprimento fixo (e.g. string)
² Pelo menos um valor destinado ao buffer é escrito fora de seus limites (geralmente após o seu fim)
² Leitura da entrada ou após o tratamento de dados
6 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer ² O que é?
² Buffer overflows = buffer overruns
² Stack overrun ² Buffer na pilha (stack) ² Também chamado “stack smashing”
² Heap overrun ² Buffer na heap ² Também chamado “heap smashing”
7 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer ² O que é?
² Problema comum
² Se explorável ² Agressor pode controlar o programa
completamente
² Agressor pode tipicamente causar negação de serviço ² Muitas defesas simplesmente reduzem-se de
“programa de controle” para o DoS (Denial-of-Service)
8 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
1988: Morris worm – tirou Internet do ar Inclui estouro de buffer via gets() in fingerd
1999: Implementação de referência crypto RSA, Subverteu PGP, OpenSSH, Apache’s ModSSL, etc.
2003: SQL Slammer worm comprometeu máquinas rodando Microsoft SQL Server 2000
2008: Twilight hack – abre consoles Wii, Criando um nome longo para cavalo “Epona” no jogo "The Legend of Zelda: Twilight Princess", permitindo execução
2001: Code Red worm – buffer overflow no Microsoft’s Internet Information Services (IIS) 5.0
1998: University of Washington servidor IMAP (mail)
Histórico
9 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
² Linguagens de Programação e Estouro de Buffer ² Linguagens que permitem o evento
² C, C++, Objective-C, Vala, Forth, Assembly ² Linguagens que não permitem
² Ada strings, Pascal: Detém/previne overflow ² Java, Python, Perl, Ada: Auto-resize
² Outras linguagens não dão imunidade ² Implementações da maioria são em C/C++ ² Várias bibliotecas/componentes do SO incluem C/C++ ² Algumas linguagens/compiladores permitem desabilitar
proteção ² C# e Ada
² Escolhendo outra ajuda – mas não completamente
Muito comum
11 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
² Terminação de string em C è \O ² Strings em C terminam com caracter \0 (1 byte valor 0) ² Vários SOs e componentes construídos com C
² Interfaces herdam semanticamente “strings com \0” ² Alguns componentes não lidam com isto, mesmo
que a linguagem possa ² Observe que \0 ocupa espaço – lembre-se disto ² Nome formal é NUL ou caracter NULL
² Às vezes confundido com NULL – “null pointer”
H e l l o \0 NIL (reduzir confusão)
12 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
² Arrays em C ² Arrays alocam um tamanho fixo de memória
² Ex., para um buffer ² Arrays “char” são usadas para string de caracteres
² Devem ser o grande suficiente ² Para os caracteres a serem armazenados ² Incluindo também o caracter NIL
² Ex. “char x[10];” § Aloca espaço para uma array x § Array x possui 10 chars § Armazena 9 caracteres + caracter de
terminação NIL
13 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Exemplo #1
int main() { int array[5] = {1, 2, 3, 4, 5}; printf("%d\n", array[5]); }
§ Nunca faça isto § Checar limites da array em tempo de
execução
14 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Exemplo #2
int main() { int array[5] = {1, 2, 3, 4, 5}; int i; for( i=0; i<=255; i++ ) array[i] = 41; }
§ Nunca faça isto § Checar limites da array em tempo de
execução
15 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Exemplo #3
int main(int argc, char* argv[]) { char command[10]; printf(”Seu comando? \n"); gets(command); printf(”Seu comando foi: %s\n", command); } § Só 10 bytes para variável command
(incluindo NIL) § Instrução gets não provê proteção
contra estouro de buffer
§ Nunca use gets § Use fgets(buf, size, stdin)
16 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Exemplo #3
... char dest [20]; strcpy (dest, src) //copia string src para dest ...
§ strcpy assume dest é grande o bastante
§ Nunca use strcpy § Use strncpy(dest, src, size)
18 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Stack (Pilha)
Heap (alocada dinamicamente) Dados 2 Globais não inicializados Dados 1 Globais
inicializados Código do Programa
§ Stack: Contém endereço de retorno das chamadas de função, argumentos para funções e variáveis locais
§ Heap: Contém dados dinâmicos e não inicializados
§ Dados 2: Contém variáveis globais não inicializadas
§ Dados 1: Contém variáveis globais inicializadas § Inicializadas na carga do código
§ Código do programa: Contém as instruções (comandos) § Somente pra leitura
§ Usado para variáveis e constantes globais
19 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Observando código abaixo
int main() { int char sample[10]; int i; for (i=0; i<=9; i++)
sample[i] = 'A'; sample[10] = 'B’
}
Onde ‘B’ ficará (memória) ?
20 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Possibilidade #1
A A A A A A A A A A B
Mem
ória
Afeta os dados do usuário
Dados do Usuário
21 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Possibilidade #2
A A A A A A A A A A B
Mem
ória
Afeta código do usuário
Dados do Usuário Código do Programa do
Usuário
22 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Possibilidade #3
A A A A A A A A A A B
Mem
ória
Afeta os dados do sistema
Dados do Usuário Dados do Sistema
23 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Possibilidade #4
A A A A A A A A A A B
Mem
ória
Afeta código do sistema
Dados do Usuário Código do Programa do
Sistema
24 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer Questões para responder
² Que valores o hacker poderia inserir após o buffer que causasse prejuízo ou dano?
² Quais códigos de instrução planejados o sistema seria forçado a executar?
25
Capítulo 03 Estouro Buffer
02/04/14 © P C F de Oliveira 2014
Seção 1.4 Stack Smashing (estouro da pilha)
26 02/04/14 © P C F de Oliveira 2014
² Conceito de Pilha (Stack) ² Pilha de objetos tem a propriedade de que o último objeto
inserido será o primeiro objeto a ser removido ² Last in – First out (LIFO) ² Operações básicas
² PUSH: adiciona um elemento no topo da pilha
² POP: remove um elemento do topo da pilha, reduzindo o tamanho dela em 1 unidade
Capítulo 03 Estouro Buffer
28 02/04/14 © P C F de Oliveira 2014
² Pilha (Stack) no Processo de Mapeamento da Memória ² Área de memória reservada para implementar as chamadas para
um procedure / function / method / subroutine ² Estes termos são sinônimos (C -> function – função)
² Stack é usada para implementar controle de fluxo ² Quando você chama procedure, de “onde ele veio" é inserido
(PUSH) na pilha ² Quando procedure retorna, o de “onde vim" é removido (POP)
da pilha; ² Sistema começa a execução de código lá
² Stack também utilizado para outros dados (em muitos casos) ² Parâmetros passados para procedure ² Variáveis locais das procedures ² Valores de retorno da procedure
Capítulo 03 Estouro Buffer
29 02/04/14 © P C F de Oliveira 2014
² Stack possui 2 valores ² Stack Pointer: valor que está no topo
² Onde o último dado foi armazenado
² Modificado quando dado for (pushed/popped)
² Frame Pointer: valor do “quadro” – conteúdo ² Simplifica acesso a parâmetros e variáveis locais
² Aponta para onde “o procedimento” começa dentro da pilha
² Modificado na entrada/saída do procedimento
Capítulo 03 Estouro Buffer
30 02/04/14 © P C F de Oliveira 2014
#include <stdio.h> #include <stdlib.h> #include <string.h> void f(int a, int b, int c) { char buffer1[5]; char buffer2[10]; strcpy(buffer2, "This is a very long string!!!!!!!");
} int main() { f(1,2,3);
}
Capítulo 03 Estouro Buffer
Código assembler pushl $3 ;constante 3 pushl $2 ;constante 2 pushl $1 ;constante 1 call f
Execução do programa
31 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses
Stack pointer (SP) (current top of stack) 3
Stack: após push do valor 3
32 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 Stack pointer (SP) (current top of stack)
Stack: após push do valor 2
Stack cresce; i.e. devido à chamada da procedure
33 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 1
Stack pointer (SP) (current top of stack)
Stack: após push do valor 1
Stack cresce; i.e. devido à chamada da procedure
34 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 1
Stack: logo após a chamada da
função
Endereço Retorno em main() Stack pointer (SP) (current top of stack)
Stack cresce; i.e. devido à chamada da procedure
35 02/04/14 © P C F de Oliveira 2014
#include <stdio.h> #include <stdlib.h> #include <string.h> void f(int a, int b, int c) { char buffer1[5]; char buffer2[10]; strcpy(buffer2, "This is a very long string!!!!!!!");
} int main() { f(1,2,3);
}
Capítulo 03 Estouro Buffer
pushl %ebp ;Push old frame pointer (FP) movl %esp,%ebp ;New FP é SP (old) subl $20,%esp ;New SP está após vars locais
;“$20” calculado p/ser >= espaço var local
Execução da procedure
§ EBP: Base pointer: aponta para o início do stack frame corrente
§ ESP: Stack pointer: aponta para o topo da stack
36 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 1
Stack: execução da função
Endereço Retorno em main()
Frame pointer (FP) – Use para acessar variáveis locais e parâmetros
Frame pointer salvo (old)
Array local “buffer1”
Array local “buffer2”
Stack pointer (SP) (current top of stack)
Stack cresce; i.e. devido à chamada da procedure
37 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 1
Stack: “estourando” buffer2
Endereço Retorno em main()
Frame pointer (FP) – Use para acessar variáveis locais e parâmetros
Frame pointer salvo (old)
Array local “buffer1”
Array local “buffer2”
Stack pointer (SP) (current top of stack)
Overw
rite
Stack cresce; i.e. devido à chamada da procedure
38 02/04/14 © P C F de Oliveira 2014
² O que acontece se escrevermos algo no fim de buffer2? ² Substitui o que estiver após buffer2
² Quanto mais longe for, mais endereços altos sobrescritos
² Impacto depende de detalhes do sistema
² No exemplo, irá substituir ² Valores locais (buffer1)
² Frame Pointer Salvo ² Valor de Retorno (mudando ponto de volta ao PP) ² Parâmetros da função (procedure)
² Frames anteriores
Capítulo 03 Estouro Buffer
39 02/04/14 © P C F de Oliveira 2014
² Ataque mais comum de estouro de buffer ² Enviar dados muito largos ou ² Criar dados extremamente largos ² Dados muito largos sobrescrevem o buffer
² Modifica o valor de retorno para
² Aponta para algo que o hacker quer que se execute ² Talvez com parâmetros diferentes também
² No retorno executa código selecionado por ele
Capítulo 03 Estouro Buffer
Mas, tem coisa pior!!!
40 02/04/14 © P C F de Oliveira 2014
² Inserindo código no estouro de buffer (e.g. Shell code) ² Hacker pode incluir um código de máquina que ele quer
que se rode ² Se ele pode definir o valor de “retorno” apontar para
um código malicioso, ² No retorno a vítima executará este código
² A menos que algo seja feito ² O paper “Smashing the Stack” contém uma descrição
de como inserir este código
Capítulo 03 Estouro Buffer
41 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 1
Stack: 1 possível resultado após ataque
Endereço Retorno em main()
Frame pointer (FP) – Use para acessar variáveis locais e parâmetros
Frame pointer salvo (old)
Array local “buffer1”
Array local “buffer2”
Stack pointer (SP) (current top of stack)
Stack cresce; i.e. devido à chamada da procedure
Código Malicioso
Ptr código malicioso
42 02/04/14 © P C F de Oliveira 2014
Capítulo 03 Estouro Buffer
Lower-numbered addresses
Higher-numbered addresses 3
2 1
Stack: 1 possível resultado após ataque
Endereço Retorno em main()
Frame pointer (FP) – Use para acessar variáveis locais e parâmetros
Frame pointer salvo (old)
Array local “buffer1”
Array local “buffer2”
Stack pointer (SP) (current top of stack)
Stack cresce; i.e. devido à chamada da procedure
Ptr código malicioso
Shellcode: \xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh
NOP sled: \x90\x90\x90\x90\x90…. NOP slide § Permite que hacker
pule para qualquer lugar para atacar
§ Alguns muito complexos para detectar
Shellcode: ver slide seguinte
43 02/04/14 © P C F de Oliveira 2014
² Outros tipos de ataques possíveis no estouro de buffer ² Fazer o “código de retorno” apontar para um código
existente que o hacker queira que se execute ² E.g. chamar um shell ² Talvez modificar parâmetros
² Alterar valores de variáveis locais adjacentes ² Alterar valor dos parâmetros ² Entender que sobrescrever algo após o fim de um buffer
pode ter consequências devastadoras ² Detalhes dependem do sistema ² Sim, os hackers realmente entendem isto
Capítulo 03 Estouro Buffer
44 02/04/14 © P C F de Oliveira 2014
Seção 1.5 Heap Smashing (estouro da heap)
Capítulo 03 Estouro Buffer
45 02/04/14 © P C F de Oliveira 2014
² “Estourando a Heap” ² Heap contém dados alocados dinamicamente
² e.g. “new” (Java/C++) ² malloc (C)
² Dados são globais ² Incluem valores de controle de infraestrutura importantes ² Se hacker pode sobrescrever além do buffer, pode controlar outros
valores (e.g. Armazenados depois disto) ² Valores de outras estruturas ² Dados de manutenção da heap (e.g. O que livre/usado) ² Até mesmo 1 byte sobrescrito pode ser devastador
² Detalhes são dependentes do sistema ² Hackers podem explorá-los também ² Questão fundamental como estouro da pilha (stack smashing)
Capítulo 03 Estouro Buffer
47 02/04/14 © P C F de Oliveira 2014
Solução óbvia quando se usa C é sempre
verificar os limites dos buffers (i.e. arrays)
Entretanto...
Capítulo 03 Estouro Buffer
48 02/04/14 © P C F de Oliveira 2014
² Funções C que não verificam limites ² gets() – lê entrada sem checar – não use!!! ² strcpy() – strcpy(dest, src) copia src para dest
² Se src > dest, continua escrevendo!!!! ² strcat() – strcat(dest, src) adiciona src em dest
² Se src + dados em dest > buffer dest, continua gravando!!!
Capítulo 03 Estouro Buffer
49 02/04/14 © P C F de Oliveira 2014
² Funções C que não verificam limites ² scanf() família de funções de entrada – várias opções
perigosas ² scanf(), fscanf(), sscanf(), vscanf(), vsscanf(),
vfscanf() ² Muitas opções não controlam comprimento máximo
(e.g. “%s”) ² Outras funções perigosas
² realpath(), getopt(), getpass() ² streadd(), strecpy(), and strtrns()
² Laços (loops) também podem ocasionar estouro
Capítulo 03 Estouro Buffer
51 02/04/14 © P C F de Oliveira 2014
² Estouro de Buffer pode ser devastador ² C / C++ / Objective-C è vulneráveis ² Tentar linguagens seguras (e.g. Java, Python)
² Tornar a localização da pilha (stack) aleatória ² Usar verificação em tempo de execução
² StackGuard
² Libsafe ² SafeC
² Teste da Caixa Preta (e.g. eEye Retina, ISIC)
Capítulo 03 Estouro Buffer
52 02/04/14 © P C F de Oliveira 2014
² Referências ² Conference on Software Security : Aleph One, Smashing
the Stack for Fun and Profit. Originally published in Phrack 49-14.1996
² IEEE Reference : Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade*
² Pincus, Jonathan,”Beyond Stack Smashing: Recent
Advances in Exploiting Buffer Overruns”, IEEE Security&Privacy
Capítulo 03 Estouro Buffer