mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
100 lines
7.6 KiB
Markdown
100 lines
7.6 KiB
Markdown
# Relro
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Relro
|
||
|
||
**RELRO** steht für **Relocation Read-Only** und ist eine Minderung, die vom Linker (`ld`) implementiert wird, der einen Teil der ELF-Datensegmente **nach Anwendung aller Relokationen schreibgeschützt macht**. Das Ziel ist es, einen Angreifer daran zu hindern, Einträge in der **GOT (Global Offset Table)** oder anderen relokationsbezogenen Tabellen zu überschreiben, die während der Programmausführung dereferenziert werden (z. B. `__fini_array`).
|
||
|
||
Moderne Linker implementieren RELRO, indem sie die **GOT** (und einige andere Abschnitte) **neu anordnen**, sodass sie **vor** der **.bss** leben und – am wichtigsten – indem sie ein dediziertes `PT_GNU_RELRO`-Segment erstellen, das direkt nach Abschluss der Relokationen durch den dynamischen Loader `R–X` umgemappt wird. Folglich können typische Pufferüberläufe in der **.bss** die GOT nicht mehr erreichen, und willkürliche Schreibprimitive können nicht verwendet werden, um Funktionszeiger zu überschreiben, die sich innerhalb einer RELRO-geschützten Seite befinden.
|
||
|
||
Es gibt **zwei Ebenen** des Schutzes, die der Linker ausgeben kann:
|
||
|
||
### Partial RELRO
|
||
|
||
* Produziert mit dem Flag `-Wl,-z,relro` (oder einfach `-z relro`, wenn `ld` direkt aufgerufen wird).
|
||
* Nur der **nicht-PLT** Teil der **GOT** (der Teil, der für Datenrelokationen verwendet wird) wird in das schreibgeschützte Segment gelegt. Abschnitte, die zur Laufzeit geändert werden müssen – am wichtigsten **.got.plt**, das **lazy binding** unterstützt – bleiben beschreibbar.
|
||
* Aufgrund dessen kann ein **willkürliches Schreiben** immer noch den Ausführungsfluss umleiten, indem ein PLT-Eintrag überschrieben wird (oder durch Ausführen von **ret2dlresolve**).
|
||
* Der Leistungsimpact ist vernachlässigbar und daher **versenden fast alle Distributionen seit Jahren Pakete mit mindestens Partial RELRO (es ist der GCC/Binutils-Standard seit 2016)**.
|
||
|
||
### Full RELRO
|
||
|
||
* Produziert mit **beiden** Flags `-Wl,-z,relro,-z,now` (auch bekannt als `-z relro -z now`). `-z now` zwingt den dynamischen Loader, **alle** Symbole im Voraus aufzulösen (eager binding), sodass **.got.plt** nie wieder geschrieben werden muss und sicher schreibgeschützt gemappt werden kann.
|
||
* Die gesamte **GOT**, **.got.plt**, **.fini_array**, **.init_array**, **.preinit_array** und einige zusätzliche interne glibc-Tabellen landen in einem schreibgeschützten `PT_GNU_RELRO`-Segment.
|
||
* Fügt messbare Startkosten hinzu (alle dynamischen Relokationen werden beim Start verarbeitet), aber **keine Laufzeitkosten**.
|
||
|
||
Seit 2023 haben mehrere gängige Distributionen damit begonnen, die **System-Toolchain** (und die meisten Pakete) standardmäßig mit **Full RELRO** zu kompilieren – z. B. **Debian 12 “bookworm” (dpkg-buildflags 13.0.0)** und **Fedora 35+**. Als Pentester sollten Sie daher erwarten, auf Binärdateien zu stoßen, bei denen **jeder GOT-Eintrag schreibgeschützt ist**.
|
||
|
||
---
|
||
|
||
## So überprüfen Sie den RELRO-Status einer Binärdatei
|
||
```bash
|
||
$ checksec --file ./vuln
|
||
[*] '/tmp/vuln'
|
||
Arch: amd64-64-little
|
||
RELRO: Full
|
||
Stack: Canary found
|
||
NX: NX enabled
|
||
PIE: No PIE (0x400000)
|
||
```
|
||
`checksec` (Teil von [pwntools](https://github.com/pwncollege/pwntools) und vielen Distributionen) analysiert `ELF`-Header und gibt das Schutzniveau aus. Wenn Sie `checksec` nicht verwenden können, verlassen Sie sich auf `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
|
||
```
|
||
Wenn die Binärdatei läuft (z. B. ein set-uid root Helper), können Sie die ausführbare Datei weiterhin **über `/proc/$PID/exe`** inspizieren:
|
||
```bash
|
||
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
|
||
```
|
||
---
|
||
|
||
## Aktivieren von RELRO beim Kompilieren Ihres eigenen Codes
|
||
```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` funktioniert sowohl für **GCC/clang** (nach `-Wl,` übergeben) als auch direkt für **ld**. Wenn Sie **CMake 3.18+** verwenden, können Sie Full RELRO mit dem integrierten Preset anfordern:
|
||
```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-Techniken
|
||
|
||
| RELRO-Stufe | Typische Primitive | Mögliche Ausnutzungstechniken |
|
||
|-------------|-------------------|----------------------------------|
|
||
| Keine / Teilweise | Arbiträres Schreiben | 1. Überschreiben des **.got.plt**-Eintrags und Ausführung umschalten.<br>2. **ret2dlresolve** – gefälschte `Elf64_Rela` & `Elf64_Sym` in einem beschreibbaren Segment erstellen und `_dl_runtime_resolve` aufrufen.<br>3. Funktionszeiger in **.fini_array** / **atexit()**-Liste überschreiben. |
|
||
| Voll | GOT ist schreibgeschützt | 1. Nach **anderen beschreibbaren Codezeigern** suchen (C++ vtables, `__malloc_hook` < glibc 2.34, `__free_hook`, Rückrufe in benutzerdefinierten `.data`-Sektionen, JIT-Seiten).<br>2. Missbrauch von *relativen Lese*-Primitiven, um libc auszulesen und **SROP/ROP in libc** durchzuführen.<br>3. Ein bösartiges Shared Object über **DT_RPATH**/`LD_PRELOAD` injizieren (wenn die Umgebung vom Angreifer kontrolliert wird) oder **`ld_audit`**.<br>4. **Format-String** oder teilweise Zeigerüberschreibung ausnutzen, um den Kontrollfluss umzuleiten, ohne die GOT zu berühren. |
|
||
|
||
> 💡 Selbst mit Voll-RELRO ist die **GOT von geladenen Shared Libraries (z.B. libc selbst)** **nur Teilweise RELRO**, da diese Objekte bereits gemappt sind, wenn der Loader die Relokationen anwendet. Wenn Sie ein **arbiträres Schreiben**-Primitive erhalten, das auf die Seiten eines anderen Shared Objects abzielt, können Sie die Ausführung weiterhin umschalten, indem Sie die GOT-Einträge von libc oder den `__rtld_global`-Stack überschreiben, eine Technik, die regelmäßig in modernen CTF-Herausforderungen ausgenutzt wird.
|
||
|
||
### Beispiel für einen echten Bypass (2024 CTF – *pwn.college “enlightened”*)
|
||
|
||
Die Herausforderung wurde mit Voll-RELRO ausgeliefert. Der Exploit nutzte ein **Off-by-One**, um die Größe eines Heap-Chunks zu korrumpieren, leakte libc mit `tcache poisoning` und überschreibt schließlich `__free_hook` (außerhalb des RELRO-Segments) mit einem One-Gadget, um Codeausführung zu erhalten. Es war kein GOT-Schreiben erforderlich.
|
||
|
||
---
|
||
|
||
## Aktuelle Forschung & Schwachstellen (2022-2025)
|
||
|
||
* **glibc 2.40 deprecates `__malloc_hook` / `__free_hook` (2025)** – Die meisten modernen Heap-Exploits, die diese Symbole ausnutzten, müssen nun auf alternative Vektoren wie **`rtld_global._dl_load_jump`** oder C++-Ausnahmetabellen umschalten. Da Hooks **außerhalb** von RELRO leben, erhöht ihre Entfernung die Schwierigkeit von Voll-RELRO-Bypässen.
|
||
* **Binutils 2.41 “max-page-size” Fix (2024)** – Ein Fehler erlaubte es, dass die letzten paar Bytes des RELRO-Segments eine Seite mit beschreibbaren Daten auf einigen ARM64-Bauten teilten, was eine kleine **RELRO-Lücke** hinterließ, die nach `mprotect` geschrieben werden konnte. Der Upstream richtet jetzt `PT_GNU_RELRO` an Seitengrenzen aus, wodurch diesen Randfall beseitigt wird.
|
||
|
||
---
|
||
|
||
## Referenzen
|
||
|
||
* Binutils-Dokumentation – *`-z relro`, `-z now` und `PT_GNU_RELRO`*
|
||
* *“RELRO – Voll, Teilweise und Bypass-Techniken”* – Blogbeitrag @ wolfslittlered 2023
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|