Jump to content

Search the Community

Showing results for tags 'elf'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Supporter area
    • Tools of the Trade
    • Finance transparency
  • MBConf
    • MBConf v1
    • MBConf v2
    • MBConf v3
  • Mente Binária
    • General
    • Computer Architecture
    • Certifications
    • Quantum computing
    • Cryptography
    • Challenges and CTF
    • Hardware Hacking
    • Electronics
    • Conferences
    • Forensics
    • Games
    • Data privacy and laws
    • Code breaking
    • Networking
    • Pentest
    • Speak to us!
    • Software releases
  • Career
    • Study and profession
    • Jobs
  • Reverse Engineering
    • General
    • Malware Analysis
    • Firmware
    • Linux and UNIX-like
    • Windows
  • Programming
    • Assembly
    • C/C++
    • Python
    • Other languages
  • Operating Systems
    • GNU/Linux and UNIX-like
    • Windows
  • Segurança na Internet's Discussão

Categories

  • Portal Mente Binária
  • Specials

Categories

  • Tech basics
    • Text comprehension
    • English
    • Mathematics
  • Computing Basics
    • Lógica de Programação
    • Computers Architecture
    • Cryptography
    • Data Structures
    • Network
    • Operating Systems
  • Specifics
    • SO Internals
    • Web
    • Python
    • Javascript
    • Infrastructure
    • Go
    • Reverse Engineering
    • DevOps
    • C/C++
    • Log Analysis

Categories

  • Crackmes
  • Documentation
  • Debuggers
  • PE tools
  • Books
  • Util
  • Packers
  • Unpackers
  • Virtual Machines

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


GitHub


Twitter


LinkedIn


Website

Found 4 results

  1. 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. 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). 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. 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. 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. 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
  2. Cá estava eu programando com o nasm, tentando (apenas tentando mesmo) reproduzir os wrappers de systemcall que existem na glibc, quando me deparei com o tamanho de um bináriozinho em assembly que só retorna um valor, um "hello world" no nasm, ali no canto do diretório. O binário tinha 4.2K, nada realmente muito pesado, mas para um programa que não utiliza nenhuma biblioteca e só retorna um valor me pareceu muito estranho. Código do programa: BITS 32 global _start _start: mov eax, 1 mov ebx, 10 int 0x80 Para compilar e testar: [mario@zrmt rivendell]$ nasm -f elf32 elrond.asm [mario@zrmt rivendell]$ ld -m elf_i386 -s elrond.o -o elrond [mario@zrmt rivendell]$ ./elrond [mario@zrmt rivendell]$ echo $? 10 Aqui vai o hexdump do binário: [mario@zrmt rivendell]$ hexdump -C elrond 00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 02 00 03 00 01 00 00 00 00 90 04 08 34 00 00 00 |............4...| 00000020 20 10 00 00 00 00 00 00 34 00 20 00 02 00 28 00 | .......4. ...(.| 00000030 03 00 02 00 01 00 00 00 00 00 00 00 00 80 04 08 |................| 00000040 00 80 04 08 74 00 00 00 74 00 00 00 04 00 00 00 |....t...t.......| 00000050 00 10 00 00 01 00 00 00 00 10 00 00 00 90 04 08 |................| 00000060 00 90 04 08 0c 00 00 00 0c 00 00 00 05 00 00 00 |................| 00000070 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00001000 b8 01 00 00 00 bb 2a 00 00 00 cd 80 00 2e 73 68 |......*.......sh| 00001010 73 74 72 74 61 62 00 2e 74 65 78 74 00 00 00 00 |strtab..text....| 00001020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00001040 00 00 00 00 00 00 00 00 0b 00 00 00 01 00 00 00 |................| 00001050 06 00 00 00 00 90 04 08 00 10 00 00 0c 00 00 00 |................| 00001060 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 |................| 00001070 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................| 00001080 0c 10 00 00 11 00 00 00 00 00 00 00 00 00 00 00 |................| 00001090 01 00 00 00 00 00 00 00 |........| 00001098 Da pra perceber que de 0x72 à 0xfff todos os bytes são 0. Humm... suspeito. Não sou especialista e posso estar terrívelmente errado, mas não lembro dessa quantidade de zeros no manual do formato ELF. Se abrirmos o binário com o readelf veremos o seguinte: [mario@zrmt rivendell]$ readelf elrond -h ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x8049000 Start of program headers: 52 (bytes into file) Start of section headers: 4128 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 2 Size of section headers: 40 (bytes) Number of section headers: 3 Section header string table index: 2 Três Section Headers, dois Program Headers e mais um bando de coisa. Como não precisamos das seções para executar o programa irei ignorá-las por agora. Não precisamos das seções para executar o programa devido ao fato de que elas são feitas para auxiliar o linker no momento de construção do binário. Como o binário já está construído e nenhuma das seções representa objetos dinâmicos, elas podem ser ignoradas. Então vamos diminuir esse programa aí. Primeiramente, devemos descobrir o endereço base do programa, para isto, basta pegar o entrypoint (0x8049000) e diminuir o offset do Program Header que tem a flag de executável (que vai conter o devido código do programa). Lembrando que o entrypoint é composto pelo endereço base do programa (para ser mapeado em memória) + “endereço” (no arquivo) do primeiro byte que corresponde ao código executável. O que vamos fazer aqui é achar esse primeiro byte, que pode ser encontrado no Program Header, onde se tem a flag de executável que recebe o nome de p_offset. Vejamos o readelf -l: [mario@zrmt rivendell]$ readelf -l elrond Elf file type is EXEC (Executable file) Entry point 0x8049000 There are 2 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08048000 0x08048000 0x00074 0x00074 R 0x1000 LOAD 0x001000 0x08049000 0x08049000 0x0000c 0x0000c R E 0x1000 Section to Segment mapping: Segment Sections... 00 01 .text Para ajudar: de acordo com o manual o campo p_offset é “O offset do início do arquivo onde o primeiro byte do segmento se encontra”. Como estamos lidando com um segmento executável esse primeiro byte vai ser o início do nosso código. Então dá para ver que o segundo Program Header (que possui a flag de executável) tem offset 0x001000! Então o endereço base é 0x08048000 (0x08049000 - 0x00001000) ! Já que temos o endereço base podemos excluir os zeros (caso contrário o programa ficaria quebrado e não iríamos conseguir analisá-lo com o readelf), alto lá! Apenas os inúteis! Mas quais são os inúteis ? Todos os que os Program Headers apontam, pois esses serão os bytes do programa mapeados em memória, então vamos deixar eles lá. Vou usar o hyx como editor hexa, mas o hte também funciona. Após excluirmos todos os zeros entre 0x74 e 0x1000: [mario@zrmt rivendell]$ hyx elrond 0000> 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 0010: 02 00 03 00 01 00 00 00 00 90 04 08 34 00 00 00 |............4...| 0020: 20 10 00 00 00 00 00 00 34 00 20 00 02 00 28 00 | .......4. ...(.| 0030: 03 00 02 00 01 00 00 00 00 00 00 00 00 80 04 08 |................| 0040: 00 80 04 08 74 00 00 00 74 00 00 00 04 00 00 00 |....t...t.......| 0050: 00 10 00 00 01 00 00 00 00 10 00 00 00 90 04 08 |................| 0060: 00 90 04 08 0c 00 00 00 0c 00 00 00 05 00 00 00 |................| 0070: 00 10 00 00 00 b8 01 00 00 00 bb 2a 00 00 00 cd |...........*....| 0080: 80 00 2e 73 68 73 74 72 74 61 62 00 2e 74 65 78 |...shstrtab..tex| 0090: 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |t...............| 00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 0b 00 00 |................| 00c0: 00 01 00 00 00 06 00 00 00 00 90 04 08 00 10 00 |................| 00d0: 00 0c 00 00 00 00 00 00 00 00 00 00 00 10 00 00 |................| 00e0: 00 00 00 00 00 01 00 00 00 03 00 00 00 00 00 00 |................| 00f0: 00 00 00 00 00 0c 10 00 00 11 00 00 00 00 00 00 |................| 0100: 00 00 00 00 00 01 00 00 00 00 00 00 00 |.............| Ahh muito mais enxuto! Porém o bicho tá todo quebrado. Se executarmos: [mario@zrmt rivendell]$ ./elrond Bus error (core dumped) Um “Bus error” não é nada mais que uma tentativa de read ou write em um espaço de memória desalinhado. Como citado no manual os mapeamentos tem que ser alinhados com as páginas de memória, ou seja, 4KB. Vamos consertá-lo! Vamos ter que consertar: o entrypoint e o mapeamento do segundo Program Header, ou seja, seu endereço virtual, físico e seu offset. Como estamos alterando as posições dos segmentos (isto é, o nome oficial para o que um Program Header mapeia) teremos que alterar seu mapeamento no arquivo junto com o entrypoint (que aponta para o primeiro byte de um segmento executável). Na verdade, o endereço físico pode ser ignorado, o manual cita que os “System V” ignoram endereços físicos de aplicações, mas iremos adicioná-los em prol da completude. Revisando... o entrypoint vai ser o endereço base mais o offset do segundo Program Header, e esse offset vai ser 0x75 (lembre-se que era 0x1000, mas com a retirada dos zeros entre 0x74 e 0x1000 efetivamente reduzimos o entrypoint em 0xFFF - 0x74 = 0xF8B, logo, o entrypoint vai ser 0x1000 - 0xF8B = 0x75) então nosso entrypoint vai ser 0x08048075. Esse também vai ser o endereço virtual e o endereço físico do header. Então troquemos: O entrypoint no Header ELF por 0x08048075 O offset do section header por 0x00000075 Os endereços virtuais e físicos do segundo Program Header por 0x08048075 Agora mais do que nunca teremos que ter atenção. Saque seu editor de hexa preferido e lembre-se que estamos lidando com little endian. Vou usar o hyx, que é um editor hexa um pouco parecido com o vi: No terminal de cima temos o arquivo original sem os zeros, já no de baixo temos o arquivo já alterado. Para ajudar: Vermelho: Entrypoint Amarelo: Offset do Header Verde: Endereço Virtual do Header Azul: Endereço Físico do Header Agora se executarmos: [mario@zrmt rivendell]$ ./elrond [mario@zrmt rivendell]$ echo $? 10 Como disse lá em cima, não alterei as seções e nesse caso (binário já linkado e sem bibliotecas dinâmicas) elas não são importantes. Tente ler elas pra ver o que acontece. No fim passamos de 4.2k para ... [mario@zrmt rivendell]$ ls -lh elrond -rwxr-xr-x 1 mario mario 269 --- -- --:-- elrond 269! Achei que a galera poderia gostar dessa pequena aventura, acho bem interessante principalmente para aprender bem sobre o formato. Se gostarem tenho planos pra parte dois!
  3. Pessoal... Ontem achei um artigo na Internet bem escrito, interessante e detalhado sobre Engenharia Reversa em ELF. É um reversing básico, mas não tããããão básico assim. Acho que vale a pena conferir. http://manoharvanga.com/hackme/ Valeu!
  4. Olá, Estamos enviando pelos links abaixo alguns binários executáveis (ELF 64-bit LSB) que realizam tarefas bem simples, que podem ou não ser úteis. O exercício é que você descubra o que esses binários fazem, utilizando as ferramentas que julgar mais adequadas. Como resposta, espero que você me diga o que acha que eles fazem e quais foram as ferramentas usadas para isso? Binários: https://s3-sa-east-1.amazonaws.com/desafio-binarios/ddb1c9 https://s3-sa-east-1.amazonaws.com/desafio-binarios/da87fa https://s3-sa-east-1.amazonaws.com/desafio-binarios/d3ea79 https://s3-sa-east-1.amazonaws.com/desafio-binarios/cc9621
×
×
  • Create New...