Estouro de Buffer (Buffer Overflow)
Prof. Paulo Cesar F. de Oliveira,
BSc, PhD
Capítulo 03
Estouro Buffer
Seção 1.1
Introdução
Capítulo 03
Estouro Buffer
O que é ?
² 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
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
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”
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)
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
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
Capítulo 03
Estouro Buffer
Seção 1.2
Recapitulação
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)
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
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
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
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)
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)
Seção 1.3
Mapeamento da Memória
Capítulo 03
Estouro Buffer
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
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) ?
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
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
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
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
02/04/14 © P C F de Oliveira 2014 24
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?
Capítulo 03
Estouro Buffer
Seção 1.4
Stack Smashing
(estouro da pilha)
² 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
Capítulo 03
Estouro Buffer
Funcionamento da Stack (Pilha)
² 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
² 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
#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
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
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
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 à
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
#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
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
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)
Overwrite
Stack cresce; i.e. devido à
² 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
² 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!!!
² 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
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 à
Código Malicioso
Ptr código malicioso
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\x 0c\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
² 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
Seção 1.5
Heap Smashing
(estouro da heap)
Capítulo 03
Estouro Buffer
² “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
Seção 1.6
Soluções em C
Capítulo 03
Estouro Buffer
Solução óbvia quando se usa C é sempre verificar os limites dos buffers (i.e.
arrays)
Entretanto...
Capítulo 03
Estouro Buffer
² 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
² 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
Seção 1.7 Medidas - Conclusões
Capítulo 03
Estouro Buffer
² 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
² 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
Texto – Fonte Arial Normal – Máx.14pt / Mín.12pt – Preto – Centralizado