Relro
Reading time: 7 minutes
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 σημαίνει Relocation Read-Only και είναι μια μείωση που εφαρμόζεται από τον σύνδεσμο (ld
) που καθιστά ένα υποσύνολο των δεδομένων του ELF μόνο για ανάγνωση μετά την εφαρμογή όλων των ανακατατάξεων. Ο στόχος είναι να σταματήσει έναν επιτιθέμενο από το να αντικαταστήσει τις καταχωρήσεις στον GOT (Global Offset Table) ή σε άλλες σχετικές πίνακες ανακατατάξεων που αναφέρονται κατά την εκτέλεση του προγράμματος (π.χ. __fini_array
).
Οι σύγχρονοι σύνδεσμοι εφαρμόζουν το RELRO με το να αναδιατάσσουν τον GOT (και μερικές άλλες ενότητες) έτσι ώστε να βρίσκονται πριν από το .bss και – το πιο σημαντικό – δημιουργώντας ένα αφιερωμένο τμήμα PT_GNU_RELRO
που ανακατανέμεται R–X
αμέσως μετά την ολοκλήρωση της εφαρμογής των ανακατατάξεων από τον δυναμικό φορτωτή. Ως εκ τούτου, οι τυπικές υπερχειλίσεις buffer στο .bss δεν μπορούν πλέον να φτάσουν τον GOT και οι αυθαίρετες εγγραφές δεν μπορούν να χρησιμοποιηθούν για να αντικαταστήσουν δείκτες συναρτήσεων που βρίσκονται μέσα σε μια σελίδα προστατευμένη από RELRO.
Υπάρχουν δύο επίπεδα προστασίας που μπορεί να εκπέμψει ο σύνδεσμος:
Partial RELRO
- Παράγεται με τη σημαία
-Wl,-z,relro
(ή απλά-z relro
όταν καλείτε απευθείας τοld
). - Μόνο το μη-PLT μέρος του GOT (το μέρος που χρησιμοποιείται για τις ανακατατάξεις δεδομένων) τοποθετείται στο τμήμα μόνο για ανάγνωση. Οι ενότητες που χρειάζονται τροποποίηση κατά την εκτέλεση – το πιο σημαντικό .got.plt που υποστηρίζει lazy binding – παραμένουν εγγράψιμες.
- Εξαιτίας αυτού, μια αυθαίρετη εγγραφή μπορεί ακόμα να ανακατευθύνει τη ροή εκτέλεσης αντικαθιστώντας μια καταχώρηση PLT (ή εκτελώντας ret2dlresolve).
- Ο αντίκτυπος στην απόδοση είναι αμελητέος και επομένως σχεδόν κάθε διανομή αποστέλλει πακέτα με τουλάχιστον Partial RELRO εδώ και χρόνια (είναι η προεπιλογή GCC/Binutils από το 2016).
Full RELRO
- Παράγεται με και τις δύο σημαίες
-Wl,-z,relro,-z,now
(γνωστό και ως-z relro -z now
).-z now
αναγκάζει τον δυναμικό φορτωτή να επιλύσει όλους τους συμβολισμούς εκ των προτέρων (eager binding) έτσι ώστε το .got.plt να μην χρειάζεται ποτέ να γραφτεί ξανά και μπορεί να χαρτογραφηθεί με ασφάλεια μόνο για ανάγνωση. - Ολόκληρος ο GOT, .got.plt, .fini_array, .init_array, .preinit_array και μερικοί επιπλέον εσωτερικοί πίνακες glibc καταλήγουν μέσα σε ένα τμήμα μόνο για ανάγνωση
PT_GNU_RELRO
. - Προσθέτει μετρήσιμο κόστος εκκίνησης (όλες οι δυναμικές ανακατατάξεις επεξεργάζονται κατά την εκκίνηση) αλλά κανένα κόστος εκτέλεσης.
Από το 2023 πολλές κύριες διανομές έχουν αλλάξει σε σύνθεση της εργαλειοθήκης συστήματος (και των περισσότερων πακέτων) με Full RELRO ως προεπιλογή – π.χ. Debian 12 “bookworm” (dpkg-buildflags 13.0.0) και Fedora 35+. Ως pentester, θα πρέπει επομένως να περιμένετε να συναντήσετε δυαδικά αρχεία όπου κάθε καταχώρηση GOT είναι μόνο για ανάγνωση.
Πώς να ελέγξετε την κατάσταση RELRO ενός δυαδικού αρχείου
$ 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
Αν το δυαδικό αρχείο εκτελείται (π.χ. ένας βοηθός set-uid root), μπορείτε να επιθεωρήσετε το εκτελέσιμο μέσω /proc/$PID/exe
:
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
Ενεργοποίηση RELRO κατά τη σύνταξη του δικού σας κώδικα
# 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 | Τυπική πρωτογενής | Πιθανές τεχνικές εκμετάλλευσης |
---|---|---|
Καμία / Μερική | Αυθαίρετη εγγραφή | 1. Επικαλύψτε την είσοδο .got.plt και αλλάξτε την εκτέλεση. 2. ret2dlresolve – δημιουργήστε ψεύτικα Elf64_Rela & Elf64_Sym σε ένα εγγράψιμο τμήμα και καλέστε το _dl_runtime_resolve .3. Επικαλύψτε δείκτες συναρτήσεων στη λίστα .fini_array / atexit(). |
Πλήρης | Το GOT είναι μόνο για ανάγνωση | 1. Αναζητήστε άλλους εγγράψιμους δείκτες κώδικα (C++ vtables, __malloc_hook < glibc 2.34, __free_hook , callbacks σε προσαρμοσμένα τμήματα .data , JIT σελίδες).2. Καταχρήστε σχετικές αναγνωστικές πρωτογενείς για να διαρρεύσετε τη libc και να εκτελέσετε SROP/ROP στη libc. 3. Εισάγετε ένα κακόβουλο κοινόχρηστο αντικείμενο μέσω DT_RPATH/ LD_PRELOAD (αν το περιβάλλον ελέγχεται από τον επιτιθέμενο) ή ld_audit .4. Εκμεταλλευτείτε format-string ή μερική επικαλύψη δείκτη για να αλλάξετε τη ροή ελέγχου χωρίς να αγγίξετε το GOT. |
💡 Ακόμα και με Πλήρη RELRO το GOT των φορτωμένων κοινών βιβλιοθηκών (π.χ. η libc) είναι μόνο Μερικό RELRO επειδή αυτά τα αντικείμενα είναι ήδη χαρτογραφημένα όταν ο φορτωτής εφαρμόζει τις ανακατατάξεις. Αν αποκτήσετε μια αυθαίρετη εγγραφή που μπορεί να στοχεύσει σε σελίδες άλλου κοινόχρηστου αντικειμένου, μπορείτε ακόμα να αλλάξετε την εκτέλεση επικαλύπτοντας τις εγγραφές GOT της libc ή τη στοίβα
__rtld_global
, μια τεχνική που εκμεταλλεύεται τακτικά σε σύγχρονες προκλήσεις CTF.
Παράδειγμα παράκαμψης στον πραγματικό κόσμο (2024 CTF – pwn.college “enlightened”)
Η πρόκληση παραδόθηκε με Πλήρη RELRO. Η εκμετάλλευση χρησιμοποίησε ένα off-by-one για να διαφθείρει το μέγεθος ενός κομματιού σωρού, διέρρευσε τη libc με tcache poisoning
, και τελικά επικαλέστηκε το __free_hook
(εκτός του τμήματος RELRO) με ένα one-gadget για να αποκτήσει εκτέλεση κώδικα. Δεν απαιτήθηκε εγγραφή στο GOT.
Πρόσφατη έρευνα & ευπάθειες (2022-2025)
- glibc 2.40 αποσύρει το
__malloc_hook
/__free_hook
(2025) – Οι περισσότερες σύγχρονες εκμεταλλεύσεις σωρού που εκμεταλλεύτηκαν αυτά τα σύμβολα πρέπει τώρα να στραφούν σε εναλλακτικές διαδρομές όπωςrtld_global._dl_load_jump
ή πίνακες εξαιρέσεων C++. Επειδή οι γάντζοι βρίσκονται εκτός του RELRO, η αφαίρεσή τους αυξάνει τη δυσκολία των παρακάμψεων Πλήρους RELRO. - Binutils 2.41 “max-page-size” διόρθωση (2024) – Ένα σφάλμα επέτρεψε στους τελευταίους λίγους byte του τμήματος RELRO να μοιράζονται μια σελίδα με εγγράψιμα δεδομένα σε ορισμένες κατασκευές ARM64, αφήνοντας ένα μικρό RELRO κενό που θα μπορούσε να γραφτεί μετά το
mprotect
. Η upstream τώρα ευθυγραμμίζει τοPT_GNU_RELRO
με τα όρια σελίδων, εξαλείφοντας αυτή την περίπτωση.
Αναφορές
- Τεκμηρίωση Binutils –
-z relro
,-z now
καιPT_GNU_RELRO
- “RELRO – Πλήρης, Μερική και Τεχνικές Παράκαμψης” – ανάρτηση ιστολογίου @ wolfslittlered 2023
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.