web-dev-qa-db-fra.com

Comment tester si un binaire Linux a été compilé en tant que code indépendant de la position?

J'ai récemment appris que (au moins sur Fedora et Red Hat Enterprise Linux), les programmes exécutables qui sont compilés en tant que PIE (Position Independent Executables) bénéficient d'une meilleure protection contre la randomisation de l'espace d'adressage (ASLR).

Donc: comment tester si un exécutable particulier a été compilé en tant qu'exécutable indépendant de position, sous Linux?

42
D.W.

Vous pouvez utiliser le script Perl contenu dans le hardening-check package, disponible dans Fedora et Debian (comme hardening-includes). Lisez ceci page wiki Debian pour plus de détails sur les drapeaux de compilation qui sont vérifiés. C'est spécifique à Debian, mais la théorie s'applique également à Red Hat.

Exemple:

$ 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
33
dawud

J'ai utilisé readelf --relocs pour tester si la bibliothèque statique ou dynamique est PIC sur x86-64 de la manière suivante:

$ 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

On voit ici R_X86_64_32 et R_X86_64_32S. Cela signifie que le code n'est pas indépendant de la position. Lorsque je reconstruis une bibliothèque avec -fPIC, j'obtiens:

$ 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

Cette méthode peut probablement fonctionner pour les exécutables, mais je ne l'ai pas utilisée de cette façon.

15
user2387

Utilisez simplement file sur le binaire:

$ 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

Notez les différents types imprimés après les informations LSB.

15
p5yx

file 5.36 le dit clairement

file 5.36 l'affiche clairement si l'exécutable est PIE ou non. Par exemple, un exécutable PIE s'affiche comme suit:

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

et un non-TARTE comme:

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

La fonctionnalité a été introduite dans la version 5.33, mais elle a simplement fait chmod +x vérifier. Avant cela, il vient d'imprimer shared object pour PIE.

En 5.34, il était censé commencer à vérifier le _ plus spécialisé DF_1_PIE Métadonnées ELF, mais en raison d'un bogue dans l'implémentation, elles ont en fait cassé les choses et montré les exécutables GCC PIE comme shared objects.

J'ai interprété le code source de file, y compris le bogue, et exactement les octets du format ELF qu'il vérifie en détails atroces sur: https://stackoverflow.com/questions/34519521/why-does -gcc-créer-un-objet-partagé-au-lieu-d'un-exécutable-binaire-selon/55704865 # 55704865

Voici un bref résumé du comportement du fichier 5.36:

  • si Elf32_Ehdr.e_type == ET_EXEC
    • imprimer executable
  • sinon si Elf32_Ehdr.e_type == ET_DYN
    • si DT_FLAGS_1 l'entrée de section dynamique est présente
      • si DF_1_PIE est défini dans DT_FLAGS_1:
        • impression pie executable
      • autre
        • impression shared object
    • autre
      • si le fichier est exécutable par un utilisateur, un groupe ou d'autres
        • impression pie executable
      • autre
        • impression shared object

GDB exécute l'exécutable deux fois et voit ASLR

Une chose très directe que vous pouvez faire est d'exécuter l'exécutable deux fois via GDB et de voir si l'adresse change à travers les exécutions en raison de ASLR.

J'ai expliqué comment le faire en détail sur: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and -ld/51308031 # 51308031

Bien que ce ne soit pas nécessairement la solution la plus pratique et impossible si vous ne faites pas confiance à l'exécutable, c'est amusant et il fait la vérification ultime qui nous tient vraiment à cœur, à savoir si le noyau Linux/chargeur dynamique change l'emplacement de l'exécutable ou ne pas.

Il y a un script bash checksec.sh sur Github pour vérifier les propriétés d'atténuation des exécutables (y compris RELRO, Stack Canary, bit NX, PIE, RPATH, RUNPATH, Fortify Source).

Exécutez checksec avec -f (entrée de fichier) arguments:

$ 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
3
Sourc7