sexta-feira, 15 de março de 2013

Buffer Overflow

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 é a stack?
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 stack que são guardadas as strings. O que têm de saber da stack é que nele/nela, quando é chamada uma função no vosso programa, é criado um stack frame (imaginem o stack frame como uma divisão da stack, quando temos várias funções são criados vários stack frames). 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:

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:
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.

Lista de funções inseguras e a sua solução
* gets -> fgets;
* strcpy -> strncpy
* strcat ->  strncat
* scanf -> fgets

Lista de funções inseguras e o motivo de o serem
* gets - A função gets, recebe um input e pressupõe que o input nunca seja maior que o buffer que a vai receber.
* strcpy - A função strcpy pressupõe que a string destino tenha capacidade para comportar a string origem.
* strcat - A função strcat pressupõ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 características 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.



Sem comentários:

Enviar um comentário