Bagaimana cara menguji apakah biner Linux dikompilasi sebagai kode independen posisi?

38

Baru-baru ini saya mengetahui bahwa (setidaknya pada Fedora dan Red Hat Enterprise Linux), program yang dapat dieksekusi yang dikompilasi sebagai Position Independent Executables (PIE) menerima perlindungan pengalamatan ruang alamat (ASLR) yang lebih kuat.

Jadi: Bagaimana saya menguji apakah executable tertentu dikompilasi sebagai Posisi Independen yang Dapat Dilakukan, di Linux?

DW
sumber
1
Tidak yakin tentang 32-bit, tetapi pada kode x86_64 posisi independen secara default . Dan tentu saja semua paket sistem dikompilasi dengan cara ini di kedua lengkungan.
Michael Hampton
1
@MichaelHampton, saya pikir itu tidak benar. (Hati-hati dengan perbedaan antara biner yang dapat dieksekusi dan pustaka bersama; pernyataan Anda mungkin tepat untuk pustaka bersama, tapi saya rasa itu tidak tepat untuk executable.) Bahkan pada x86_64, binari tampaknya tidak menjadi PIE secara default. Saya baru saja menulis sebuah program pengujian kecil, dan pada x86_64, itu tidak dikompilasi sebagai PIE. Saya pikir Anda harus melewati -pie -fpieflag kompiler khusus untuk mengkompilasi program sebagai PIE. Tautan itu memiliki informasi menarik lainnya - terima kasih!
DW
1
Orang ini memiliki skrip bash untuk deteksi: blog.fpmurphy.com/2008/06/position-independent-executables.html
CMCDragonkai

Jawaban:

32

Anda dapat menggunakan perlskrip yang terkandung dalam hardening-checkpaket, tersedia di Fedora dan Debian (as hardening-includes). Baca halaman wiki Debian ini untuk perincian tentang flag kompilasi yang diperiksa. Ini spesifik untuk Debian, tetapi teorinya juga berlaku untuk Red Hat.

Contoh:

$ 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
sumber
Jawaban yang bagus, juga berlaku untuk Ubuntu 16.04 LTS dan mungkin versi Ubuntu lainnya. sudo apt-get install hardening-includesdan kemudian hardening-checkskrip perl yang dapat dieksekusi tersedia di biasanya PATH( /usr/bin/hardening-check); just a nit: Sarankan untuk menghapus ./dari jawaban ;-)
Dilettant
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae tidak di 17.10 lagi :-(
Ciro Santilli 新疆 改造 中心 法轮功 心 六四 六四 事件
Di CentOS / RedHat, paket ini tersedia dalam epel repository
vikas027
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae Sepertinya itu tidak lagi tersedia di Ubuntu 18.04
Vadim Kotov
2
Paket debian yang berisi ini sekarang disebut devscripts.
Tamás Szelei
15

Saya biasa readelf --relocsmenguji apakah perpustakaan statis atau dinamis adalah PIC pada x86-64 dengan cara berikut:

$ 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

Kita lihat di sini R_X86_64_32dan R_X86_64_32S. Ini berarti bahwa kode tersebut tidak independen terhadap posisi. Ketika saya membangun kembali perpustakaan dengan -fPIC saya mendapatkan:

$ 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

Metode ini mungkin bekerja untuk executable, tetapi saya belum menggunakannya seperti itu.

pengguna2387
sumber
8
Maukah Anda menjelaskan bagaimana menginterpretasikan output dari one-liner itu? Apa kriteria yang digunakan untuk mengklasifikasikan perpustakaan bersama sebagai PIC vs non-PIC?
DW
Jika Anda membangun executable dengan -fPIE -no-pie, itu akan selalu dimuat di alamat yang sama meskipun itu bisa ditautkan sebagai executable PIE. Gunakan file a.outdan cari ELF executable(non-PIE) vs. ELF shared object` (PIE): Alamat absolut 32-bit tidak lagi diizinkan di x86-64 Linux?
Peter Cordes
12

Cukup gunakan filepada biner:

$ 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

Perhatikan jenis berbeda yang dicetak setelah informasi LSB.

p5yx
sumber
1
Bagaimana tampilan ini jika dikompilasi dengan PIE / ASLR?
Baruch
3
Satu-satunya perbedaan antara output dari pie-off dan pie.on adalah executabledan shared object. Saya kira benda yang dibagikan harus dipindahkan sehingga pikiran saya telah dikompilasi dengan PIE.
Richard Braganza
Yup, executable PIE adalah objek yang dibagikan ELF; cara termudah untuk mengimplementasikan ASLR untuk executable adalah dengan menggunakan dukungan yang ada di linker dinamis untuk dan titik masuk ELF di objek bersama. Lihat juga alamat absolut 32-bit yang tidak lagi diizinkan di x86-64 Linux? untuk lebih lanjut tentang opsi gcc yang mengontrol PIE, dan itu gcc -fPIE -piesekarang menjadi default pada banyak distro.
Peter Cordes
Versi file yang lebih baru secara eksplisit menyebutkan pie: mis. ELF 64-bit LSB pie executable, x86-64, versi 1 (SYSV), terkait secara dinamis, interpreter /lib64/ld-linux-x86-64.so.2, untuk GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, dilucuti
Brian Minton
1
@PeterCordes mencatat bahwa file5.36 sekarang dapat benar-benar mengenali PIE-ness berdasarkan DT_1_PIEbendera DT_FLAGS_1, dan dengan jelas mengatakan pie executablebukan shared object.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
8

file 5.36 mengatakannya dengan jelas

file5.36 sebenarnya mencetaknya dengan jelas jika executable adalah PIE atau tidak. Sebagai contoh, executable PIE ditampilkan sebagai:

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

dan yang non-PIE sebagai:

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

Fitur ini diperkenalkan pada 5.33 tetapi hanya melakukan chmod +xpemeriksaan sederhana . Sebelumnya hanya dicetak shared objectuntuk PIE.

Pada 5.34, itu dimaksudkan untuk mulai memeriksa DF_1_PIEmetadata ELF yang lebih terspesialisasi , tetapi karena bug dalam implementasi itu benar-benar memecahkan banyak hal dan menunjukkan executable GCC PIE sebagai shared objects.

Saya telah menafsirkan filekode sumber, termasuk bug, dan byte mana dari format ELF yang diperiksa dalam detail yang luar biasa di: https://stackoverflow.com/questions/34519521/why-does-gcc-create-a- Shared-object -bukan-of-an-executable-binary-sesuai-ke / 55704865 # 55704865

Ringkasan singkat perilaku file 5,36 adalah:

  • jika Elf32_Ehdr.e_type == ET_EXEC
    • mencetak executable
  • lain jika Elf32_Ehdr.e_type == ET_DYN
    • jika DT_FLAGS_1entri bagian dinamis hadir
      • jika DF_1_PIEdiatur DT_FLAGS_1:
        • mencetak pie executable
      • lain
        • mencetak shared object
    • lain
      • jika file dapat dieksekusi oleh pengguna, grup, atau orang lain
        • mencetak pie executable
      • lain
        • mencetak shared object

GDB menjalankan executable dua kali dan melihat ASLR

Satu hal yang sangat langsung yang dapat Anda lakukan adalah menjalankan executable dua kali melalui GDB dan melihat apakah alamat berubah di seluruh run karena ASLR.

Saya telah menjelaskan bagaimana melakukannya secara rinci di: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031 # 51308031

Walaupun ini tidak selalu merupakan solusi yang paling praktis dan tidak mungkin jika Anda tidak mempercayai yang dapat dieksekusi, itu menyenangkan dan melakukan pemeriksaan akhir yang benar-benar kami pedulikan, yaitu jika kernel Linux / dynamic loader mengubah lokasi yang dapat dieksekusi atau tidak.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber
1
"alamat perubahan utama antar berjalan" - ini bukan efek PIE murni, ini PIE dan ASLR diaktifkan. Ya, hampir di mana saja diaktifkan, tetapi untuk mesin dengan alamat ASLR yang dinonaktifkan akan sama untuk kedua kalinya. ASLR dapat diaktifkan secara global tetapi dinonaktifkan dengan setarch -R man7.org/linux/man-pages/man8/setarch.8.html " -R, --addr-no-randomize Nonaktifkan pengacakan ruang alamat virtual. Nyalakan ADDR_NO_RANDOMIZE." man7.org/linux/man-pages/man2/personality.2.html " ADDR_NO_RANDOMIZE(sejak Linux 2.6.12) Dengan flag ini disetel, nonaktifkan pengacakan tata letak-ruang-alamat."
osgx
2

Ada bash script checksec.sh di Github untuk memeriksa properti mitigasi yang dapat dieksekusi (termasuk RELRO, Stack Canary, NX bit, PIE, RPATH, RUNPATH, Fortify Source).

Jalankan checksecdengan -fargumen (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
Sourc7
sumber