Relro
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Relro
RELRO signifie Relocation Read-Only et c’est une atténuation implémentée par l’éditeur de liens (ld) qui rend un sous-ensemble des segments de données ELF en lecture seule après que toutes les relocations ont été appliquées. L’objectif est d’empêcher un attaquant d’écraser des entrées dans la GOT (Global Offset Table) ou d’autres tables liées aux relocations qui sont déréférencées pendant l’exécution du programme (par ex. __fini_array).
Les linkers modernes implémentent RELRO en réordonnant la GOT (et quelques autres sections) de sorte qu’elles se trouvent avant la .bss et — surtout — en créant un segment dédié PT_GNU_RELRO qui est remappé en R–X immédiatement après que le chargeur dynamique a fini d’appliquer les relocations. Par conséquent, les débordements de tampon typiques dans la .bss ne peuvent plus atteindre la GOT et des primitives d’écriture arbitraire ne peuvent pas être utilisées pour écraser des pointeurs de fonction situés dans une page protégée par RELRO.
Il existe deux niveaux de protection que l’éditeur de liens peut émettre :
Partial RELRO
- Produit avec le drapeau
-Wl,-z,relro(ou simplement-z relrolorsque l’on invoquelddirectement). - Seule la partie non-PLT de la GOT (la partie utilisée pour les relocations de données) est placée dans le segment en lecture seule. Les sections qui doivent être modifiées à l’exécution – surtout .got.plt qui prend en charge le lazy binding – restent modifiables.
- De ce fait, une primitive d’arbitrary write peut encore rediriger le flux d’exécution en écrasant une entrée PLT (ou en effectuant un ret2dlresolve).
- L’impact sur les performances est négligeable et par conséquent presque toutes les distributions livrent des paquets avec au moins Partial RELRO depuis des années (c’est le comportement par défaut de GCC/Binutils depuis 2016).
Full RELRO
- Produit avec les deux flags
-Wl,-z,relro,-z,now(a.k.a.-z relro -z now).-z nowforce le chargeur dynamique à résoudre tous les symboles au démarrage (eager binding) de sorte que .got.plt n’ait plus jamais besoin d’être écrit et puisse être mappé en lecture seule. - L’ensemble de la GOT, .got.plt, .fini_array, .init_array, .preinit_array et quelques tables internes supplémentaires de glibc se retrouvent dans un segment
PT_GNU_RELROen lecture seule. - Ajoute une surcharge de démarrage mesurable (toutes les relocations dynamiques sont traitées au lancement) mais aucune surcharge à l’exécution.
Depuis 2023, plusieurs distributions grand public ont basculé vers la compilation de la system tool-chain (et de la plupart des paquets) avec Full RELRO par défaut — par exemple Debian 12 “bookworm” (dpkg-buildflags 13.0.0) et Fedora 35+. En tant que pentester, vous devez donc vous attendre à rencontrer des binaires où chaque entrée GOT est en lecture seule.
Comment vérifier le statut RELRO d’un binaire
$ checksec --file ./vuln
[*] '/tmp/vuln'
Arch: amd64-64-little
RELRO: Full
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
checksec (part of pwntools et de nombreuses distributions) analyse les en-têtes ELF et affiche le niveau de protection. Si vous ne pouvez pas utiliser checksec, utilisez 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
Si le binaire est en cours d’exécution (par ex. un set-uid root helper), vous pouvez toujours inspecter l’exécutable via /proc/$PID/exe :
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
Activer RELRO lors de la compilation de votre propre 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 fonctionne à la fois pour GCC/clang (passé après -Wl,) et pour ld directement. Lorsque vous utilisez CMake 3.18+ vous pouvez demander Full RELRO avec le preset intégré :
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")
Techniques de contournement
| RELRO level | Typical primitive | Possible exploitation techniques |
|---|---|---|
| Aucun / Partiel | Arbitrary write | 1. Écraser l’entrée .got.plt et pivoter l’exécution. 2. ret2dlresolve – construire de faux Elf64_Rela & Elf64_Sym dans un segment écrivable et appeler _dl_runtime_resolve.3. Écraser les pointeurs de fonction dans .fini_array / la liste atexit(). |
| Full | GOT is read-only | 1. Chercher d’autres writable code pointers (C++ vtables, __malloc_hook < glibc 2.34, __free_hook, callbacks in custom .data sections, JIT pages).2. Abuser des primitives relative read pour leak libc et effectuer SROP/ROP into libc. 3. Injecter une bibliothèque partagée malveillante via DT_RPATH/ LD_PRELOAD (si l’environnement est contrôlé par l’attaquant) ou ld_audit.4. Exploiter format-string ou un écrasement partiel de pointeur pour détourner le flux de contrôle sans toucher le GOT. |
💡 Même avec Full RELRO le GOT des bibliothèques partagées chargées (p.ex. libc lui-même) est seulement Partial RELRO parce que ces objets sont déjà mappés lorsque le chargeur applique les relocations. Si vous gagnez une primitive arbitrary write pouvant cibler les pages d’une autre bibliothèque partagée vous pouvez toujours pivoter l’exécution en écrasant les entrées GOT de libc ou la pile
__rtld_global, une technique régulièrement exploitée dans les CTF modernes.
Real-world bypass example (2024 CTF – pwn.college “enlightened”)
Le challenge était livré avec Full RELRO. L’exploit a utilisé un off-by-one pour corrompre la taille d’un heap chunk, a leak libc avec tcache poisoning, et a finalement écrasé __free_hook (en dehors du segment RELRO) avec un one-gadget pour obtenir l’exécution de code. Aucune écriture sur le GOT n’était requise.
Recherches récentes & vulnérabilités (2022-2025)
- glibc hook removal (2.34 → present) – les malloc/free hooks ont été extraits du libc principal vers la
libc_malloc_debug.sooptionnelle, éliminant un primitive courant de contournement Full‑RELRO ; les exploits modernes doivent cibler d’autres pointeurs modifiables. - GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41) – le linker bug 30612 faisait que les derniers octets de
PT_GNU_RELROpartageaient une page modifiable sur les systèmes à pages de 64 KiB ; les binutils actuels alignent RELRO surmax-page-size, comblant cette “RELRO gap”.
References
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


