Relro
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Relro
RELRO stands for Relocation Read-Only and it is a mitigation implemented by the linker (ld) that turns a subset of the ELF’s data segments read-only after all relocations have been applied. The goal is to stop an attacker from overwriting entries in the GOT (Global Offset Table) or other relocation-related tables that are dereferenced during program execution (e.g. __fini_array).
Modern linkers implement RELRO by re–ordering the GOT (and a few other sections) so they live before the .bss and – most importantly – by creating a dedicated PT_GNU_RELRO segment that is remapped R–X right after the dynamic loader finishes applying relocations. Consequently, typical buffer overflows in the .bss can no longer reach the GOT and arbitrary‐write primitives cannot be used to overwrite function pointers that sit inside a RELRO-protected page.
There are two levels of protection that the linker can emit:
Partial RELRO
- Produced with the flag
-Wl,-z,relro(or just-z relrowhen invokinglddirectly). - Only the non-PLT part of the GOT (the part used for data relocations) is put into the read-only segment. Sections that need to be modified at run-time – most importantly .got.plt which supports lazy binding – remain writable.
- Because of that, an arbitrary write primitive can still redirect execution flow by overwriting a PLT entry (or by performing ret2dlresolve).
- The performance impact is negligible and therefore almost every distribution has been shipping packages with at least Partial RELRO for years (it is the GCC/Binutils default as of 2016).
Full RELRO
- Produced with both flags
-Wl,-z,relro,-z,now(a.k.a.-z relro -z now).-z nowforces the dynamic loader to resolve all symbols up-front (eager binding) so that .got.plt never needs to be written again and can safely be mapped read-only. - The entire GOT, .got.plt, .fini_array, .init_array, .preinit_array and a few additional internal glibc tables end up inside a read-only
PT_GNU_RELROsegment. - Adds measurable start-up overhead (all dynamic relocations are processed at launch) but no run-time overhead.
Since 2023 several mainstream distributions have switched to compiling the system tool-chain (and most packages) with Full RELRO by default – e.g. Debian 12 “bookworm” (dpkg-buildflags 13.0.0) and Fedora 35+. As a pentester you should therefore expect to encounter binaries where every GOT entry is read-only.
Bir ikili dosyanın RELRO durumunu nasıl kontrol edersiniz
$ checksec --file ./vuln
[*] '/tmp/vuln'
Arch: amd64-64-little
RELRO: Full
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
checksec ([pwntools] paketinin bir parçası ve birçok dağıtımda mevcuttur) ELF başlıklarını çözer ve koruma seviyesini yazdırır. checksec kullanamıyorsanız, readelf’e güvenin:
# 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
Eğer binary çalışıyorsa (ör. set-uid root helper), yine yürütülebilir dosyayı üzerinden /proc/$PID/exe inceleyebilirsiniz:
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
Kendi kodunuzu derlerken RELRO’yu etkinleştirme
# 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 hem GCC/clang (-Wl, sonrasında geçirilir) hem de doğrudan ld için çalışır. CMake 3.18+ kullanıyorsanız yerleşik preset ile Full RELRO talep edebilirsiniz:
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")
Atlatma Teknikleri
| RELRO level | Typical primitive | Possible exploitation techniques |
|---|---|---|
| None / Partial | Arbitrary write | 1. Overwrite .got.plt entry and pivot execution. 2. ret2dlresolve – craft fake Elf64_Rela & Elf64_Sym in a writable segment and call _dl_runtime_resolve.3. Overwrite function pointers in .fini_array / atexit() list. |
| Full | GOT is read-only | 1. Look for other writable code pointers (C++ vtables, __malloc_hook < glibc 2.34, __free_hook, callbacks in custom .data sections, JIT pages).2. Abuse relative read primitives to leak libc and perform SROP/ROP into libc. 3. Inject a rogue shared object via DT_RPATH/ LD_PRELOAD (if environment is attacker-controlled) or ld_audit.4. Exploit format-string or partial pointer overwrite to divert control-flow without touching the GOT. |
💡 Full RELRO olsa bile, GOT of loaded shared libraries (e.g. libc itself) sadece Partial RELRO olur çünkü loader relocations uygulandığında bu nesneler zaten maplenmiş olur. Eğer başka bir shared object’in sayfalarını hedefleyebilen bir arbitrary write primitive elde ederseniz, libc’nin GOT entry’lerini veya
__rtld_globalyığınını overwrite ederek hâlâ execution pivot edebilirsiniz; bu, modern CTF challenge’larında düzenli olarak kullanılan bir tekniktir.
Gerçek dünya atlatma örneği (2024 CTF – pwn.college “enlightened”)
Challenge Full RELRO ile geldi. Exploit, heap chunk boyutunu bozmak için bir off-by-one kullandı, tcache poisoning ile libc’yi leaked etti ve sonunda RELRO segmenti dışında kalan __free_hook’u bir one-gadget ile overwrite ederek kod yürütme elde etti. GOT yazması gerekmedi.
Son araştırmalar & zafiyetler (2022-2025)
- glibc hook removal (2.34 → present) – malloc/free hook’ları ana libc’den opsiyonel
libc_malloc_debug.so’ya taşındı; bu, yaygın bir Full‑RELRO atlatma primitive’ini ortadan kaldırdı; modern exploit’lerin diğer writable pointer’ları hedeflemesi gerekiyor. - GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41) – linker bug 30612,
PT_GNU_RELRO’nun son byte’larının 64 KiB sayfa sistemlerinde writable bir sayfayı paylaşmasına neden oluyordu; mevcut binutils RELRO’yumax-page-size’a hizalayarak bu “RELRO gap”i kapattı.
References
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


