# 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}}