Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

Localhost

Buffer Overflow - O terrível demónio

Mensagens Recomendadas

Localhost

Olá pessoal, resolvi então escrever mais alguma coisa aqui no forúm, escolhi então que desta vez fosse sobre buffer overflow. Visto que pode causar grandes problemas se existir a possibilidade de existir eu venho aqui explicar o que ele é e como se pode evitá-lo. Este texto é 100 % da minha autoria. Vamos lá começar então.


O que é o buffer overflow?

Buffer overflow é o facto de se passarem os limites do buffer, o buffer é a região de memória onde são lidos e escritos dados como strings por exemplo. Como vocês sabem as strings não são mais do que vectores de elementos de 1byte, os chamados chars ou caracteres. O que o buffer overflow faz ou é, melhor dizendo, é passar os limites desse buffer atingindo assim outras zonas da memória. Agora a pergunta que fica no ar é, o que é que isso tem de perigoso e que zonas é que são "atingidas"? Vamos ver isso a seguir.

O que é o/a stack?

O ou A, stack é o local da memória onde são guardados dados temporários como as variáveis locais, é também o que o computador utiliza para entradas e saída de dados rápidas. É também na/no stack que são guardadas as strings. O que têm de saber da/do stack é que nele/nela, quando é chamada uma função no vosso programa, é criado um stack frame (imaginem o stack frame como uma divisão do/da stack, quando temos várias funções são criados vários stack frame(s)). Ora bem, nesse stack frame vai ser onde vão ser armazenadas todas as variáveis da função e também um endereço, um endereço muito especial, o chamado, endereço de retorno.

O que é o endereço de retorno?

Quando chamamos uma função então é criado um stack frame, agora imaginem na vossa mente o stack frame, agora imaginem como é que no final da função o programa sabia por onde prosseguir a execução? Então para isso existe o endereço de retorno, ele contêm o endereço da próxima instrução de onde foi chamada a função. Para perceberem melhor, vou pôr aqui um código:

#include <stdio.h>

int main(void){
   char string[8];
   gets(string); //Ainda vamos falar muito desta função.
   printf("%s\n", string);
   return (0);
}

Vamos perceber o programa, declaramos uma string de 8bytes, e depois chamamos a função gets, ora bem, no stack frame da função gets é criado as suas variáveis locais e também um endereço de retorno que contêm o endereço da próxima instrução do programa que neste caso é a função printf. Tentem imaginar isto como quando vamos fazer uma caminhada, pomos as pedras no caminho para não nos perdermos, digamos que a pedras são o endereço de retorno para o caminho principal.

Então como ocorre o buffer overflow?

Ora bem, quando nós passamos os limites do buffer a verdade é que tudo o que está "ao lado" dele vai entrar em contacto com os dados que passaram fora da string (no caso). Na verdade o buffer overflow é só isso, o "transboradamento", como o nome diz de dados pelo buffer fora. No entanto, ao lado do buffer muitas vezes está o endereço de retorno, e é aí que se tenta explorar, imaginem que se meta lixo até preencher o buffer e depois de se preencher, estando já em contacto com o endereço de retorno se coloque lá outro endereço, por exemplo um endereço para uma função maliciosa. Na verdade eu não estou aqui para vos explicar como explorar mas o que as pessoas mal intencionadas fazem não é meter um endereço mas sim uma coisa chamada de shellcode (procurem sobre isso no google). Para provar que é sobreescrito tudo que estiver ao lado do buffer (se forem passados os limites) compilem e executem este código:

#include <stdio.h>

int main(void){
   char s_1[8], s_2[8], s_3[8];
   gets(s_1);
   gets(s_2);
   gets(s_3);
   printf("%s\n%s\n%s\n", s_1, s_2, s_3);
   return 0;
}

E agora passem os limites da segunda string ou da primeira, neste caso não vamos estar em contacto com o endereço de retorno mas sim com a string que está a seguir dependendo da que quiserem, vejam então o output e tentem perceber o que aconteceu. Nota: Se estiverem em Linux vai dar um segmentation fault, não podendo assim verem o output, que é o meu caso.

Como se proteger?

Finalmente chegamos à parte da protecção, como nos podemos proteger disto tudo? É simples, usamos funções que verifiquem se a string do input é maior do que aquela que a vai receber. Vou introduzir uma lista a seguir então de funções vulneráveis e das que não são vulneráveis, relativamente a essas.

Funções - Lista (ex: Função_vulnerável - Função segura)

- gets - fgets;

- strcpy - strncpy

- strcat -  strncat

- scanf(strings) - fgets

Lista - O porquê de serem vulneráveis

- gets - A função gets, recebe um input e presupõe que o input nunca seja maior que o buffer que a vai receber.

- strcpy - A função strcpy presupõe que a string destino tenha capacidade para comportar a string origem.

- strcat - A função strcat presupõe que a string que a vai receber tem ainda capacidade para comportar a string que vai ser copiada

- scanf(se não forem incluídas restrições) - A função scanf tem as mesmas caracteristicas que a gets no caso de estarmos a ler strings. Não confundam com inteiros e outro tipos de dados.

Bem, estas são apenas algumas funções, muito poucas aliás mas já dá para ter uma ideia por isso sempre que utilizarem uma nova função pesquisem sobre ela.

Bem decidi editar aqui para pôr uma imagem para melhor compreensão, afinal uma imagem vale mais do que mil palavras.

buffer_overflow_attack.jpg

Por hoje foi tudo, espero que tenham gostado. Até à próxima.  B)


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Quadrado

Está muito bom, quando andei a estudar esta parte os manuais/livros/tutoriais que utilizei diziam muita coisa mas explicavam pouca, porque para pessoas que estão a iniciar não interessam ainda coisas complicadas, deu para aprender mas uma coisa que facilmente se aprende em 30 minutos com tal excesso de material desnecessário uma pessoa demoraria 1 ou 2 horas, em relação a esta matéria só 3 ou 4 manuais depois é que achei um com uma explicação para isto tão rápida e concisa como esta... Muito bem... B)


Será? Porquê? O quê?   - Estudar Sempre -

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Baderous

É na/no stack que são guardadas as strings.

Todas as strings que são variáveis locais cujo valor não é hard-coded. As strings criadas dinamicamente residem na Heap, as strings literais (escritas pelo programador no código) que são variáveis globais e que são inicializadas como char[] str = "cenas" ficam no Data e as strings (locais ou globais) inicializadas como char * str = "cenas" ficam no Rodata.

- scanf - A função scanf tem as mesmas caracteristicas que a gets no caso de estarmos a ler strings. Não confundam com inteiros e outro tipos de dados.

A função scanf pode ser usada seguramente com strings, indicando o nº máximo de caracteres a ler, tal como a fgets.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Localhost

Baderous, o que eu queria dizer na primeira parte era que também são guardadas as strings no/na stack e não que são apenas guardados no/na stack.

No segundo não conheço isso, podes-me dar um exemplo?


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Baderous
scanf("%80[^\n]",str); ////lê no máximo 80 caracteres para uma string ou, caso o input seja menor que 80, lê até encontrar um '\n' que indica mudança de linha

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.