Relro
Reading time: 7 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
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
, wennld
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
$ 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 und vielen Distributionen) analysiert ELF
-Header und gibt das Schutzniveau aus. Wenn Sie checksec
nicht verwenden können, verlassen Sie sich auf 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
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:
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
Aktivieren von RELRO beim Kompilieren Ihres eigenen Codes
# 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:
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. 2. ret2dlresolve – gefälschte Elf64_Rela & Elf64_Sym in einem beschreibbaren Segment erstellen und _dl_runtime_resolve aufrufen.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).2. Missbrauch von relativen Lese-Primitiven, um libc auszulesen und SROP/ROP in libc durchzuführen. 3. Ein bösartiges Shared Object über DT_RPATH/ LD_PRELOAD injizieren (wenn die Umgebung vom Angreifer kontrolliert wird) oder ld_audit .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 wiertld_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 jetztPT_GNU_RELRO
an Seitengrenzen aus, wodurch diesen Randfall beseitigt wird.
Referenzen
- Binutils-Dokumentation –
-z relro
,-z now
undPT_GNU_RELRO
- “RELRO – Voll, Teilweise und Bypass-Techniken” – Blogbeitrag @ wolfslittlered 2023
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.