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?


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

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

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.


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.


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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.