Relro

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Relro

RELRO staan vir Relocation Read-Only en is ’n mitigasie wat deur die linker (ld) geïmplementeer word wat ’n substel van die ELF se datasegmente lees-slegs maak nadat alle relocations toegepas is. Die doel is om te keer dat ’n aanvaller inskrywings in die GOT (Global Offset Table) of ander relocasie-verwante tabelle wat tydens programuitvoering gedereferensieer word (bv. __fini_array) oor skryf.

Moderne linkers implementeer RELRO deur die GOT (en ’n paar ander sections) te herorden sodat dit voor die .bss woon en – meesters belangrik – deur ’n toegewyde PT_GNU_RELRO-segment te skep wat as R–X herkaart word net nadat die dynamic loader klaar is met die toepassing van relocations. Gevolglik kan tipiese buffer overflows in die .bss nie meer die GOT bereik nie en kan arbitrary‐write primitives nie gebruik word om funksieaanwysers binne ’n RELRO-beskermde bladsy oor te skryf nie.

Daar is twee vlakke van beskerming wat die linker kan uitstuur:

Partial RELRO

  • Geskep met die vlag -Wl,-z,relro (of net -z relro wanneer ld direk aangeroep word).
  • Slegs die non-PLT deel van die GOT (die deel wat vir data relocations gebruik word) word in die lees-slegs segment geplaas. Seksections wat by run-time gewysig moet word – die belangrikste is .got.plt wat lazy binding ondersteun – bly skryfbaar.
  • As gevolg hiervan kan ’n arbitrary write primitive steeds die uitvoeringsvloei herlei deur ’n PLT-inskrywing oor te skryf (of deur ret2dlresolve uit te voer).
  • Die prestasie-impak is verwaarloosbaar en daarom het byna elke distribusie vir jare pakkette met ten minste Partial RELRO verskaf (dit is die GCC/Binutils standaard sedert 2016).

Full RELRO

  • Geproduseer met beide vlagte -Wl,-z,relro,-z,now (a.k.a. -z relro -z now). -z now dwing die dynamic loader om alle simbole vooraf op te los (eager binding) sodat .got.plt nooit weer geskryf hoef te word nie en veilig as lees-slegs gekaart kan word.
  • Die hele GOT, .got.plt, .fini_array, .init_array, .preinit_array en ’n paar addisionele interne glibc-tabelle beland binne ’n lees-slegs PT_GNU_RELRO-segment.
  • Voeg meetbare opstart-oorhoof by (alle dynamic relocations word by die begin verwerk) maar geen run-time overhead nie.

Sedert 2023 het verskeie hoofstroom distribusies oorgeskakel na die samestelling van die system tool-chain (en meeste pakkette) met Full RELRO by default – bv. Debian 12 “bookworm” (dpkg-buildflags 13.0.0) en Fedora 35+. As ’n pentester moet jy dus verwag om binaries te vind waar elke GOT-inskrywing lees-slegs is.


How to Check the RELRO status of a binary

$ 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 en baie verspreidings) ontleed ELF-opskrifte en toon die beskermingsvlak. As jy nie checksec kan gebruik nie, maak staat op readelf:

# 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
# Full RELRO → PT_GNU_RELRO *and* the DF_BIND_NOW flag
$ readelf -d ./vuln | grep BIND_NOW
0x0000000000000010 (FLAGS)              FLAGS: BIND_NOW

As die binary aan die gang is (e.g. a set-uid root helper), kan jy steeds die executable ondersoek via /proc/$PID/exe:

readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO

Aktiveer RELRO wanneer jy jou eie code kompileer

# 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 (deur -Wl, gegee) en ld direk. Wanneer jy CMake 3.18+ gebruik, kan jy Full RELRO versoek met die ingeboude voorinstelling:

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")

Omseilingstegnieke

RELRO levelTypical primitivePossible exploitation techniques
Geen / GedeeltelikArbitrary write1. Oorskryf .got.plt entry en pivot execution.
2. ret2dlresolve – konstruer vals Elf64_Rela & Elf64_Sym in ’n skryfbare segment en roep _dl_runtime_resolve.
3. Oorskryf funksie-aanwysers in .fini_array / atexit()-lys.
VolledigGOT is read-only1. Soek na ander skryfbare kode-aanwysers (C++ vtables, __malloc_hook < glibc 2.34, __free_hook, callbacks in custom .data sections, JIT pages).
2. Misbruik relative read primitives om libc te leak en SROP/ROP into libc uit te voer.
3. Inspuit ’n kwaadwillige shared object via DT_RPATH/LD_PRELOAD (as die omgewing deur ’n aanvaller beheer word) of ld_audit.
4. Benut format-string of gedeeltelike pointer-oorskrywing om control-flow te verskuif sonder om die GOT aan te raak.

💡 Selfs met Full RELRO is die GOT van gelaaide shared libraries (e.g. libc itself) slegs Partial RELRO omdat daardie objekte reeds gemapped is wanneer die loader relocations toepas. If you gain an arbitrary write primitive that can target another shared object’s pages you can still pivot execution by overwriting libc’s GOT entries or the __rtld_global stack, a technique regularly exploited in modern CTF challenges.

Werklike voorbeeld van omseiling (2024 CTF – pwn.college “enlightened”)

Die challenge is met Full RELRO verskaf. Die exploit het ’n off-by-one gebruik om die grootte van ’n heap chunk te korrupteer, leaked libc with tcache poisoning, en uiteindelik __free_hook (buite die RELRO-segment) oorskryf met ’n one-gadget om code execution te kry. Geen GOT write was benodig nie.


Onlangse navorsing & kwetsbaarhede (2022-2025)

  • glibc hook removal (2.34 → present) – malloc/free hooks is uitgehaal uit die hoof libc in die opsionele libc_malloc_debug.so, wat ’n algemene Full‑RELRO omseil-primitive verwyder; moderne exploits moet ander skryfbare aanwysers teiken.
  • GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41) – linker bug 30612 het veroorsaak dat die laaste bytes van PT_GNU_RELRO ’n skryfbare bladsy gedeel het op 64 KiB bladsy sisteme; huidige binutils belyn RELRO op max-page-size, wat daardie “RELRO gap” sluit.

References

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks