From b3545eb964b94e1e3f13d4ed9c68033fae2b586a Mon Sep 17 00:00:00 2001 From: Translator Date: Thu, 17 Jul 2025 00:13:20 +0000 Subject: [PATCH] Translated ['src/binary-exploitation/common-binary-protections-and-bypas --- .../relro.md | 92 ++++++++++++++++--- 1 file changed, 79 insertions(+), 13 deletions(-) diff --git a/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md b/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md index 3e2d316dc..3072d7a40 100644 --- a/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md +++ b/src/binary-exploitation/common-binary-protections-and-bypasses/relro.md @@ -4,30 +4,96 @@ ## Relro -**RELRO** означає **Relocation Read-Only**, і це функція безпеки, що використовується в бінарних файлах для зменшення ризиків, пов'язаних з переписуванням **GOT (Global Offset Table)**. Існує два типи захисту **RELRO**: (1) **Частковий RELRO** і (2) **Повний RELRO**. Обидва вони реорганізовують **GOT** і **BSS** з ELF файлів, але з різними результатами та наслідками. Конкретно, вони розміщують секцію **GOT** _перед_ **BSS**. Тобто, **GOT** знаходиться за нижчими адресами, ніж **BSS**, що унеможливлює переписування записів **GOT** шляхом переповнення змінних у **BSS** (пам'ять записується з нижчих адрес до вищих). +**RELRO** означає **Relocation Read-Only** і є заходом, реалізованим компоновником (`ld`), який перетворює підмножину сегментів даних ELF на **тільки для читання після застосування всіх перенесень**. Мета полягає в тому, щоб зупинити зловмисника від перезапису записів у **GOT (Global Offset Table)** або інших таблицях, пов'язаних з перенесеннями, які розіменовуються під час виконання програми (наприклад, `__fini_array`). -Давайте розглянемо концепцію в її двох різних типах для ясності. +Сучасні компоновники реалізують RELRO, **переставляючи** **GOT** (і кілька інших секцій) так, щоб вони знаходилися **перед** **.bss** і – що найважливіше – створюючи спеціальний сегмент `PT_GNU_RELRO`, який перенаправляється `R–X` відразу після того, як динамічний завантажувач закінчує застосування перенесень. Внаслідок цього типові переповнення буфера в **.bss** більше не можуть досягти GOT, і примітиви довільного запису не можуть бути використані для перезапису вказівників функцій, які знаходяться всередині захищеної сторінки RELRO. -### **Частковий RELRO** +Існує **два рівні** захисту, які може випустити компоновник: -**Частковий RELRO** використовує простіший підхід для підвищення безпеки без значного впливу на продуктивність бінарного файлу. Частковий RELRO робить **.got тільки для читання (не-PLT частина секції GOT)**. Майте на увазі, що решта секції (як .got.plt) все ще може бути записуваною і, отже, підлягає атакам. Це **не запобігає зловживанню GOT** **з вразливостей довільного запису**. +### Partial RELRO -Примітка: За замовчуванням, GCC компілює бінарні файли з Частковим RELRO. +* Виробляється з прапором `-Wl,-z,relro` (або просто `-z relro`, коли викликається `ld` безпосередньо). +* Тільки **не-PLT** частина **GOT** (частина, що використовується для перенесень даних) поміщається в сегмент тільки для читання. Секції, які потрібно змінювати під час виконання – найважливіше **.got.plt**, що підтримує **lazy binding** – залишаються записуваними. +* Через це примітив **довільного запису** все ще може перенаправити потік виконання, перезаписуючи запис PLT (або виконуючи **ret2dlresolve**). +* Вплив на продуктивність незначний, тому **майже кожен дистрибутив протягом багатьох років постачає пакунки з принаймні Partial RELRO (це стандарт GCC/Binutils з 2016 року)**. -### **Повний RELRO** +### Full RELRO -**Повний RELRO** підвищує захист, **роблячи всю GOT (як .got, так і .got.plt) та секцію .fini_array** повністю **тільки для читання.** Як тільки бінарний файл запускається, всі адреси функцій вирішуються і завантажуються в GOT, після чого GOT позначається як тільки для читання, ефективно запобігаючи будь-яким змінам під час виконання. +* Виробляється з **обома** прапорами `-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`. +* Додає вимірюване навантаження при запуску (всі динамічні перенесення обробляються під час запуску), але **немає накладних витрат під час виконання**. -Однак, компроміс з Повним RELRO полягає в продуктивності та часі запуску. Оскільки потрібно вирішити всі динамічні символи під час запуску перед тим, як позначити GOT як тільки для читання, **бінарні файли з увімкненим Повним RELRO можуть мати довший час завантаження**. Це додаткове навантаження під час запуску є причиною, чому Повний RELRO не увімкнено за замовчуванням у всіх бінарних файлах. +З 2023 року кілька основних дистрибутивів перейшли на компіляцію **системного інструментального набору** (і більшості пакунків) з **Full RELRO за замовчуванням** – наприклад, **Debian 12 “bookworm” (dpkg-buildflags 13.0.0)** та **Fedora 35+**. Як пентестер, ви повинні очікувати зустріти бінарні файли, де **кожен запис GOT є тільки для читання**. -Можна перевірити, чи **увімкнено** Повний RELRO у бінарному файлі за допомогою: +--- + +## Як перевірити статус RELRO бінарного файлу ```bash -readelf -l /proc/ID_PROC/exe | grep BIND_NOW +$ checksec --file ./vuln +[*] '/tmp/vuln' +Arch: amd64-64-little +RELRO: Full +Stack: Canary found +NX: NX enabled +PIE: No PIE (0x400000) +``` +`checksec` (частина [pwntools](https://github.com/pwncollege/pwntools) та багатьох дистрибутивів) аналізує заголовки `ELF` і виводить рівень захисту. Якщо ви не можете використовувати `checksec`, покладайтеся на `readelf`: +```bash +# 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 ``` -## Bypass -Якщо увімкнено Full RELRO, єдиний спосіб обійти його - знайти інший спосіб, який не потребує запису в таблицю GOT для отримання довільного виконання. +```bash +# 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`**: +```bash +readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO +``` +--- -Зверніть увагу, що **GOT LIBC зазвичай є Partial RELRO**, тому його можна змінити за допомогою довільного запису. Більше інформації в [Targetting libc GOT entries](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)**.** +## Увімкнення RELRO під час компіляції власного коду +```bash +# 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+**, ви можете запитати повний RELRO за допомогою вбудованого пресету: +```cmake +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`, зворотні виклики в кастомних секціях `.data`, JIT-сторінки).
2. Зловживати *відносними читаннями* для витоку libc та виконання **SROP/ROP у libc**.
3. Впровадити зловмисний спільний об'єкт через **DT_RPATH**/`LD_PRELOAD` (якщо середовище контролюється атакуючим) або **`ld_audit`**.
4. Використати **форматний рядок** або частковий перезапис вказівника для зміни потоку управління без торкання 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) з одним гаджетом для отримання виконання коду. Запис у GOT не був потрібен. + +--- + +## Останні дослідження та вразливості (2022-2025) + +* **glibc 2.40 знецінює `__malloc_hook` / `__free_hook` (2025)** – Більшість сучасних експлуатацій купи, які зловживали цими символами, тепер повинні переходити на альтернативні вектори, такі як **`rtld_global._dl_load_jump`** або таблиці виключень C++. Оскільки гачки живуть **поза** RELRO, їх видалення ускладнює обходи Повного RELRO. +* **Виправлення “max-page-size” Binutils 2.41 (2024)** – Помилка дозволила останнім кільком байтам сегмента RELRO ділити сторінку з записуваними даними на деяких збірках ARM64, залишаючи маленький **RELRO-проміжок**, який можна було записати після `mprotect`. Тепер upstream вирівнює `PT_GNU_RELRO` до меж сторінок, усуваючи цей крайній випадок. + +--- + +## Посилання + +* Документація Binutils – *`-z relro`, `-z now` та `PT_GNU_RELRO`* +* *“RELRO – Повний, Частковий та Техніки обходу”* – допис у блозі @ wolfslittlered 2023 {{#include ../../banners/hacktricks-training.md}}