100 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 `RX` 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.<br>2. **ret2dlresolve** vervaardig vals `Elf64_Rela` & `Elf64_Sym` in 'n skryfbare segment en bel `_dl_runtime_resolve` aan.<br>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).<br>2. Misbruik *relatiewe lees* primitiewe om libc te lek en **SROP/ROP in libc** uit te voer.<br>3. Spuit 'n rogue gedeelde objek via **DT_RPATH**/`LD_PRELOAD` (as omgewing deur die aanvaller beheer word) of **`ld_audit`**.<br>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}}