Segurança
O que é um buffer overflow?
Sab 5 Nov 2005 17:17 |
- Detalhes
- Categoria: Falhas e Exploits
- Atualização: Segunda, 13 Agosto 2007 18:10
- Autor: vovó Vicki
- Acessos: 14769
Existem livros e mais livros que falam de overflow. Por este motivo, não exagere nas suas expectativas porque este texto não pretende concorrer com a literatura existente. É apenas uma explicação simples destinada aos iniciantes.
O que é um overflow
Para entender o que é um overflow, a tradução da palavra ajuda muito. Overflow significa inundação e, quando aplicada como termo da informática, significa um transbordamento que causa uma inundação.
Como os computadores trabalham apenas com bits, as menores unidades de informação, um overflow numa máquina deste tipo nada mais é do que um transbordamento de bits. Mas como acontece um transbordamento de bits?
Os computadores possuem chips especiais chamados de memória. Estes chips especiais recebem o nome de memória porque guardam informações... informações em forma de bits. Quando um programa está sendo executado, a sequência de instruções que deve ser seguida, a instrução que está sendo executada no momento, endereços, valores de constantes, valores de variáveis, etc, ficam armazenados na memória. Para que não haja bagunça, a memória é "loteada", ou seja, são definidas áreas da memória para guardar cada coisa em seu lugar. Estas áreas, assim como em qualquer loteamento, possuem limites e são conhecidas como buffers.
Cada "terreno" da memória (ou buffer), por sua vez, é dividido em células ou posições de memória. Cada uma destas posições é identificada por um número, o chamado endereço de memória. Em cada células pode ser guardado apenas um bit. Quando é preciso guardar bits na memória, o que geralmente é feito em grupos de 8 (byte), 16 (word), 32 (double word) ou 64 (quadword), também é preciso indicar o endereço no qual os bits devem ser colocados. Quando, por exemplo, o valor de uma variável de 32 bits é enviada para um endereço no finzinho do buffer onde, digamos, há apenas 20 células disponíveis, os bits da variável dão uma de MST e 12 deles invadem o terreno de algum vizinho, ou seja, causam um overflow.
Resumindo: um overflow acontece sempre que alguns bits transbordam e invadem uma área que não lhes pertence :mad:
A sequência de execução de um programa
Existem programas muito simples que seguem apenas uma linha de execução. Isto significa que as instruções colocadas no buffer de instruções da memória são seguidas da primeira até a última sem qualquer possibilidade de desvio. Por exemplo, se cada instrução tiver 5 bits (é apenas um exemplo!) e as instruções estiverem armazenadas nos endereços 100 até 200, elas serão executadas sequencialmente, uma atrás da outra: 100, 105, 110... 200.
A maioria dos programas não segue o modelo que acabei de citar. Por exemplo, quando uma determinada tarefa deve ser repetida algumas vezes, costuma-se criar uma subrotina que é chamada toda vez que esta tarefa precisar ser executada. Isto significa que, em determinados pontos da linha principal de execução, ocorre um desvio para uma linha secundária. Para que o programa não "perca o fio da meada", guarda-se o endereço da instrução que chamou a subrotina, a execução é desviada para o endereço desta subrotina e, quando o serviço estiver terminado, ela tem como retornar para o endereço da chamada. Para guardar estes endereços (imagine a linha principal chamando uma subrotina, que chama outra subrotina, que chama outra...) existe uma área especial da memória chamada pilha (stack).
Buffer overflow
Existem dois tipos de buffer overflow, o stack overflow e o heap overflow. O mais fácil de entender é o transbordamento de bits para a área reservada da pilha (stack overflow). Como já vimos, a pilha guarda, entre outras coisas, os endereços de retorno. Se, de repente, a linha de execução entrar por um atalho e, no meio do processamento, houver um stack overflow que injeta bits que atropelam o endereço de retorno, o programa fica sem pai nem mãe - volta para um ponto diferente do ponto de chamada ou então fica perdido de vez. Neste caso, geralmente a máquina trava ou dá algum tipo de mensagem de erro que os mortais comuns não sabem o que quer dizer.
O segundo tipo de buffer overflow é o heap overflow. A área da memória que é ocupada dinamicamente pelo programa é chamada de heap. Quando o programa começa a rodar, ele vai buscar informações no sistema operacional para saber onde há "terrenos" livres, ou seja, áreas de memória disponíveis. É nestas áreas que o programa vai colocar vários dados com as quais irá trabalhar. Este tipo de ocupação é chamado de dinâmico porque é o aplicativo que faz a solicitação e porque, cada vez que o programa é executado, esta área pode ser diferente. Bem, em todo caso, o heap overflow ocorre quando bits invadem a área reservada para o heap.
Explorando os overflows
Além do transtorno que os overflows podem causar, a coisa pode ficar bem mais séria se eles forem usados para injetar código estranho num programa. Estes são os chamados exploits. Novamente, o exemplo mais simples é o exploit de um stack overflow. Os crackers, com frequência, costumam aproveitar este tipo de vulnerabilidade. Como?
Digamos que um aplicativo peça ao usuário que digite um valor. O cracker, sabendo que a checagem do tamanho deste valor não é feita (ou que é mal feita), insere um valor que é bem maior, ou seja, que possui muito mais bits. Como o valor não "cabe" na área que foi designada para esta variável, os bits excedentes invadem a pilha e destroem o endereço de retorno. Até aí, nada de excepcional - o programa vai ficar perdido ou travar. Mas, e se, ao invés de digitar um valor qualquer, os bits excedentes deste valor sejam exatamente os bits que compõem um endereço onde esteja localizado um chamado código malicioso?
Código malicioso é uma sequência de instruções que realizam a tarefa que o cracker quer. O aplicativo, quando encontra o endereço de retorno falso, segue cegamente a ordem, vai para o endereço indicado e executa todas as instruções que encontra pela frente. Se o safado que colocou o código malicioso é dos "bons", ele coloca no fim do código malicioso uma instrução para que o fluxo de execução retorne para o endereço de retorno correto. Moral da história: a máquina ou o aplicativo não travam e, na maioria das vezes, até se descobrir que houve um desvio forçado (com roubo de informações e outras gracinhas), pode ser tarde demais