Continuando a série de artigos sobre vulnerabilidades e exploits hoje vamos falar sobre algumas proteções de memória existentes nos sistemas atuais para prevenir esses tipos de ataques, tanto em ambiente Linux quanto Windows.
Exploits e Proteções de Memória
Longe de esgotar todo o assunto esse artigo estará focado em uma introdução sobre os temas.
É comum ouvirmos falar sobre essas proteções quando ocorrem competições de segurança que são amplamente divulgadas pela mídia especializada. Recentemente ocorreu a Pwn2Own 2011 onde vários softwares foram colocados a prova para hackers tentar invadí-los.
No concurso desse ano o Internet Explorer 8 com todas atualizações rodando no Windows 7 SP1 foi invadido pelo pesquisador Stephen Fewer, que também faz parte do time de desenvolvimento do Metasploit.
Ele explicou que para conseguir passar pelas proteções no IE 8 e Win 7 teve que rodar três exploits diferentes, um para cada proteção: ASLR, DEP e a Sandbox que isola o navegador do sistema operacional para não permitir a propagação de malwares.
Apenas para ilustrar, esse vídeo mostra uma técnica parecida que foi utilizada na competição do ano passado onde o pesquisador Peter Vreugdenhil utilizou dois exploits para passar pelas proteções ASLR e DEP do Windows 7:
Vamos ver agora o que significam essas duas siglas ASLR e DEP.
ASLR – Address Space Layout Randomization
O princípio por trás dessa técnica é sempre atribuir um endereço de memória aleatório para executáveis, bibliotecas, pilha e heap. Assim o atacante não terá um ponto fixo na memória para executar seu código já que a cada execução será atribuído um endereço diferente.
No artigo sobre o Exploit do Buffer Overflow o endereço de retorno foi sobrescrito com um endereço fixo na pilha conforme imagem abaixo:
Nesse Linux o ASLR não estava ativado então toda vez que o programa era executado sempre recebia o mesmo endereço de memória para a formação da pilha. Por isso ao sobrescrever o retorno da função com 0xbfffffd8 sempre iria nos levar para o início da pilha.
Com o ASLR isso não funcionaria, nas próximas execuções do programa seriam atribuídos outros endereços para a pilha. As distribuições Linux e Windows atuais já vêm com o ASLR habilitado por padrão.
Vamos ver o ASLR funcionando, utilizei o BackTrack Linux 4 nos exemplos. Criei o programinha abaixo em C e compilei no gcc 4.3.1:
//find_esp.c
unsigned long find_esp(void){
__asm__("movl %esp,%eax");
}
int main(int argc, char *argv[]){
printf("ESP: 0x%08x\n",find_esp());
}
O programa chama uma função que possui código Assembly Inline e retorna o endereço do registrador ESP (Stack Pointer), assim saberemos qual o endereço da pilha.
Algumas execuções:
Primeiro confirmamos o valor que está em “/proc/sys/kernel/randomize_va_space” que ativa/desativa o ASLR. No início está 2 (ativado), valor padrão das distribuições Linux atuais.
Executamos o programa três vezes e nas três vemos que retornaram valores diferentes, em seguida desativamos o ASLR e vemos que ele retornou o mesmo endereço. Isso é a ASLR em ação.
Resolvi testar o mesmo código no Windows 7, com o Bloodshed Dev-C++ que também usa o gcc como compilador, vejamos a execução:
A princípio imaginei que estaria ativado no Win 7, mas não, os endereços da pilha se repetiram, após pesquisar sobre o assunto descobri que o Win 7 só ativa por padrão a ASLR em arquivos do sistema e existe uma opção no registro para ativar para todos os arquivos. Olha aí uma oportunidade de burlar a ASLR no Win.
Atualização sobre a ASLR no Windows (25/03/2011) Após troca de ideias com o pessoal da lista Exploits-Brasil, ficou mais clara a situação da ASLR no Windows. Funciona por seção e não por execução, a cada reinicialização do sistema o binário vai receber um novo endereço e não a cada execução. Foi implementada somente a partir do Vista e depende do compilador ativá-la ou não. Basicamente no Visual Studio 2005 e 2008 existe a flag /DYNAMICBASE que deve ser utilizada para permitir a ASLR do executável. Já na versão Visual Studio 2010 essa opção está habilitada por default. Detalhes aqui. No exemplo utilizei o Dev-C++, que não possui atualização desde 2005 e não tem a opção de habilitar a ASLR, mas pode ser feito manualmente. Pode-se editar o executável diretamente com algum editor PE, e alterar DllCharacteristics para 0x40 que corresponde a IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, ou então, habilitar o ASLR para todas as aplicações criando uma nova chave no registro com nome "MoveImages" em: HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\ O valor pode ser 0, sem randomização, isso vai manter o base address que está no cabeçalho PE, ou pode ser -1, para habilitar o ASLR, independente de DllCharacteristics. Detalhes aqui. Ainda sobre o Windows 7 existe uma outra particularidade implementada, que é para evitar o respawn de processos, ou seja, se for feita brute-force para descobrir os endereços e o processo for derrubado por mais de três vezes ele não irá mais se reiniciar automaticamente. Contribuições de Rodrigo Rubira e Walison Morales. |
Como um atacante poderia explorar a ASLR?
Basicamente ele deve procurar um local fixo na memória que poderia ser utilizado para “pular” para seu shellcode. Uma código deve ser compilado especificamente para utilizar a ASLR, isso quer dizer que toda vez que for carregado na memória estará em um endereço diferente.
A questão de performance é o maior empecilho para compilar tudo como aleatório, não só porque o arquivo deve ser tratado de forma diferente toda vez que for carregado mas também por causa das otimizações que os compiladores fazem que são prejudicadas com esse tipo de randomização.
Então nem tudo vai estar utilizando a ASLR, inclusive vimos que no próprio Win 7 somente os arquivos de sistema a utilizam. Pode-se utilizar funções de programas de terceiros que não utilizam essa proteção.
A empresa Secunia fez um estudo sobre como anda a implementação da ASLR e DEP em programas populares utilizados no Windows.
DEP – Data Execution Prevention
Essa proteção significa prevenir a execução de códigos localizados na heap, pilha ou seção de dados da memória. É baseada em hardware, mas também por ser implementada por software.
CPUs AMD posteriores a 2004 possuem um bit chamado NX que permite o hardware reconhecer a memória como executável ou não e agir de acordo. Depois a Intel criou o bit XD com as mesmas características.
Isso quer dizer que um shellcode colocado na pilha por exemplo não irá ser executado se o bit NX/XD estiver habilitado como memória não executável.
O Windows utiliza a DEP desde o XP SP2. Aplicações podem ser “linkadas” com a flag “/NXCOMPACT” para habilitar a proteção de hardware. Caso a CPU não suporte isso o Windows irá reverter para DEP por software.
Por questões de compatibilidade e performance a DEP nem sempre estará habilitada.
No Linux existe a “Non-Executable Memory Pages” para proteção de heap e pilha. Tem a mesma função da DEP, mas é implementada por um patch no Kernel, o Page-eXec – PaX, que tenta controlar a execução de código na pilha e heap.
O Red Hat Enterprise e Fedora oferecem a implementação dessa proteção através do ExecShield.
Como um atacante poderia explorar a DEP?
Em poucas palavras ele deve procurar áreas não protegidas contra execução na memória para conseguir seu objetivo.
A técnica que introduziu esse conceito é a chamada return to libc. Ao invés de colocarmos nosso shellcode para ser executado na pilha que está protegida contra execução, redirecionamos o retorno do programa para uma área não protegida como por exemplo a biblioteca glibc que armazena as funções principais da linguagem C.
Então na pilha o código para sobrescrever o EIP seria o endereço da função system() (que executa um programa no sistema) localizada na glibc, passando o local do programa que queremos executar “/bin/sh”. Simplificando colocaríamos esse código na pilha:
PUSH “/bin/sh”
CALL system()
Isso quer dizer que efetivamente não seria a pilha (que está protegida com DEP) que executaria o shell e sim a libc.
ASLR + DEP – proteção eficaz
Apesar de ser possível explorar as duas técnicas separadamente, juntas apresentam uma ótima proteção contra exploits. Por exemplo utilizando a técnica “return to libc” para passar a DEP com a ASLR ativada não teríamos como saber o endereço exato da função system() na libc já que a cada execução estaria em um local diferente da memória.
Como vimos existem falhas, seção de códigos que não são aplicadas as proteções, programas de terceiros vulneráveis, etc. A partir disso o atacante consegue ter sucesso.
Para finalizar deixo esse trecho de um artigo da Microsoft falando sobre quais são as intenções deles ao trabalhar nessas proteções:
“Ultimately our goal with exploit mitigations is to reach a point where vulnerabilities become too expensive to reliably exploit - and this is a goal we are actively working toward.“
Tradução livre:
“Em última análise nosso objetivo com as proteções contra exploits é atingir um ponto onde vulnerabilidades se tornem muito caras para serem Isso mostra a consciência que eles têm que sempre vai haver um meio de explorá-las porém cada vez vai ficando mais trabalhoso e caro.