Come verificare se un binario Linux è stato compilato come codice indipendente dalla posizione?


38

Di recente ho appreso che (almeno su Fedora e Red Hat Enterprise Linux), i programmi eseguibili compilati come PIE (Position Independent Executables) ricevono una protezione ASLR (Address Space Casualization) più forte.

Quindi: come posso verificare se un particolare eseguibile è stato compilato come eseguibile indipendente dalla posizione, su Linux?


1
Non sono sicuro circa 32 bit, ma il codice x86_64 è indipendente dalla posizione per impostazione predefinita . E ovviamente tutti i pacchetti di sistema sono compilati in questo modo su entrambi gli arch.
Michael Hampton,

1
@MichaelHampton, non credo sia giusto. (Fai attenzione alla differenza tra un binario eseguibile e una libreria condivisa; la tua affermazione potrebbe essere giusta per le librerie condivise, ma non penso che sia giusta per gli eseguibili.) Anche su x86_64, i binari non sembrano essere PIE per impostazione predefinita. Ho appena scritto un piccolo programma di test e su x86_64 non è stato compilato come PIE. Penso che devi passare i -pie -fpieflag speciali del compilatore per compilare un programma come PIE. Quel link aveva altre informazioni interessanti, grazie!
DW

1
Questo ragazzo ha uno script bash per il rilevamento: blog.fpmurphy.com/2008/06/position-independent-executables.html
CMCDragonkai

Risposte:


32

Puoi usare lo perlscript contenuto nel hardening-checkpacchetto, disponibile in Fedora e Debian (as hardening-includes). Leggi questa pagina wiki Debian per i dettagli su quali flag di compilazione sono controllati. È specifico di Debian, ma la teoria si applica anche a Red Hat.

Esempio:

$ 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

Bella risposta, applicabile anche a Ubuntu 16.04 LTS e possibilmente ad altre versioni di Ubuntu. sudo apt-get install hardening-includese quindi lo hardening-checkscript eseguibile perl è disponibile sul solito PATH( /usr/bin/hardening-check); solo un pò: suggerire di rimuovere il ./dalla risposta ;-)
Dilettant

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae non più alle 17.10 :-(
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

In CentOS / RedHat, questo pacchetto è disponibile in EPEL repository
vikas027

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae Sembra che non sia più disponibile in Ubuntu 18.04
Vadim Kotov

2
Il pacchetto debian che contiene questo è ora chiamato devscripts.
Tamás Szelei,

15

Ho usato readelf --relocsper verificare se la libreria statica o dinamica è PIC su x86-64 nel modo seguente:

$ 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

Vediamo qui R_X86_64_32e R_X86_64_32S. Ciò significa che il codice non è indipendente dalla posizione. Quando ricostruisco una libreria con -fPIC ottengo:

$ 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

Questo metodo potrebbe probabilmente funzionare per eseguibili, ma non l'ho usato in questo modo.


8
Ti andrebbe di spiegare come interpretare l'output di quel one-liner? Quali sono i criteri da utilizzare per classificare la libreria condivisa come PIC vs non-PIC?
DW

Se si creava un eseguibile con -fPIE -no-pie, sarebbe sempre caricato allo stesso indirizzo anche se avrebbe potuto essere collegato come eseguibile PIE. Utilizzare file a.oute cercare ELF executable(non PIE) vs. ELF shared object` (PIE): indirizzi assoluti a 32 bit non più consentiti in Linux x86-64?
Peter Cordes,

12

Basta usare filesul binario:

$ 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

Nota il diverso tipo stampato dopo le informazioni LSB.


1
Come viene mostrato se compilato con PIE / ASLR?
Baruch,

3
L'unica differenza tra gli output di pie-off e pie.on sono executablee shared object. Presumo che gli oggetti condivisi debbano essere trasferibili, quindi secondo me sono stati compilati con PIE.
Richard Braganza,

Sì, gli eseguibili PIE sono oggetti condivisi ELF; il modo più semplice per implementare ASLR per gli eseguibili era usare il supporto esistente nel linker dinamico per e punto di entrata ELF in un oggetto condiviso. Vedi anche indirizzi assoluti a 32 bit non più consentiti in Linux x86-64? per maggiori informazioni sulle opzioni di gcc che controllano PIE, e questo gcc -fPIE -pieè ora il default su molte distro.
Peter Cordes,

Le versioni più recenti del file menzionano esplicitamente la torta: ad esempio eseguibile ELF a 64 bit LSB, x86-64, versione 1 (SYSV), collegata dinamicamente, interprete /lib64/ld-linux-x86-64.so.2, per GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, stripped
Brian Minton

1
@PeterCordes nota che la file5.36 ora può effettivamente riconoscere PIE-ness in base alla DT_1_PIEbandiera di DT_FLAGS_1, e dice chiaramente pie executableinvece di shared object.
Ciro Santilli 16 改造 中心 法轮功 六四 事件

9

file 5.36 lo dice chiaramente

file5.36 in realtà lo stampa chiaramente se l'eseguibile è PIE o no. Ad esempio, un eseguibile PIE mostra come:

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

e uno non PIE come:

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

La funzione è stata introdotta in 5.33 ma ha fatto solo un semplice chmod +xcontrollo. Prima di ciò è appena stato stampato shared objectper PIE.

In 5.34, doveva iniziare a controllare i DF_1_PIEmetadati ELF più specializzati , ma a causa di un bug nell'implementazione ha effettivamente rotto le cose e mostrato gli eseguibili GCC PIE come shared objects.

Ho interpretato fileil codice sorgente, incluso il bug, ed esattamente quali byte del formato ELF controlla dettagliatamente in dettaglio su: https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object -invece-di-un-eseguibile-binary-secondo-a / 55704865 # 55704865

Un breve riepilogo del comportamento del file 5.36 è:

  • Se Elf32_Ehdr.e_type == ET_EXEC
    • stampare executable
  • altro se Elf32_Ehdr.e_type == ET_DYN
    • se DT_FLAGS_1è presente la voce di sezione dinamica
      • se DF_1_PIEè impostato in DT_FLAGS_1:
        • stampare pie executable
      • altro
        • stampare shared object
    • altro
      • se il file è eseguibile dall'utente, dal gruppo o da altri
        • stampare pie executable
      • altro
        • stampare shared object

GDB esegue il file eseguibile due volte e visualizza ASLR

Una cosa molto diretta che puoi fare è eseguire il file eseguibile due volte tramite GDB e vedere se l'indirizzo cambia tra le esecuzioni a causa di ASLR.

Ho spiegato come farlo in dettaglio su: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031 # 51308031

Sebbene questa non sia necessariamente la soluzione più pratica e non possibile se non ti fidi dell'eseguibile, è divertente e fa il controllo finale che ci interessa davvero, cioè se il kernel / caricatore dinamico Linux cambia la posizione dell'eseguibile o non.


1
"indirizzo delle principali modifiche tra le serie" - questo non è un effetto di PIE pura, è PIE e abilitato ASLR. Sì, è quasi ovunque abilitato, ma per le macchine con indirizzo ASLR disabilitato sarà lo stesso entrambe le volte. ASLR può essere abilitato a livello globale ma disabilitato con setarch -R man7.org/linux/man-pages/man8/setarch.8.html " -R, --addr-no-randomize Disabilita la randomizzazione dello spazio degli indirizzi virtuali. Attiva ADDR_NO_RANDOMIZE." man7.org/linux/man-pages/man2/personality.2.html " ADDR_NO_RANDOMIZE(da Linux 2.6.12) Con questo flag impostato, disabilita la randomizzazione del layout dello spazio indirizzo."
osgx,

2

Esiste lo script bash checksec.sh su Github per verificare le proprietà di mitigazione degli eseguibili (inclusi RELRO, Stack Canary, bit NX, PIE, RPATH, RUNPATH, Fortify Source).

Esegui checkseccon -fargomenti (input file):

$ 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.