Jak sprawdzić, czy plik binarny systemu Linux został skompilowany jako kod niezależny od pozycji?


38

Niedawno dowiedziałem się, że (przynajmniej w Fedorze i Red Hat Enterprise Linux) programy wykonywalne skompilowane jako pliki niezależne od pozycji (PIE) otrzymują silniejszą ochronę przed losową przestrzenią adresową (ASLR).

A zatem: Jak sprawdzić, czy określony plik wykonywalny został skompilowany w Linuksie jako plik wykonywalny niezależny od pozycji?


1
Nie jestem pewien co do wersji 32-bitowej, ale kod x86_64 jest domyślnie niezależny od pozycji . I oczywiście wszystkie pakiety systemowe są kompilowane w ten sposób na dowolnym archu.
Michael Hampton

1
@MichaelHampton, nie sądzę, że to prawda. (Uważaj na różnicę między wykonywalnym plikiem binarnym a biblioteką współdzieloną; twoja instrukcja może być odpowiednia dla bibliotek współdzielonych, ale nie sądzę, że jest odpowiednia dla plików wykonywalnych.) Nawet na x86_64, pliki binarne nie wydają się domyślnie SROKA. Właśnie napisałem mały program testowy i na x86_64 nie został skompilowany jako PIE. Myślę, że musisz przekazać -pie -fpiespecjalne flagi kompilatora, aby skompilować program jako SROKA. Ten link zawierał jednak inne interesujące informacje - dziękuję!
DW

Odpowiedzi:


32

Możesz użyć perlskryptu zawartego w hardening-checkpakiecie, dostępnego w Fedorze i Debianie (as hardening-includes). Przeczytaj tę stronę wiki Debiana, aby uzyskać szczegółowe informacje na temat sprawdzanych flag kompilacji. Jest specyficzny dla Debiana, ale teoria dotyczy również Red Hata.

Przykład:

$ 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

Ładna odpowiedź, dotyczy również Ubuntu 16.04 LTS i ewentualnie innych wersji Ubuntu. sudo apt-get install hardening-includesa następnie hardening-checkskrypt wykonywalny perla jest dostępny na zwykłej PATH( /usr/bin/hardening-check); tylko nit: Zaproponuj usunięcie ./odpowiedzi ;-)
Dilettant

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae nie jest już w 17.10 :-(
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

W CentOS / RedHat, ten pakiet jest dostępny w EPEL repozytorium
vikas027

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae Wygląda na to, że nie jest już dostępny w Ubuntu 18.04
Vadim Kotov

2
Pakiet debian, który ją zawiera, jest teraz nazywany devscripts.
Tamás Szelei

15

Kiedyś readelf --relocs, aby sprawdzić, czy statyczne lub dynamiczne biblioteki PIC na x86-64 następujący sposób:

$ 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

Widzimy tutaj R_X86_64_32i R_X86_64_32S. Oznacza to, że kod nie jest niezależny od pozycji. Kiedy odbudowuję bibliotekę z opcją -fPIC, otrzymuję:

$ 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

Ta metoda prawdopodobnie działa w przypadku plików wykonywalnych, ale nie użyłem jej w ten sposób.


8
Czy zechciałby pan wyjaśnić, jak interpretować wyniki tego jednowierszowego? Jakie kryteria należy zastosować, aby sklasyfikować bibliotekę współdzieloną jako PIC w porównaniu do PIC?
DW

Jeśli zbudowałeś plik wykonywalny -fPIE -no-pie, zawsze byłby ładowany pod tym samym adresem, nawet gdyby mógł być połączony jako plik wykonywalny PIE. Używać file a.outi szukać ELF executable(non-PIE) vs. ELF współdzielony obiekt` (PIE): 32-bitowe adresy absolutne nie są już dozwolone w Linuksie x86-64?
Peter Cordes

12

Po prostu użyj filena pliku binarnym:

$ 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

Zwróć uwagę na inny typ wydrukowany po informacji LSB.


1
Jak to pokazuje, jeśli jest skompilowane z PIE / ASLR?
Baruch,

3
Jedyną różnicą między wyjściami z pie-off i pie.on są executablei shared object. Zakładam, że wspólne obiekty muszą być relokowalne, dlatego moim zdaniem zostały skompilowane z SROKĄ.
Richard Braganza

Tak, pliki wykonywalne PIE są obiektami współdzielonymi ELF; najłatwiejszym sposobem zaimplementowania ASLR dla plików wykonywalnych było użycie istniejącej obsługi dynamicznego linkera i punktu wejścia ELF we współdzielonym obiekcie. Zobacz także 32-bitowe adresy bezwzględne nie są już dozwolone w Linuksie x86-64? aby dowiedzieć się więcej o opcjach gcc, które kontrolują PIE, i gcc -fPIE -piejest to teraz domyślne w wielu dystrybucjach.
Peter Cordes

Nowsze wersje pliku wyraźnie wspominają o pliku kołowym: np. ELF 64-bitowy plik wykonywalny LSB pie, x86-64, wersja 1 (SYSV), dynamicznie połączony, interpreter /lib64/ld-linux-x86-64.so.2, dla GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, rozebrany
Brian Minton

1
@PeterCordes zauważa, że file5.36 może teraz rozpoznawać SROKI w oparciu o DT_1_PIEflagę DT_FLAGS_1i wyraźnie mówi pie executablezamiast shared object.
Ciro Santilli 16 改造 中心 法轮功 六四 事件

8

file 5.36 mówi to wyraźnie

file5.36 faktycznie drukuje to wyraźnie, jeśli plik wykonywalny jest PIE, czy nie. Na przykład plik wykonywalny PIE pokazuje się jako:

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

i inny niż SROKA, ponieważ:

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

Ta funkcja została wprowadzona w 5.33, ale wykonała jedynie prostą chmod +xkontrolę. Wcześniej drukowane tylko shared objectdla SROKI.

W 5.34 zamierzano rozpocząć sprawdzanie bardziej wyspecjalizowanych DF_1_PIEmetadanych ELF, ale z powodu błędu w implementacji faktycznie coś zepsuło i pokazało pliki wykonywalne GIE PIE jako shared objects.

Zinterpretowałem filekod źródłowy, w tym błąd, i dokładnie to, które bajty formatu ELF sprawdza on wyjątkowo szczegółowo pod adresem : https://stackoverflow.com/questions/34519521/hy-does-gcc-create-a-shared-object -in-zamiast-pliku wykonywalnego-binarnego zgodnie z / 55704865 # 55704865

Szybkie podsumowanie zachowania pliku 5.36 to:

  • Jeśli Elf32_Ehdr.e_type == ET_EXEC
    • wydrukować executable
  • inaczej jeśli Elf32_Ehdr.e_type == ET_DYN
    • jeśli DT_FLAGS_1jest obecny wpis sekcji dynamicznej
      • jeśli DF_1_PIEjest ustawiony w DT_FLAGS_1:
        • wydrukować pie executable
      • jeszcze
        • wydrukować shared object
    • jeszcze
      • jeśli plik jest wykonywalny przez użytkownika, grupę lub inne osoby
        • wydrukować pie executable
      • jeszcze
        • wydrukować shared object

GDB uruchom plik wykonywalny dwa razy i zobacz ASLR

Jedną bardzo bezpośrednią rzeczą, którą możesz zrobić, jest dwukrotne uruchomienie pliku wykonywalnego za pośrednictwem GDB i sprawdzenie, czy adres zmienia się w różnych biegach z powodu ASLR.

Wyjaśniłem, jak to zrobić szczegółowo na stronie : https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031 # 51308031

Chociaż niekoniecznie jest to najbardziej praktyczne rozwiązanie i nie jest możliwe, jeśli nie ufasz plikowi wykonywalnemu, jest zabawny i wykonuje ostateczną kontrolę, na której nam naprawdę zależy, to znaczy, czy jądro Linux / moduł ładujący dynamicznie zmienia lokalizację pliku wykonywalnego lub nie.


1
„adres głównych zmian między uruchomieniami” - to nie jest efekt czystej SROKI, to JEST SROKA i włączony ASLR. Tak, jest prawie wszędzie włączony, ale dla komputerów z wyłączonym adresem ASLR będzie taki sam za każdym razem. ASLR może być włączony globalnie, ale wyłączony za pomocą setarch -R man7.org/linux/man-pages/man8/setarch.8.html-R, --addr-no-randomize Wyłącza randomizację wirtualnej przestrzeni adresowej. Włącza się ADDR_NO_RANDOMIZE”. man7.org/linux/man-pages/man2/personality.2.htmlADDR_NO_RANDOMIZE(od Linuksa 2.6.12) Po ustawieniu tej flagi wyłącz randomizację układu przestrzeni adresowej”.
osgx

2

Na Github znajduje się skrypt bash checksec.sh do sprawdzania właściwości ograniczania plików wykonywalnych (w tym RELRO, Stack Canary, bit NX, PIE, RPATH, RUNPATH, Fortify Source).

Uruchom checksecz -fargumentami (wprowadzanie pliku):

$ 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.