Este tutorial faz parte do GUIA COMPLETO do skilled em Segurança Ofensiva de Software program, saiba mais.
Aula 24: Proteções
Os ataques de exploração de vulnerabilidades, especialmente os que envolvem corrupção de memória como buffer overflows, motivaram o desenvolvimento de uma série de mecanismos de segurança no nível do sistema operacional e do compilador. Estas proteções de memória são barreiras essenciais que dificultam a execução de código malicioso e o desvio do fluxo de execução de um programa.
Aula 24.1: Canários
Os Cookies (também conhecidos como Canários) são um mecanismo criado para proteger contra ataques de transbordamento de buffer de pilha (stack buffer overflow).
- Origem do Nome: O termo “Canário” tem origem histórica, referindo-se aos pássaros utilizados em minas para alertar sobre a baixa concentração de oxigénio — um alerta precoce de perigo.
- Funcionamento: É um marcador aleatório inserido na pilha, posicionado estrategicamente entre um buffer native (como uma variável string) e o endereço de retorno da função. Se ocorrer um transbordamento no buffer, o atacante terá de sobrescrever o cookie antes de atingir o endereço de retorno.
- Verificação: Uma instrução de checagem é inserida no epílogo (o ultimate) da função. Antes de usar o endereço de retorno, a função verifica se o valor do cookie foi alterado. Se o valor for diferente do authentic, o sistema detecta o ataque e aborta o processo.
![]() |
Figura 1: Exemplo de COOKIE |
- Implementação: Pode ser inserido em tempo de compilação (método mais comum, como no GCC com a flag -fstack-protector e no Visible Studio com /GS) ou em tempo de execução por meio de “funções empacotadoras” (wrappers), sendo esta última opção usada para proteger sistemas legados sem a necessidade de recompilação, embora acarrete um overhead de desempenho.
- Bypass: Técnicas avançadas, como a exploração de Tratadores de Exceções Estruturadas (SEH) no Home windows, permitiam que o atacante desviasse o fluxo do programa para código malicioso antes que a checagem do cookie fosse realizada.
Aula 24.2: SafeSEH e SEHOP
SafeSEH (Protected Structured Exception Dealing with) e SEHOP (Structured Exception Dealing with Overwrite Safety) são proteções específicas do ambiente Home windows, desenvolvidas para mitigar a exploração de uma vulnerabilidade na forma como o sistema lida com exceções estruturadas.
- Motivação: Os ponteiros para os tratadores de exceção ficavam na pilha e podiam ser sobrescritos antes da checagem do cookie.
- Objetivo: Estas proteções asseguram a integridade da cadeia de tratadores de exceção na pilha, impedindo que um atacante a corrompa para desviar a execução para o seu código.
Aula 24.3: ASLR
O Handle House Structure Randomization (ASLR), e seu análogo Rebase, é uma técnica basic para combater ataques de reutilização de código.
- Funcionamento: Embaralha (randomiza) os endereços de memória de áreas-chave do processo, como a pilha, o heap e as bibliotecas dinâmicas (DLLs ou bibliotecas compartilhadas), a cada inicialização do programa ou do sistema.
- Objetivo: Ao tornar os endereços imprevisíveis, o ASLR impede que um atacante saiba para onde desviar o fluxo de execução (ex: um endereço de uma função útil em ROP), o que tornaria a maioria dos ataques de reutilização de código ineficazes.
- Implementação: Está implementado no Linux (kernel 2.6.12+), com a randomização ocorrendo durante a carga do processo, e no Home windows (Vista/Server 2008+), com a randomização feita durante a inicialização do sistema operacional.
- Bypass: Pode ser contornado se um binário ou biblioteca não for compilado com a flag de suporte a ASLR (ex: /DYNAMICBASE), fixando seus endereços. Outros bypasses incluem o uso de heap spraying, vazamento de endereços de memória ou técnicas de força bruta.
Aula 24.4: Pilha Não-Executável (nx-stack)
A proteção nx-stack (Non-Executable Stack) impede que um atacante execute instruções na área de memória da pilha (stack) de um processo.
- Funcionamento: Marca a região da pilha como não-executável, prevenindo a execução de shellcode injetado na pilha.
- Implementação: É uma proteção basic implementada desde 1996 nos principais sistemas operacionais, incluindo Linux, OpenBSD, Mac OS X, Solaris e Home windows.
Aula 24.5: DEP
Prevenção de Execução de Dados (DEP), também conhecida pelo princípio Write xor Execute (W^X), é uma proteção implementada no {hardware} (pelo bit NX/XD) e no sistema operacional.
- Funcionamento: Impede que o código seja executado a partir de páginas de memória marcadas como dados, como as regiões de pilha (stack) e heap.
- Objetivo: É uma medida primária contra a injeção de código, complementando a nx-stack ao estender a proteção a outras áreas de dados do processo.
- Implementação: Está presente em sistemas como Linux (kernel 2.6.8+) e Home windows (XP SP2+), sendo ativada em binários compilados com flags específicas (ex: /NXCOMPACT no Visible Studio).
- Bypass: A DEP pode ser contornada por técnicas de reutilização de código, como Return-Oriented Programming (ROP) ou ret2libc, que utilizam trechos de código legítimo do próprio programa ou das suas bibliotecas para executar ações maliciosas.
Aula 24.6: Filtros de dados
Os Filtros de Dados atuam na sanitização e validação da entrada (enter) de um programa, sendo uma linha de defesa essential contra vulnerabilidades que se originam de dados não confiáveis.
- Objetivo: Garantir que o dado introduzido por um utilizador ou por outra fonte externa seja seguro, restringindo a sua forma e conteúdo ao que é estritamente esperado.
- Exemplos de Restrições:
- Tamanho: Limitar o comprimento de uma string para evitar buffer overflows (ex: máximo de 256 bytes).
- Tipo de Caracteres (whitelist): Permitir apenas um conjunto restrito de caracteres (ex: nome de arquivo só pode ter letras, números e hifens: a-z, A-Z, 0-9, -).
- Caracteres “Badchars”: Remover ou codificar caracteres que têm um significado especial e perigoso no contexto de um ataque, como o Byte Nulo (0x00), que é usado para terminar strings e pode parar a execução de um shellcode.
- Bypass: A técnica de bridge constructing é um exemplo de como atacantes tentam codificar blocos de instruções ou instruções individuais para evitar a detecção por filtros que procuram por badchars no código injetado.
Aula 24.7: Assinaturas
O conceito de Assinaturas é amplamente utilizado por sistemas de deteção de intrusão, antivírus e outros softwares de segurança para identificar a presença de código malicioso conhecido.
- Funcionamento: Uma assinatura é uma sequência de bytes única de um malware ou de um binário de ataque conhecido. O sistema de segurança compara o binário (ou partes dele) com uma base de dados de assinaturas (muitas vezes otimizada com tabelas hash para agilidade).
- Aplicação: Usado por Antivírus, Sistemas de Prevenção de Intrusão (IPS), entre outros.
- Bypass: Os atacantes utilizam diversas técnicas para alterar o código malicioso sem mudar a sua funcionalidade, fugindo assim à deteção baseada em assinaturas:
- Encoders/Ofuscação de Código: Codificam o shellcode para que a sequência de bytes não corresponda à assinatura authentic.
- Inserção de Lixo (Junk Code): Adicionam instruções inócuas para modificar o padrão de bytes do programa.
- Troca de Instruções/Registos: Substituem instruções equivalentes (ex: usar PUSH/POP em vez de MOV) ou trocam registos e variáveis entre operações para criar um binário funcionalmente idêntico, mas com uma assinatura de bytes diferente.