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.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Relro
RELRO stands for Relocation Read-Only and it is a mitigation implemented by the linker (ld) that turns a subset of the ELF’s data segments тільки для читання після застосування всіх релокацій. Метою є перешкодити атакуючому перезаписувати записи в GOT (Global Offset Table) або інших таблицях, пов’язаних з релокаціями, до яких звертаються під час виконання програми (наприклад, __fini_array).
Сучасні лінкери реалізують RELRO шляхом перепорядкування GOT (та кількох інших секцій), щоб вони розташовувалися перед .bss і — що найважливіше — шляхом створення виділеного сегмента PT_GNU_RELRO, який після того, як динамічний лоадер застосує релокації, відмаплюється як R–X. Внаслідок цього типові переповнення буфера в .bss більше не можуть дістатися до GOT і примітиви довільного запису не можуть бути використані для перезапису вказівників на функції, що містяться на сторінці, захищеній RELRO.
Існує дві рівні захисту, які може згенерувати лінкер:
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 релокацій даних) 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.
Як перевірити статус RELRO у 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
Якщо бінарний файл запущено (наприклад, 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 | Typical primitive | Possible exploitation techniques |
|---|---|---|
| Немає / Частковий | Arbitrary write | 1. Перезаписати .got.plt entry і перенаправити виконання. 2. ret2dlresolve – змайструвати фейкові Elf64_Rela & Elf64_Sym в записуваному сегменті і викликати _dl_runtime_resolve.3. Перезаписати вказівники функцій у .fini_array / списку atexit(). |
| Full | GOT is read-only | 1. Шукати інші записувані вказівники коду (C++ vtables, __malloc_hook < glibc 2.34, __free_hook, callbacks у кастомних .data секціях, JIT сторінки).2. Зловживати relative read примітивами щоб leaked libc і виконати SROP/ROP into libc. 3. Інжектити зловмисний shared object через DT_RPATH/ LD_PRELOAD (якщо середовище контролюється нападником) або ld_audit.4. Використати format-string або частковий перезапис вказівника, щоб відхилити контроль виконання без зміни GOT. |
💡 Навіть з Full RELRO GOT завантажених shared libraries (наприклад libc) є лише Partial RELRO, бо ці об’єкти вже відображені, коли завантажувач застосовує релокації. Якщо ви отримуєте примітив arbitrary write, який може цілитися в сторінки іншого shared object, ви все одно можете перенаправити виконання, перезаписавши записи GOT libc або стек
__rtld_global— техніка, яку регулярно експлуатують у сучасних CTF-змаганнях.
Приклад обходу в реальному світі (2024 CTF – pwn.college “enlightened”)
Завдання було з Full RELRO. Експлойт використав 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; сучасні експлойти мають цілитись в інші записувані вказівники. - GNU ld RELRO page‑alignment fix (binutils 2.39+/2.41) – помилка лінкера 30612 спричиняла, що останні байти
PT_GNU_RELROділили записувану сторінку на системах з 64 KiB сторінками; поточні binutils вирівнюють RELRO доmax-page-size, закриваючи цю “RELRO gap”.
References
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.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


