sexta-feira, 2 de julho de 2010

Resumo do Artigo Beyond Stack Smashing Recent Advances in Exploiting

Jonathan Pincus é pesquisador sênior da Microsoft Research, e Brandon Baker, engenheiro de segurança de desenvolvimento da Microsoft. Neste artigo, eles descrevem três famílias de ataques derivados do estouro de buffers.

O estouro de buffers ocorre quando um programa tenta ler ou escrever além do limite declarado de um array (o referido buffer). Nas linguagens C e C++ não existe nenhum tipo de checagem de extrapolação de limites, ao contrário do que acontece com as linguagens Pascal, Java e C# por exemplo. O estouro de buffer pode ainda ser caracterizado como estouro de buffer da pilha ou estouro de buffer do heap, dependendo do tipo de memória utilizada – no primeiro caso trata-se de variáveis estáticas, localizadas na pilha de execução, ao passo que no segundo caso trata-se de variáveis dinâmicas, localizadas no heap.

A abordagem tradicional do estouro de buffer é o stack smashing: a modificação do endereço de retorno presente na pilha de execução de maneira a alterar o fluxo de execução do programa. Ao invés de apontar para o retorno, o endereço aponta para código malicioso armazenado em determinado local pelo atacante.

No artigo, os autores apresentam 3 novos tipos de ataques desta natureza, afim de que a compreensão do funcionamento dos ataques leve a melhores estratégias de segurança. A seguir, cada um deles é brevemente apresentado.

Arc injection
Este ataque é orientado a dados. Ao invés de também inserir código executável malicioso para que seja desviado o fluxo de execução até ele, um atacante pode apenas fornecer dados tais que quando o programa original operar sobre os mesmos, o objetivo do ataque também será atingido. Um exemplo deste tipo de ataque são comandos de sistema que o programa atacado passa a utilizar para criar novos processos, o que permite a execução arbitrária de código.

Um exemplo deste ataque é o estouro de buffer para desviar o fluxo de execução para uma chamada SYSTEM() presente no código do próprio programa, onde as verificações de integridade dos parâmetros podem ser puladas e o parâmetro é um dado armazenado pelo atacante.

Pointer Subterfuge
Este ataque consiste em alterar o valor de ponteiros. Existem pelo menos quatro versões deste tipo de ataque:

- Function-Pointer Clobbering: Alteração do valor de um ponteiro para um local com código malicioso;

- Data-Pointer Modification: Alteração de locais arbitrários da memória como isca, na expectativa de que tais locais sejam utilizados em alguma atribuição, fazendo com que se obtenha poder também sobre outras áreas da memória que forem fisgadas;

- Exception-Handler Hijacking: Quando um programa lança uma exceção, o Windows examina uma lista encadeada que armazena manipuladores de exceção e invoca um ou mais via ponteiros para o tratamento da exceção. O ataque consiste em alterar tal ponteiro via estouro de buffer, permitindo que ao invés de invocar um manipulador de exceção, o fluxo de execução seja desviado.

- Virtual Pointer (VPTR) Smashing: A maioria dos compiladores C++ implementa funções virtuais através de uma tabela de funções virtuais (VTBL) associada a cada classe. A VTBL é um array de ponteiros para funções utilizados em tempo de execução para implementar o despacho dinâmico. Objetidos individuais apontam para a VTBL apropriada através de ponteiros virtuais (VPTR) armazenado no header do objeto. Substituindo-se o VPTR de um objeto com um ponteiro para código malicioso faz com que o fluxo seja desviado na próxima vez em que uma função virtual for invacada.

Heap Smashing
Ao contrário do que se pensava até recentemente, não são apenas os buffers da pilha de execução vulneráveis a este tipo de ataque. Alocadores de memória dinâmica mantém headers para cada bloco do heap, ligados duplamente em listas encadeadas de blocos alocados e liberados. Tais headers são atualizados a cada operação sobre a memória (alocação e liberação).

Se houverem três blocos de memória contíguos X, Y e Z, e houver estouro de buffer em X de forma que os ponteiros do header de Y sejam modificados, pode ocorrer modificação de uma parte arbitrária da memória quando X, Y e Z forem liberados.

Referência
Pincus, J.; Baker, B. Beyond Stack Smashing: Recent Advances in Exploiting Buffer Overruns. Security & Privacy, IEEE Volume 2, Issue 4, July-Aug. 2004 Page(s): 20 – 27. Disponível em: http://ieeexplore.ieee.org/iel5/9141/29316/01324594.pdf. Acesso em 02 de Junho de 2010.

quinta-feira, 1 de julho de 2010

Reflections on Trusting Trust by Ken Thompson

Ken Thompson recebeu o prêmio Turing pela ACM (Association for Computing Machinery) em 1983 pelo desenvolvimento da teoria de sistemas operacionais e pela implementação do sistema operacional UNIX. O autor se auto-denomina um programador, e em três etapas descreve a criação de um trojan. Um programa que se auto-replica, através de um compilador

Na primeira etapa o autor descreve a criação de um programa que se auto-replique. Na segunda etapa, o autor utiliza o exemplo do compilador C, desenvolvido em liguagem C para demonstrar que existem falhas sobre como compilar em C um novo compilador com instruções diferentes. Haveria inconsistências, uma vez que o compilador original não reconhecerá as novas instruções, o que leva a alterações em mais baixo nível no compilador original, possibilitando que ele seja compilado. Na etapa 3, o autor apresenta a introdução de código malicioso no novo compilador, o qual descompila o comando “login” e o compila novamente para aceitar uma senha mestra, além da senha correta. Se o código malicioso for auto-replicante e atacar o código-fonte de um compilador, é possível utilizar o binário malicioso como original e apagar o código fonte malicioso, não deixando rastros. Desta forma, teríamos um código-fonte limpo e um binário malicioso, que se auto-replicaria a cada compilação.

O autor chega à conclusão de que não se pode confiar em códigos não escritos por você mesmo, não importando o nível de verificação de códigos-fonte podem nos assegurar quando se utiliza códigos não confiáveis. À medida que o nível dos códigos abaixa (compilador, assembler, liguagem de montagem, carregador ou mesmo microcódigo de hardware), mais difícil é a detecção de possíveis “bugs”.

Por fim, o artigo conclui que a segurança fica comprometida quanto mais dependermos de códigos de terceiros. Ken afirma que apenas um código desenvolvido por você mesmo pode ser dito como um código confiável. O autor também enfatiza que o acesso não autorizado a computadores alheios é crime e deve ser levado a sério.

Pontos Principais do Artigo

  • Não existe código confiável, exceto o de sua autoria;
  • À medida em que o nível dos códigos-fonte diminui, mais difícil é a detecção de código malicioso;
  • Ainda no ano de 1984 o autor já alertava sobre as falhas nos códigos penais a respeito de crimes digitais, e ainda alertava sobre a gestação de uma “situação explosiva”.


Referência


[1] Thompson, Ken. Reflections on Trusting Trust.Communications of the ACM, 1984, vol. 27, n. 8, 761-763. Disponível em: http://portal.acm.org/citation.cfm?id=358210.