Como testar se um binário Linux foi compilado como código independente de posição?

38

Recentemente eu aprendi que (pelo menos no Fedora e Red Hat Enterprise Linux), os programas executáveis ​​que são compilados como PIE (Position Independent Executables) recebem proteção mais forte de randomização do espaço de endereço (ASLR).

Então: como testar se um executável específico foi compilado como um executável independente de posição, no Linux?

DW
fonte
11
Não tenho certeza sobre 32 bits, mas no código x86_64 é independente da posição por padrão . E é claro que todos os pacotes do sistema são compilados dessa maneira em ambos os arcos.
Michael Hampton
11
@ MichaelHampton, eu não acho isso certo. (Cuidado com a diferença entre um binário executável e uma biblioteca compartilhada; sua instrução pode ser correta para bibliotecas compartilhadas, mas não acho que seja correta para executáveis.) Mesmo no x86_64, os binários não parecem ser TORTA por padrão. Acabei de escrever um pequeno programa de teste e, no x86_64, ele não foi compilado como TORTA. Eu acho que você precisa passar os -pie -fpiesinalizadores especiais do compilador para compilar um programa como uma TORTA. Esse link tinha outras informações interessantes - obrigado!
DW
11
Esse cara tem um script de detecção: blog.fpmurphy.com/2008/06/position-independent-executables.html
CMCDragonkai

Respostas:

32

Você pode usar o perlscript contido no hardening-checkpacote, disponível no Fedora e Debian (as hardening-includes). Leia esta página wiki da Debian para obter detalhes sobre quais sinalizadores de compilação são verificados. É específico do Debian, mas a teoria se aplica ao Red Hat também.

Exemplo:

$ hardening-check $(which sshd)
/usr/sbin/sshd:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes
dawud
fonte
Boa resposta, também aplicável ao Ubuntu 16.04 LTS e possivelmente a outras versões do Ubuntu. sudo apt-get install hardening-includese então o hardening-checkscript perl executável está disponível no usual PATH( /usr/bin/hardening-check); apenas um nit: Sugerir para remover a ./partir da resposta ;-)
Dilettant
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae não está mais no 17.10 :-(
Ciro Santilli 新疆 改造 中心 法轮功 六四
Em Red Hat Enterprise Linux / Red Hat, este pacote está disponível em EPEL repositório
vikas027
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae Parece que não está mais disponível no Ubuntu 18.04
Vadim Kotov
2
O pacote debian que contém isso agora é chamado devscripts.
Tamás Szelei
15

Eu costumava readelf --relocstestar se a biblioteca estática ou dinâmica é PIC em x86-64 da seguinte maneira:

$ readelf --relocs /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_32
R_X86_64_32S
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSLD
R_X86_64_TPOFF32

Nós vemos aqui R_X86_64_32e R_X86_64_32S. Isso significa que o código não é independente de posição. Quando reconstruo uma biblioteca com -fPIC, recebo:

$ readelf --relocs libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSGD
R_X86_64_TLSLD

Esse método provavelmente pode funcionar para executáveis, mas eu não o usei dessa maneira.

user2387
fonte
8
Você gostaria de explicar como interpretar a saída desse one-liner? Quais são os critérios a serem usados ​​para classificar a biblioteca compartilhada como PIC vs não PIC?
DW
Se você construísse um executável -fPIE -no-pie, ele sempre seria carregado no mesmo endereço, mesmo que pudesse ter sido vinculado como um executável PIE. Use file a.oute procure por ELF executableobjetos compartilhados (não PIE) vs. ELF (PIE): endereços absolutos de 32 bits não são mais permitidos no Linux x86-64?
Peter Cordes
12

Basta usar fileno binário:

$ file ./pie-off
./pie-off: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0dc3858e9f0334060bfebcbe3e854909191d8bdc, not stripped
$ file ./pie-on
./pie-on: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=962235df5bd188e1ec48c151ff61b6435d395f89, not stripped

Observe o tipo diferente impresso após as informações do LSB.

p5yx
fonte
11
Como isso se mostra se compilado com PIE / ASLR?
Baruch
3
A única diferença entre as saídas de pie-off e pie.on são executablee shared object. Presumo que os objetos compartilhados precisam ser realocados, portanto, na minha opinião, foram compilados com o PIE.
Richard Braganza
Sim, executáveis ​​PIE são objetos compartilhados por ELF; a maneira mais fácil de implementar o ASLR para executáveis ​​era usar o suporte existente no vinculador dinâmico para e o ponto de entrada ELF em um objeto compartilhado. Veja também endereços absolutos de 32 bits que não são mais permitidos no x86-64 Linux? para saber mais sobre as opções do gcc que controlam o TORTA, e gcc -fPIE -pieagora é o padrão em muitas distribuições.
Peter Cordes
As versões mais recentes do arquivo mencionam explicitamente o pie: por exemplo, executável do ELF de 64 bits LSB, x86-64, versão 1 (SYSV), vinculado dinamicamente, intérprete /lib64/ld-linux-x86-64.so.2, para GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, despojado
Brian Minton
11
@ PeterCordes observe que a versão file5.36 agora pode realmente reconhecer PIE-ness com base na DT_1_PIEbandeira de DT_FLAGS_1, e diz claramente em pie executablevez de shared object.
Ciro Santilli escreveu: 16/04
8

file 5.36 diz claramente

file5.36 realmente imprime claramente se o executável é TORTA ou não. Por exemplo, um executável PIE mostra como:

main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped

e um não-TORTA como:

main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

O recurso foi introduzido na 5.33, mas fez apenas uma chmod +xverificação simples . Antes disso, apenas imprimia shared objectpara TORTA.

Na versão 5.34, ele deveria começar a verificar os DF_1_PIEmetadados ELF mais especializados , mas devido a um erro na implementação, ele realmente quebrou as coisas e mostrou os executáveis ​​do GCC PIE como shared objects.

Eu interpretei o filecódigo fonte, incluindo o bug, e exatamente quais bytes do formato ELF ele verifica com detalhes excruciantes em: https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object de acordo com um binário executável de acordo com / 55704865 # 55704865

Um resumo rápido do comportamento do arquivo 5.36 é:

  • E se Elf32_Ehdr.e_type == ET_EXEC
    • impressão executable
  • senão se Elf32_Ehdr.e_type == ET_DYN
    • se DT_FLAGS_1a entrada de seção dinâmica estiver presente
      • se DF_1_PIEestiver definido em DT_FLAGS_1:
        • impressão pie executable
      • outro
        • impressão shared object
    • outro
      • se o arquivo é executável por usuário, grupo ou outros
        • impressão pie executable
      • outro
        • impressão shared object

O GDB executa o executável duas vezes e consulte ASLR

Uma coisa muito direta que você pode fazer é executar o executável duas vezes através do GDB e verificar se o endereço muda entre as execuções devido ao ASLR.

Expliquei como fazer isso em detalhes em: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031 # 51308031

Embora essa não seja necessariamente a solução mais prática e não seja possível se você não confia no executável, é divertido e faz a verificação final com a qual realmente nos preocupamos, ou seja, se o kernel / carregador dinâmico do Linux altera o local do executável ou não.

Ciro Santilli adicionou uma nova foto
fonte
11
"endereço das principais alterações entre execuções" - isso não é efeito de TORTA pura, é TORTA e ASLR ativado. Sim, está quase ativado em qualquer lugar, mas para máquinas com endereço ASLR desativado será o mesmo nas duas vezes. O ASLR pode ser ativado globalmente, mas desabilitado com setarch -R man7.org/linux/man-pages/man8/setarch.8.html " -R, --addr-no-randomize Desativa a randomização do espaço de endereço virtual. Liga ADDR_NO_RANDOMIZE." man7.org/linux/man-pages/man2/personality.2.html " ADDR_NO_RANDOMIZE(desde Linux 2.6.12) Com esse sinalizador definido, desative a randomização do layout do espaço de endereço."
Osgx
2

Existe o script bash checksec.sh no Github para verificar as propriedades de atenuação dos executáveis ​​(incluindo RELRO, Stack Canary, NX bit, PIE, RPATH, RUNPATH, Fortify Source).

Execute checkseccom -fargumentos (entrada de arquivo):

$ checksec -f /usr/bin/bash

RELRO           STACK CANARY      NX            PIE             RPATH     RUNPATH      FORTIFY Fortified Fortifiable
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH    YES      13        33
Sourc7
fonte