Skip to content

Position Independent Executable

Ana programı bir ET_DYN object'i (-fPIE -pie) olarak derlemek, loader'ın onun text/data'sını randomize edilmiş bir base'e yerleştirmesini sağlar; binary'yi sabit bir adreste bırakmak yerine ASLR'yi executable'ın kendisine genişletir.

Mechanism

Neden çalışır

ASLR, stack'in, heap'in, mmap bölgesinin ve shared library'lerin base'ini randomize eder — ama bir non-PIE binary'si, program header'larına mutlak load adresleri gömülü bir ET_EXEC ELF'idir; bu yüzden kernel onun text ve data'sını linker'ın seçtiği sabit virtual address'e map'lemek zorundadır. Bu, her şey hareket etse bile saldırgana bilinen code ve data'dan (gadget'lar, GOT/PLT, global function pointer'ları) oluşan sabit bir ada verir.

Bir Position Independent Executable, bir ET_DYN object'i olarak — shared library ile aynı ELF type'ı — yalnızca PC-relative adresleme ve symbol referansları için bir GOT kullanılarak compile ve link edilir. Image'de hiçbir şey sabit bir load adresi varsaymadığı için, loader, .so library'leri için zaten yaptığı gibi, executable için tam olarak bir rastgele base seçmekte özgürdür. Bir PIE'deki function "adresleri" aslında loader'ın base'i seçtiğinde çözdüğü offset'lerdir.

Invariant: PIE ile, process image'inin hiçbir parçası compile-zamanı-bilinen bir adreste oturmaz. Bu son sabit bölgeyi kapatır, böylece güvenilir code-reuse için (bilinen bir mutlak yerine) tek bir info leak ön koşul haline gelir — PIE'yi, ASLR'nin tüm address space'i kapsamasını sağlayan parça yapar.

Walkthrough

1. PIE ile ve PIE olmadan derle, ELF type'ını karşılaştır.

$ gcc -no-pie -fno-pie demo.c -o demo_nopie
$ gcc -fPIE -pie       demo.c -o demo_pie     # default on most modern distros

$ readelf -h demo_nopie | grep Type
  Type:                              EXEC (Executable file)

$ readelf -h demo_pie   | grep Type
  Type:                              DYN (Position-Independent Executable file)

ET_EXEC ⇒ sabit base; ET_DYN ⇒ relocatable, ASLR'ye uygun. (file, aynı nedenle PIE'yi "ELF ... shared object" olarak raporlar — o bir ET_DYN'dir.)

2. Bir hardening envanteriyle doğrula. checksec, e_type alanını okur; DYN PIE'ye işaret eder:

$ checksec --file=./demo_pie
RELRO        STACK CANARY  NX     PIE        ...
Full RELRO   Canary found  NX en  PIE enabled

$ checksec --file=./demo_nopie
...                                No PIE (0x400000)

Düz 0x400000, klasik sabit x86-64 ET_EXEC base'idir — bir saldırgan için bedava bilinen bir adres.

3. Base'in hareket etmesini (PIE) vs sabit kalmasını (non-PIE) izle. ASLR açıkken (/proc/sys/kernel/randomize_va_space = 2):

$ for i in 1 2 3; do ./demo_pie   & sleep 0.05; grep " r-xp .*demo_pie"  /proc/$!/maps | head -1; done
55e6a1c1f000-...  r-xp ...  demo_pie
560b3f4aa000-...  r-xp ...  demo_pie     # base differs each run

$ for i in 1 2 3; do ./demo_nopie & sleep 0.05; grep " r-xp .*demo_nopie" /proc/$!/maps | head -1; done
00400000-...      r-xp ...  demo_nopie
00400000-...      r-xp ...  demo_nopie   # always 0x400000

PIE entropy/perf maliyeti getirir ve leak'lerden muaf değildir

32-bit'te PIE base entropy'si brute-force edilecek kadar küçüktür. PIE ayrıca GOT-indirection overhead'i ekler; tarihsel olarak register'ı kıt x86-32'de daha ağırdır. Ve PIE base'i yalnızca gizler — bir adres leak edildiğinde hiçbir şey yapmaz.

Detection

Statik olarak envanterlemek önemsizdir: readelf -h (Type: DYN), file ("shared object") veya checksec/hardening-check ("PIE enabled" / "Position Independent Executable: yes"). Bir INTERP segment'i ve bir entry point'i olan bir DYN bir PIE'dir; INTERP'siz bir DYN sıradan bir shared library'dir.

Mitigation

(Artık risk / bypass.) PIE, yalnızca arkasındaki ASLR entropy'si ve leak'lerin yokluğu kadar güçlüdür. Tek bir pointer leak, rastgele base'i açığa çıkarır ve fixed-offset ROP'u yeniden mümkün kılar. Düşük-entropy base'ler ASLR brute force'a davetiye çıkarır ve offset2lib / partial pointer overwrite gibi partial-overwrite numaraları, tam bir leak olmadan randomization'ı yenebilir veya atlatabilir.

References