MC504 - Sistemas Operacionais
Buffer Overflow
Islene Calciolari Garcia
Instituto de Computação - Unicamp
Primeiro Semestre de 2017
Sumário
Introdução
Alterar o endereço de retorno
Produzindo o shell code
Analisar o execve
Arrumar a chamada para o execve
Explorando a vı́tima
Proteção
Buffer Overflow
I Ataque que insere mais dados do que o espaço
previamente alocado. Estes dados extras na verdade são
trechos de códigos que serão executados pelo
programa-vı́tima.
I Esta aula foi baseada na série Buffer Overflow Primer, de
Vivek Ramachandran
Registradores Intel 32-bits
I EBP: base pointer
I ESP: stack pointer
I EAX: acumulador
I ECX: contador
I EDX: dados
I ESI: source index
I EDI: destination index
Vamos examinar a pilha de execução
I Componentes do frame (não necessariamente nesta
ordem):
I valor de retorno
I endereço de retorno
I registradores
I argumentos para a função
I variáveis locais da função
I Veja os códigos pilha.c e pilha2.c
Funções vulneráveis
I Veja man gets(), man fgets() e man scanf()
I Você já utilizou scanf("%<max>s, s");?
I Veja o código buffer.c
I Insira um buffer maior do que o esperado e veja o
resultado
I Veja o código buffer-strcpy.c
Como colocar o novo ponto de execução via entrada
padrão?
I Como colocar encontrar e inserir o endereço na string?
I Veja man printf()
Endereço: 0x4005f6
$ printf "abcdef... \xf6\x05\x40\x00" | ./buffer
Vı́tima e armadilhas
Loop infinito
I Shellcode: Código malicioso a ser inserido tem este
nome porque, na maioria das vezes, o código adicionado
iria abrir uma nova shell.
I Vamos escrever armadilhas. A vı́tima vai colaborar nos
testes executando código via mmap.
I Veja os códigos map-armadilha-loop e map-vitima
I Como modificar map-armadilha-loop para chamar uma
função tipo printf ou outra função qualquer?
Vı́tima e armadilhas
Chamada de outras funções
I Para fazer outros testes, não será preciso recompilar o
código da vı́tima. Por quê?
I Tente colocar algo como printf("Armadilha!!!!"); no
código da vı́tima. Por que não funciona?
I Veja o código map-armadilha-printf.c
I No gdb, utilize disassemble f
Chamadas de sistema
I Fazem a fronteira entre o modo usuário e o modo kernel
(protegido)
I Exemplos: fork, waitpid, execve, open, close, read, write,
mkdir, link, unlink, ...
I O kernel deve ter uma tabela com as várias chamadas.
Chamada de sistema
Tanenbaum: Figura 1.17
execve
I Veja o exemplo execve.c
int main() {
char *args[2] = {"/bin/bash", NULL};
execve(args[0], args, NULL);
return 0;
}
Veja map-armadilha-execve.c
Todos os argumentos devem estar na pilha
I Argumentos
I filename
I argv
I envp
I Veja o código map-armadilha-execve2.c
I Não produz um shellcode perfeito porque a string de
entrada ainda contém 0s (NULLs). :(
Explorando a vı́tima
I Considere um shellcode sem NULLs como o disponı́vel
em demystifying execve shellcode
I Como saber em qual endereço o shellcode deve ser
posicionado?
I NOP Sled antes do shell code permite a recuperação de
pequenas falhas no cálculo do endereço.
I Ataque força-bruta?
I Veja o código buffer-shellcode.c
Proteção das páginas
I Controlar quais páginas são executáveis poderia resolver
o problema?
I Return to libc
I Veja o código buffer-libc.c
Como funciona o Stack Canary
I Termo canário inspirado nos pássaros utilizados nas
minas de carvão.
I Valores chave são inseridos na pilha
I Caso esses valores sejam alterados, o programa deve
interromper sua execução.
I Veja as opções de compilação do gcc 6.2:
-fstack-protector: Proteç~
ao para funç~
oes que invocam
alloca ou funç~
oes com buffers maiores do que 8 bytes.
-fstack-protector-all: Proteç~
ao para todas as funç~
oes
-fno-stack-protector: Desliga a proteç~ ao