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

38

J'ai récemment appris que (du moins sur Fedora et Red Hat Enterprise Linux), les programmes exécutables compilés en tant qu'exécutables indépendants de la position (PIE) bénéficient d'une protection renforcée de la randomisation de l'espace adresse (ASLR).

Alors: comment puis-je tester si un exécutable particulier a été compilé en tant qu’exécutable indépendant du poste sous Linux?

DW
la source
1
Pas sûr de 32 bits, mais sur x86_64 le code est indépendant de la position par défaut . Et bien sûr, tous les paquets système sont compilés de cette façon sur l’un ou l’autre des fichiers.
Michael Hampton
1
@ MichaelHampton, je ne pense pas que ce soit vrai. (Faites attention à la différence entre un binaire exécutable et une bibliothèque partagée; votre déclaration pourrait être exacte pour les bibliothèques partagées, mais je ne pense pas que ce soit le cas pour les exécutables.) Même sur x86_64, les fichiers binaires ne semblent pas être PIE par défaut. Je viens d'écrire un petit programme de test, et sur x86_64, il n'a pas été compilé en tant que PIE. Je pense que vous devez passer les -pie -fpieindicateurs spéciaux du compilateur pour compiler un programme en tant que PIE. Ce lien contenait d'autres informations intéressantes - merci!
DW
1
Ce mec a un script de détection bash: blog.fpmurphy.com/2008/06/position-independent-executables.html
CMCDragonkai

Réponses:

32

Vous pouvez utiliser le perlscript contenu dans le hardening-checkpaquet, disponible dans Fedora et Debian (en tant que hardening-includes). Lisez cette page wiki Debian pour plus de détails sur les drapeaux de compilation à vérifier. 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
Dawud
la source
Bonne réponse, également applicable à Ubuntu 16.04 LTS et éventuellement à d'autres versions d'Ubuntu. sudo apt-get install hardening-includeset ensuite le hardening-checkscript exécutable perl est disponible avec la valeur habituelle PATH( /usr/bin/hardening-check); juste un nit: suggère de retirer le ./de la réponse ;-)
Dilettant
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae plus dans 17h10 :-(
Ciro Santilli 中心 事件
Dans CentOS / RedHat, ce paquet est disponible dans epel dépôt
vikas027
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae On dirait qu'il n'est plus disponible à Ubuntu. 18.04
Vadim Kotov Le
2
Le paquet debian qui contient cela est maintenant appelé devscripts.
Tamás Szelei
15

J'avais l'habitude readelf --relocsde 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

Nous voyons ici R_X86_64_32et 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, je reçois:

$ 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.

utilisateur2387
la source
8
Souhaitez-vous expliquer comment interpréter les résultats de cette ligne? Quels sont les critères à utiliser pour classer la bibliothèque partagée entre PIC et non-PIC?
DW
Si vous construisez un exécutable avec -fPIE -no-pie, il sera toujours chargé à la même adresse même s'il aurait pu être lié en tant qu'exécutable PIE. Utiliser file a.outet rechercher ELF executableun objet partagé (non-PIE) par rapport à un objet partagé ELF (PIE): les adresses absolues 32 bits ne sont plus autorisées dans x86-64 Linux?
Peter Cordes
12

Utilisez simplement filesur 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 le type différent imprimé après les informations LSB.

p5yx
la source
1
Comment cela montre-t-il s'il est compilé avec PIE / ASLR?
Baruch
3
La seule différence entre les sorties de pie-off et de pie.on est executableet shared object. Je suppose que les objets partagés doivent pouvoir être déplacés, ce qui, à mon avis, a été compilé avec PIE.
Richard Braganza
Oui, les exécutables PIE sont des objets partagés ELF; Le moyen le plus simple d'implémenter ASLR pour les exécutables était d'utiliser le support existant dans l'éditeur de liens dynamique pour et le point d'entrée ELF dans un objet partagé. Voir aussi Les adresses absolues 32 bits ne sont plus autorisées dans Linux x86-64? Pour en savoir plus sur les options gcc qui contrôlent PIE, il gcc -fPIE -pies’agit maintenant du comportement par défaut de nombreuses distributions.
Peter Cordes
Les versions les plus récentes du fichier mentionnent explicitement le camembert: par exemple, l'exécutable du camembert ELB 64 bits d'ELF, x86-64, version 1 (SYSV), lié dynamiquement, interpréteur /lib64/ld-linux-x86-64.so.2, pour GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, dépouillé
Brian Minton le
1
@PeterCordes note que file5.36 peut maintenant reconnaître PIE-ness sur la base du DT_1_PIEdrapeau de DT_FLAGS_1, et dit clairement pie executableau lieu de shared object.
Ciro Santilli du
9

file 5.36 le dit clairement

file5.36 l’imprime 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-PIE 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 n’a fait qu’une simple chmod +xvérification. Avant cela, il venait juste d’être imprimé shared objectpour PIE.

En 5.34, il était censé commencer à vérifier les DF_1_PIEmétadonnées ELF plus spécialisées , mais en raison d’un bogue dans l’implémentation, il a en réalité volé en éclats et a montré les exécutables de GCC PIE shared objects.

J'ai interprété filele code source, y compris le bogue, et exactement quels octets du format ELF il vérifie avec des détails insoutenables à l' adresse : https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object au lieu d'un exécutable binaire selon / 55704865 # 55704865

Un résumé rapide du comportement du fichier 5.36 est le suivant:

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

GDB exécuter le fichier exécutable deux fois et voir 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 d'une exécution à l'autre en raison de ASLR.

J'ai expliqué comment procéder en détail à l' adresse suivante : 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 cela vérifie en dernier ressort que nous nous soucions vraiment de savoir si le chargeur dynamique du noyau / de Linux modifie l’emplacement de l’exécutable ou si ne pas.

Ciro Santilli 改造 中心 六四 事件
la source
1
"adresse des principaux changements entre les exécutions" - ce n'est pas un effet de PIE pur, c'est PIE et activé ASLR. Oui, il est activé presque partout, mais pour les machines avec une adresse ASLR désactivée, la situation sera la même à chaque fois. ASLR peut être activé globalement mais désactivé avec setarch -R man7.org/linux/man-pages/man8/setarch.8.html " -R, --addr-no-randomize Désactive la randomisation de l'espace d'adressage virtuel. S'active ADDR_NO_RANDOMIZE." man7.org/linux/man-pages/man2/personality.2.html " ADDR_NO_RANDOMIZE(depuis Linux 2.6.12) Lorsque cet indicateur est défini, désactivez la randomisation de la structure d'adresse-espace-espace."
osgx
2

Il existe un script bash checksec.sh sur Github pour vérifier les propriétés d’atténuation des exécutables (notamment RELRO, Stary Canary, bit NX, PIE, RPATH, RUNPATH, Fortify Source).

Exécuter checksecavec -fdes arguments (entrée de fichier):

$ 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
la source