# Relro {{#include ../../banners/hacktricks-training.md}} ## Relro **RELRO** staan vir **Relocation Read-Only** en dit is 'n versagting wat deur die linker (`ld`) geïmplementeer word wat 'n substel van die ELF se datasegmente **lees-alleen maak nadat alle herlokasies toegepas is**. Die doel is om 'n aanvaller te stop om inskrywings in die **GOT (Global Offset Table)** of ander herlokasie-verwante tabelle wat tydens programuitvoering gedereferensieer word (bv. `__fini_array`) te oorskry. Moderne linkers implementeer RELRO deur die **GOT** (en 'n paar ander afdelings) te **herorden** sodat hulle **voor** die **.bss** woon en – die belangrikste – deur 'n toegewyde `PT_GNU_RELRO` segment te skep wat `R–X` herkaarteer reg na die dinamiese laaier klaar is met die toepassing van herlokasies. Gevolglik kan tipiese buffer oorgroeis in die **.bss** nie meer die GOT bereik nie en arbitrêre skryfprimitiewe kan nie gebruik word om funksie-aanwysers wat binne 'n RELRO-beskermde bladsy sit, te oorskry nie. Daar is **twee vlakke** van beskerming wat die linker kan uitreik: ### Gedeeltelike RELRO * Geproduseer met die vlag `-Wl,-z,relro` (of net `-z relro` wanneer `ld` direk aangeroep word). * Slegs die **nie-PLT** deel van die **GOT** (die deel wat vir dataskakelings gebruik word) word in die lees-alleen segment geplaas. Afdelings wat tydens uitvoering gewysig moet word – die belangrikste is **.got.plt** wat **luie binding** ondersteun – bly skryfbaar. * As gevolg hiervan kan 'n **arbitrêre skryf** primitiewe steeds die uitvoeringsvloei herlei deur 'n PLT-inskrywing te oorskry (of deur **ret2dlresolve** uit te voer). * Die prestasie-impak is verwaarloosbaar en daarom **het byna elke verspreiding al jare lank pakkette met ten minste Gedeeltelike RELRO gestuur (dit is die GCC/Binutils standaard sedert 2016)**. ### Volledige RELRO * Geproduseer met **albei** vlae `-Wl,-z,relro,-z,now` (ook bekend as `-z relro -z now`). `-z now` dwing die dinamiese laaier om **alle** simbole vooraf op te los (gretige binding) sodat **.got.plt** nooit weer geskryf hoef te word nie en veilig lees-alleen kan wees. * Die hele **GOT**, **.got.plt**, **.fini_array**, **.init_array**, **.preinit_array** en 'n paar addisionele interne glibc tabelle eindig binne 'n lees-alleen `PT_GNU_RELRO` segment. * Voeg meetbare opstart oorhoofse koste by (alle dinamiese herlokasies word by die bekendstelling verwerk) maar **geen uitvoering oorhoofse koste** nie. Sedert 2023 het verskeie hoofstroom verspreidings oorgeskakel na die kompilering van die **stelsels hulpmiddel-ketting** (en die meeste pakkette) met **Volledige RELRO as standaard** – bv. **Debian 12 “bookworm” (dpkg-buildflags 13.0.0)** en **Fedora 35+**. As 'n pentester moet jy dus verwag om binaries te teëkom waar **elke GOT-inskrywing lees-alleen is**. --- ## Hoe om die RELRO-status van 'n binêre te kontroleer ```bash $ checksec --file ./vuln [*] '/tmp/vuln' Arch: amd64-64-little RELRO: Full Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) ``` `checksec` (deel van [pwntools](https://github.com/pwncollege/pwntools) en baie verspreidings) ontleed `ELF` koppe en druk die beskermingsvlak. As jy nie `checksec` kan gebruik nie, vertrou op `readelf`: ```bash # Partial RELRO → PT_GNU_RELRO is present but BIND_NOW is *absent* $ readelf -l ./vuln | grep -E "GNU_RELRO|BIND_NOW" GNU_RELRO 0x0000000000600e20 0x0000000000600e20 ``` ```bash # Full RELRO → PT_GNU_RELRO *and* the DF_BIND_NOW flag $ readelf -d ./vuln | grep BIND_NOW 0x0000000000000010 (FLAGS) FLAGS: BIND_NOW ``` As die binêre loop (bv. 'n set-uid root helper), kan jy steeds die uitvoerbare lêer inspekteer **via `/proc/$PID/exe`**: ```bash readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO ``` --- ## Aktivering van RELRO wanneer jy jou eie kode saamstel ```bash # GCC example – create a PIE with Full RELRO and other common hardenings $ gcc -fPIE -pie -z relro -z now -Wl,--as-needed -D_FORTIFY_SOURCE=2 main.c -o secure ``` `-z relro -z now` werk vir beide **GCC/clang** (gegee na `-Wl,`) en **ld** direk. Wanneer jy **CMake 3.18+** gebruik, kan jy Volle RELRO met die ingeboude voorinstelling versoek: ```cmake set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # LTO set(CMAKE_ENABLE_EXPORTS OFF) set(CMAKE_BUILD_RPATH_USE_ORIGIN ON) set(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,relro,-z,now") ``` --- ## Bypass Tegnieke | RELRO vlak | Tipiese primitiewe | Moglike uitbuitingstegnieke | |-------------|-------------------|----------------------------------| | Geen / Gedeeltelik | Willekeurige skrywe | 1. Oorskry **.got.plt** inskrywing en draai uitvoering om.
2. **ret2dlresolve** – vervaardig vals `Elf64_Rela` & `Elf64_Sym` in 'n skryfbare segment en bel `_dl_runtime_resolve` aan.
3. Oorskry funksie-aanwysers in **.fini_array** / **atexit()** lys. | | Vol | GOT is lees-slegs | 1. Soek **ander skryfbare kode-aanwysers** (C++ vtables, `__malloc_hook` < glibc 2.34, `__free_hook`, terugroepe in pasgemaakte `.data` afdelings, JIT bladsye).
2. Misbruik *relatiewe lees* primitiewe om libc te lek en **SROP/ROP in libc** uit te voer.
3. Spuit 'n rogue gedeelde objek via **DT_RPATH**/`LD_PRELOAD` (as omgewing deur die aanvaller beheer word) of **`ld_audit`**.
4. Exploit **formaat-string** of gedeeltelike aanwyser oorskrywing om die beheerstroom te lei sonder om die GOT aan te raak. | > 💡 Selfs met Vol RELRO is die **GOT van gelaaide gedeelde biblioteke (bv. libc self)** **slegs Gedeeltelik RELRO** omdat daardie objekte reeds gemap is wanneer die laaier herlokasies toepas. As jy 'n **willekeurige skrywe** primitiewe verkry wat 'n ander gedeelde objek se bladsye kan teiken, kan jy steeds uitvoering draai deur libc se GOT inskrywings of die `__rtld_global` stapel oor te skryf, 'n tegniek wat gereeld in moderne CTF-uitdagings benut word. ### Werklike wêreld omseil voorbeeld (2024 CTF – *pwn.college “verlig”*) Die uitdaging is gestuur met Vol RELRO. Die uitbuiting het 'n **off-by-one** gebruik om die grootte van 'n heap stuk te korrupteer, libc gelekt met `tcache poisoning`, en uiteindelik `__free_hook` (buite die RELRO segment) oorgeskryf met 'n een-gadget om kode-uitvoering te verkry. Geen GOT skrywe was nodig nie. --- ## Onlangse navorsing & kwesbaarhede (2022-2025) * **glibc 2.40 de-precates `__malloc_hook` / `__free_hook` (2025)** – Meeste moderne heap uitbuitings wat hierdie simbole misbruik het nou die noodsaak om na alternatiewe vektore soos **`rtld_global._dl_load_jump`** of C++ uitsonderingstabelle te draai. Omdat haken **buite** RELRO leef, verhoog hul verwydering die moeilikheidsgraad van Vol-RELRO omseilings. * **Binutils 2.41 “max-page-size” regstelling (2024)** – 'n Fout het toegelaat dat die laaste paar bytes van die RELRO segment 'n bladsy met skryfbare data op sommige ARM64 boude deel, wat 'n klein **RELRO gaping** gelaat het wat na `mprotect` geskryf kon word. Upstream belyn nou `PT_GNU_RELRO` met bladsygrense, wat daardie randgeval uitskakel. --- ## Verwysings * Binutils dokumentasie – *`-z relro`, `-z now` en `PT_GNU_RELRO`* * *“RELRO – Vol, Gedeeltelik en Omseil Tegnieke”* – blogpos @ wolfslittlered 2023 {{#include ../../banners/hacktricks-training.md}}