Relro
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Relro
RELRO stands for Relocation Read-Only και είναι μια μετριαστική τεχνική που υλοποιείται από τον linker (ld) που κάνει ένα υπόσύνολο των data segments του ELF read-only after all relocations have been applied. Ο στόχος είναι να εμποδίσει έναν επιτιθέμενο από το να αντικαταστήσει εγγραφές στον GOT (Global Offset Table) ή άλλους πίνακες σχετιζόμενους με relocations που dereference-ούνται κατά την εκτέλεση του προγράμματος (π.χ. __fini_array).
Οι σύγχρονοι linkers υλοποιούν το RELRO με την re–ordering της GOT (και μερικών άλλων sections) ώστε να βρίσκονται πριν την .bss και — πιο σημαντικό — με τη δημιουργία ενός αφιερωμένου segment PT_GNU_RELRO που επαναχαρτογραφείται R–X αμέσως μετά το τέλος της εφαρμογής των relocations από τον dynamic loader. Συνεπώς, τυπικά buffer overflows στην .bss δεν μπορούν πλέον να φτάσουν το GOT και μηχανισμοί arbitrary‐write δεν μπορούν να χρησιμοποιηθούν για να αντικαταστήσουν δείκτες συναρτήσεων που βρίσκονται σε σελίδα προστατευμένη με RELRO.
Υπάρχουν δύο επίπεδα προστασίας που μπορεί να εκδώσει ο linker:
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.
How to Check the RELRO status of a binary
$ checksec --file ./vuln
[*] '/tmp/vuln'
Arch: amd64-64-little
RELRO: Full
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
checksec (μέρος του pwntools και πολλών διανομών) αναλύει τις κεφαλίδες ELF και εμφανίζει το επίπεδο προστασίας. Αν δεν μπορείτε να χρησιμοποιήσετε το checksec, βασιστείτε σε 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
Αν το binary εκτελείται (π.χ. set-uid root helper), μπορείς ακόμη να επιθεωρήσεις το εκτελέσιμο μέσω του /proc/$PID/exe:
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
Ενεργοποίηση RELRO κατά τη μεταγλώττιση του δικού σας code
# 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 λειτουργεί και για τα GCC/clang (περασμένο μετά από -Wl,) και για το ld απευθείας. Όταν χρησιμοποιείτε το CMake 3.18+ μπορείτε να ζητήσετε Full RELRO με την ενσωματωμένη προεπιλογή:
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")
Τεχνικές Παράκαμψης
| RELRO level | Τυπικό primitive | Πιθανές τεχνικές εκμετάλλευσης |
|---|---|---|
| Κανένα / Μερικό | Arbitrary write | 1. Επικαλύψτε την καταχώρηση .got.plt και ανακατευθύνετε την εκτέλεση. 2. ret2dlresolve – δημιουργήστε ψεύτικα Elf64_Rela & Elf64_Sym σε εγγράψιμο τμήμα και καλέστε _dl_runtime_resolve.3. Επικαλύψτε δείκτες συναρτήσεων σε .fini_array / λίστα atexit(). |
| Πλήρες | GOT is read-only | 1. Αναζητήστε άλλους εγγράψιμους δείκτες κώδικα (C++ vtables, __malloc_hook < glibc 2.34, __free_hook, callbacks σε προσαρμοσμένα τμήματα .data, JIT σελίδες).2. Εκμεταλλευθείτε relative read primitives για να leak το libc και να εκτελέσετε SROP/ROP into libc. 3. Ενθέστε ένα rogue shared object μέσω DT_RPATH/ LD_PRELOAD (αν το περιβάλλον ελέγχεται από τον επιτιθέμενο) ή ld_audit.4. Εκμεταλλευθείτε format-string ή μερική επικάλυψη δεικτών για να αποκλίνετε τη ροή ελέγχου χωρίς να αγγίξετε το GOT. |
💡 Ακόμα και με Full RELRO, το GOT των φορτωμένων shared libraries (π.χ. libc itself) είναι only Partial RELRO επειδή αυτά τα αντικείμενα έχουν ήδη χαρτογραφηθεί όταν ο loader εφαρμόζει relocations. Εάν αποκτήσετε ένα arbitrary write primitive που μπορεί να στοχεύσει τις σελίδες ενός άλλου shared object, μπορείτε ακόμα να ανακατευθύνετε την εκτέλεση επικαλύπτοντας καταχωρήσεις GOT του libc ή το στοίβα
__rtld_global, μια τεχνική που εκμεταλλεύονται τακτικά σε σύγχρονα CTF challenges.
Πραγματικό παράδειγμα παράκαμψης (2024 CTF – pwn.college “enlightened”)
Το challenge shipped με Full RELRO. Το exploit χρησιμοποίησε ένα off-by-one για να καταστρέψει το μέγεθος ενός heap chunk, leaked libc με tcache poisoning, και τελικά επικαλύψε το __free_hook (εκτός του τμήματος RELRO) με ένα one-gadget για να αποκτήσει εκτέλεση κώδικα. Δεν απαιτήθηκε εγγραφή στο GOT.
Πρόσφατη έρευνα & ευπάθειες (2022-2025)
- glibc hook removal (2.34 → present) – τα malloc/free hooks αποσπάστηκαν από το κύριο libc στο προαιρετικό
libc_malloc_debug.so, εξαλείφοντας ένα κοινό Full‑RELRO bypass primitive· τα σύγχρονα exploits πρέπει να στοχεύουν άλλους εγγράψιμους δείκτες. - GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41) – το bug του linker 30612 προκάλεσε τα τελευταία bytes του
PT_GNU_RELROνα μοιράζονται μια εγγράψιμη σελίδα σε συστήματα με σελίδες 64 KiB· τα τρέχοντα binutils ευθυγραμμίζουν το RELRO στοmax-page-size, κλείνοντας αυτό το “RELRO gap”.
Αναφορές
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.


