Jump to content
  • As Diferentes Proteções de Executáveis

       (1 review)

    R3tr074
     Share

    Durante o estudo de exploração de binários executáveis, uma das primeiras e mais importantes coisas que vemos são as proteções como NX, PIE, ASLR, de entre outras. Hoje vamos ver um pouco mais de perto cada uma delas.

     

    NX

    No eXecute (NX) é uma das proteções mais simples e mais lógica, implementada por volta de 2004. Durante a execução de um binário sem essa proteção ativada, a sua stack, heap e outras regiões possuíam poder de execução, simples assim.

    Os processadores da família x86 tardaram muito para implementar o bit NX, que basicamente é uma forma de sinalizar uma página em memória como executável ou não. Isso gerou projetos para tentar emular tal proteção via software, como o Exec Shield, um projeto da Red Hat que continha um patch no kernel do Linux para emular o funcionamento do NX.

    nx-bit.thumb.png.8a14dd2ca0ceed28f2a4759db0bbebca.png

    No kernel Linux, o suporte para o NX foi adicionado oficialmente em 2004. Patches como o mencionado acima, do Exec Shield, já existiam desde 2002. No Windows, a proteção está presente desde 2003 com o nome de DEP (Data Execution Prevention), porém a DEP emulada via software funciona de uma forma diferente: ela não se baseia no bit NX, mas sim checando sempre que uma exceção é realizada se o endereço da execução bate com a tabela de funções do binário.

    Essa proteção é ativada ou não durante o carregamento do binário na memória. No Linux isso é controlado com uma flag exec no segmento PT_GNU_STACK do binário. Já no Windows, as configurações ficam no arquivo Boot.ini, podendo ter até quatro opções diferentes:

    • OptIn: Apenas em binários do sistema a proteção é ativada.
    • OptOut: A DEP é ativada por padrão para todos os processos.
    • AlwaysOn: Todos os processos têm a DEP ativada e não existe a possibilidade de desativar para um processo específico.
    • AlwaysOff: A proteção não é habilitada para nenhum processo.

     

    PIE/PIC

    O Position-Independent Executable (PIE) ou Position-Independent code (PIC) não é em si uma proteção, mas uma técnica para criar código, assim como o nome diz, independente de posição. Isso significa que, onde o código for alocado, ele conseguirá executar sem problemas, diferente de binários comuns, os quais precisam ser carregados em lugares específicos para fazerem referências de forma correta. Essa técnica é usada principalmente para bibliotecas (shared libraries).

    library-calls.thumb.jpg.06ac089463e4a751ffdbe0f598fa4494.jpg

    O problema disso durante a exploração é que os endereços do binário também são randomizados com a ASLR, proteção que vai ser explicada a seguir, impossibilitando, assim, conhecer os endereços do binário e consequentemente utilizar Return Oriented Programming (ROP) para explorar uma vulnerabilidade deixa de ser viável.

    A solução para fazer bypass dessa proteção é conseguir um vazamento (leak) de memória, pois é possível calcular a base já que os offsets continuam os mesmos.

    Como o PIE é uma forma de gerar código, não é possível "desabilitá-lor", porém se a ASLR estiver desligada, o endereço base se manterá o mesmo, não tento efeito prático para mitigar uma ROP, por exemplo.

     

    ASLR

    A Address Space Layout Randomization (ASLR), assim como o nome diz, tem a função de randomizar endereços como os da heap, stack e bibliotecas. Como uma proteção em nível de sistema, cada sistema operacional mantém uma implementação própria.

    aslr-example.png.7dd4f1b6ae762d2bb5051ec7add94814.png

    No Linux, a ALSR já está presente desde a sua versão 2.6.12, lançada em 2005. Executáveis PIE também possuem um endereço base randômico desde 2003, porém ambos com uma implementação fraca e com pouca aleatoriedade. O PaX e o Exec Shield (mencionado acima) foram responsáveis por patches com uma implementação mais complexa e segura. O endereço da stack com essas alterações podem ter até 524.288 variações diferentes.

    Por padrão, a ASLR é configurada no Linux através do arquivo /proc/sys/kernel/randomize_va_space e pode possuir três valores diferentes: 0 para desabilitar, 1 para randomizar stack, bibliotecas e executáveis PIE e 2, o valor mais alto, para randomizar também a base da heap. É possível, também, ativar ou desativar para processos isoladamente usando um recurso chamado personality .

    O Windows teve sua implementação da ASLR lançada em 2007 com uma abordagem diferente: a ASLR só é ativada em executáveis e DLLs que possuírem uma "flag" no processo de linkagem e todos os membros precisam possuir essa "flag". Por exemplo, suponha que A.exe dependa de B.dll e C.dll. Caso C.dll não tenha ASLR habilitada, A.exe não terá a proteção ligada. Hoje em dia essa é uma situação rara, pois apenas programas mais antigos não possuem suporte para ASLR.

     

    Canary

    O canary é uma proteção muito interessante. Ao compilar algum código com essa proteção, o compilador adiciona um fragmento de código no começo e no final de cada função. No prólogo da função, se cria uma variável local na stack com um valor aleatório e no final se acessa essa mesma variável para verificar a integridade do valor, validando se continua o mesmo. Caso tenha mudado, uma função de callback é chamada para gerar um abort, assim evitando transbordamentos de memória. O GCC, LLVM, Intel compiler entre outros compiladores possuem implementações do canary.

    stack-canary-illustration.thumb.png.c0b232d49d8375915cee94c89605bc25.png

    O valor aleatório citado acima é o chamado canary ou stack cookie. Esse cookie pode ser classificado de três formas:

    terminator
    O terminator Canary se baseia na observação de que a maioria das vulnerabilidades de buffer overflow acontecem em cenários de manuseio de strings que finalizam com um null byte (\0). Em contrapartida, o cookie é construído com null byte (\0), CR (\r), LF (\n) e FF (\f). Como resultado, isso mitiga um buffer overflow em funções como strcpy(), pois, mesmo sabendo o valor do cookie, não é possível copiá-lo com esse tipo de funções, já que ela ira retornar assim que ler o nullbyte.

    random
    Neste tipo, Random Canaries são gerados randomicamente a cada execução a partir de alguma fonte de entropia. Além disso, esse valor não é facilmente lido, pois no carregamento do binário esse valor é armazenado em uma variável global, que é alocada em uma região não mapeada de memória para dificultar ainda mais seu acesso.

    As formas mais viáveis de ler o cookie são com um vazamento da stack ou sabendo o endereço exato da variável global.

    random XOR
    O random XOR Canary é o tipo mais complexo. Seu valor é basicamente determinado a partir de operações XOR de vários valores de controle, como stack pointer, endereço de retorno, etc. Dessa forma, se o Canary ou os dados usados no cálculo forem corrompidos, o programa irá gerar um abort. Para conseguir enganar essa checagem de integridade, é necessário vazar não apenas o cookie, mas também os dados usados no cálculo e o próprio algoritmo para gerar o mesmo.

     

    RELRO

    A RELocation Read-Only (RELRO) é uma proteção exclusiva do Linux, ou melhor, do formato ELF, que tem como intenção deixar as seções relacionadas a realocação como somente leitura (read-only). As seções de realocação, de forma resumida, são onde são armazenados os endereços de funções externas, como as da libc. Por padrão, essas regiões de memória possuem permissão de leitura e escrita (read/write), pois normalmente é utilizada lazy bind, uma forma de resolver esses endereços não em tempo de carregamento, mas durante a execução, logo antes da chamada.

    got-graph.png.a394b5278e1d0b9c3a5fcd0c82cd40ef.png

    Essa proteção foca exatamente nessa região de meória. A realocação dos endereços é feita antes de passar o controle para o programa e a região é marcada como somente leitura, impossibilitando, assim, que um atacante a sobescreva com endereços maliciosos.

    Existem dois tipos de RELRO: partial e full, onde a partial marca como somente leitura a maioria das seções, exceto a Global Offset Table (GOT), na seção .got.plt. Já a full, como se deve imaginar, força que todos os símbolos e endereços sejam resolvidos durante o carregamento do binário, permitindo que a GOT seja completamente read-only.

     

    Referências

    - A hardware-enforced BOF protection:
      - http://index-of.es/EBooks/NX-bit.pdf
    - Windows ISV Software Security Defenses
      - https://docs.microsoft.com/en-us/previous-versions/bb430720(v=msdn.10)
    - Position-Independent Code with GCC for ARM Cortex-M
      - https://mcuoneclipse.com/2021/06/05/position-independent-code-with-gcc-for-arm-cortex-m/
    - Effect of ASLR to Memory Deduplication
      - https://www.semanticscholar.org/paper/Effect-of-ASLR-to-Memory-Deduplication-Ratio-in-)-Piao-Sung/3f74d25c72322315ec3b6552e6c3d4413af95022
    - Exploit Protection Mechanisms
      - https://ocw.cs.pub.ro/courses/cns/labs/lab-06
    - Hardening ELF binaries using Relocation Read-Only (RELRO)
      - https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro

     


    • Agradecer 1
    • Curtir 3
    • l33t 1
     Share


    User Feedback

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.
    Note: Your post will require moderator approval before it will be visible.

    Guest

    • This will not be shown to other users.
    • Add a review...

      ×   Pasted as rich text.   Restore formatting

        Only 75 emoji are allowed.

      ×   Your link has been automatically embedded.   Display as a link instead

      ×   Your previous content has been restored.   Clear editor

      ×   You cannot paste images directly. Upload or insert images from URL.


    Kirito

       1 of 1 member found this review helpful 1 / 1 member

    Um dos melhores Posts sobre proteções de binários que já vi.

    Link to review
    Share on other sites


  • Similar Content

×
×
  • Create New...