100 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Relro
{{#include ../../banners/hacktricks-training.md}}
## Relro
**RELRO** inamaanisha **Relocation Read-Only** na ni hatua ya kupunguza hatari iliyotekelezwa na linker (`ld`) ambayo inafanya sehemu fulani za data za ELF kuwa **read-only baada ya mabadiliko yote kutumika**. Lengo ni kuzuia mshambuliaji kuandika upya entries katika **GOT (Global Offset Table)** au meza nyingine zinazohusiana na mabadiliko ambazo zinarejelea wakati wa utekelezaji wa programu (mfano `__fini_array`).
Linker za kisasa zinafanya RELRO kwa **kupanga upya** **GOT** (na sehemu chache nyingine) ili ziwe **kabla** ya **.bss** na muhimu zaidi kwa kuunda sehemu maalum ya `PT_GNU_RELRO` ambayo inarudiwa `RX` mara tu loader ya dynamic inapoisha kutekeleza mabadiliko. Kwa hivyo, overflow za kawaida za buffer katika **.bss** haziwezi tena kufikia GOT na primitives za kuandika zisizo na mipaka cannot be used to overwrite function pointers ambazo ziko ndani ya ukurasa uliohifadhiwa na RELRO.
Kuna **viwango viwili** vya ulinzi ambavyo linker inaweza kutoa:
### Partial RELRO
* Inazalishwa kwa bendera `-Wl,-z,relro` (au tu `-z relro` unapoitisha `ld` moja kwa moja).
* Sehemu tu ya **non-PLT** ya **GOT** (sehemu inayotumika kwa mabadiliko ya data) inawekwa katika sehemu isiyo na maandiko. Sehemu ambazo zinahitaji kubadilishwa wakati wa utekelezaji muhimu zaidi **.got.plt** ambayo inasaidia **lazy binding** zinabaki kuwa na uwezo wa kuandikwa.
* Kwa sababu hiyo, primitive ya **kuandika bila mipaka** bado inaweza kuelekeza mtiririko wa utekelezaji kwa kuandika upya PLT entry (au kwa kufanya **ret2dlresolve**).
* Athari za utendaji ni ndogo na kwa hivyo **karibu kila usambazaji umekuwa ukisafirisha pakiti zikiwa na angalau Partial RELRO kwa miaka (ni chaguo la msingi la GCC/Binutils tangu 2016)**.
### Full RELRO
* Inazalishwa kwa **bendera zote** `-Wl,-z,relro,-z,now` (pia inajulikana kama `-z relro -z now`). `-z now` inalazimisha loader ya dynamic kutatua **mifano yote** mapema (eager binding) ili **.got.plt** isihitaji kuandikwa tena na inaweza kuandikwa kwa usalama kama read-only.
* **GOT** nzima, **.got.plt**, **.fini_array**, **.init_array**, **.preinit_array** na meza chache za ndani za glibc zinaishia ndani ya sehemu isiyo na maandiko ya `PT_GNU_RELRO`.
* Inaleta ongezeko la gharama za kuanzisha zinazoweza kupimwa (mabadiliko yote ya dynamic yanashughulikiwa wakati wa uzinduzi) lakini **hakuna gharama za wakati wa utekelezaji**.
Tangu mwaka 2023 usambazaji kadhaa maarufu umepita katika kuunda **system tool-chain** (na pakiti nyingi) kwa **Full RELRO kama chaguo la msingi** mfano **Debian 12 “bookworm” (dpkg-buildflags 13.0.0)** na **Fedora 35+**. Kama pentester unapaswa hivyo kutarajia kukutana na binaries ambapo **kila GOT entry ni read-only**.
---
## Jinsi ya Kuangalia hali ya RELRO ya binary
```bash
$ checksec --file ./vuln
[*] '/tmp/vuln'
Arch: amd64-64-little
RELRO: Full
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
```
`checksec` (sehemu ya [pwntools](https://github.com/pwncollege/pwntools) na usambazaji mwingi) inachambua vichwa vya `ELF` na kuchapisha kiwango cha ulinzi. Ikiwa huwezi kutumia `checksec`, tegemea `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
```
```bash
# Full RELRO → PT_GNU_RELRO *and* the DF_BIND_NOW flag
$ readelf -d ./vuln | grep BIND_NOW
0x0000000000000010 (FLAGS) FLAGS: BIND_NOW
```
Ikiwa binary inafanya kazi (kwa mfano, msaidizi wa set-uid root), bado unaweza kuchunguza executable **via `/proc/$PID/exe`**:
```bash
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
```
---
## Kuwezesha RELRO unapokuwa unakusanya msimbo wako mwenyewe
```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` inafanya kazi kwa **GCC/clang** (iliyopita baada ya `-Wl,`) na **ld** moja kwa moja. Wakati wa kutumia **CMake 3.18+** unaweza kuomba Full RELRO kwa preset iliyojengwa ndani:
```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")
```
---
## Mbinu za Kuepuka
| Kiwango cha RELRO | Kawaida primitive | Mbinu zinazowezekana za unyakuzi |
|-------------------|-------------------|----------------------------------|
| Hakuna / Sehemu | Kuandika bila mpangilio | 1. Badilisha **.got.plt** kuingia na pivot execution.<br>2. **ret2dlresolve** tengeneza `Elf64_Rela` & `Elf64_Sym` bandia katika sehemu inayoweza kuandikwa na kuita `_dl_runtime_resolve`.<br>3. Badilisha viashiria vya kazi katika orodha ya **.fini_array** / **atexit()**. |
| Kamili | GOT ni ya kusoma tu | 1. Tafuta **viashiria vingine vya kazi vinavyoweza kuandikwa** (C++ vtables, `__malloc_hook` < glibc 2.34, `__free_hook`, callbacks katika sehemu za desturi `.data`, kurasa za JIT).<br>2. Tumia *relative read* primitives kuvuja libc na kufanya **SROP/ROP ndani ya libc**.<br>3. Ingiza kitu cha pamoja kisicho halali kupitia **DT_RPATH**/`LD_PRELOAD` (ikiwa mazingira yanadhibitiwa na mshambuliaji) au **`ld_audit`**.<br>4. Fanya unyakuzi wa **format-string** au kuandika sehemu ya kiashiria ili kuelekeza mtiririko wa udhibiti bila kugusa GOT. |
> 💡 Hata na Full RELRO, **GOT ya maktaba za pamoja zilizoloadiwa (k.m. libc yenyewe)** ni **sehemu tu ya RELRO** kwa sababu vitu hivyo tayari vimepangwa wakati mzigo unapotumia uhamasishaji. Ikiwa unapata primitive ya **kuandika bila mpangilio** inayoweza kulenga kurasa za kitu kingine cha pamoja, bado unaweza pivot execution kwa kubadilisha entries za GOT za libc au stack ya `__rtld_global`, mbinu inayotumiwa mara kwa mara katika changamoto za kisasa za CTF.
### Mfano wa kuepuka wa kweli (2024 CTF *pwn.college “enlightened”*)
Changamoto ililetwa na Full RELRO. Unyakuzi ulitumia **off-by-one** kuharibu ukubwa wa kipande cha heap, ukavuja libc kwa `tcache poisoning`, na hatimaye ukabadili `__free_hook` (nje ya sehemu ya RELRO) kwa gadget moja ili kupata utekelezaji wa msimbo. Hakuna kuandika GOT kulihitajika.
---
## Utafiti wa hivi karibuni & udhaifu (2022-2025)
* **glibc 2.40 inafuta `__malloc_hook` / `__free_hook` (2025)** Unyakuzi wa kisasa wa heap ambao ulitumia alama hizi sasa lazima uhamie kwenye njia mbadala kama **`rtld_global._dl_load_jump`** au meza za kutengwa za C++. Kwa sababu hooks ziko **nje** ya RELRO, kuondolewa kwao kunafanya iwe vigumu zaidi kuepuka Full-RELRO.
* **Binutils 2.41 “max-page-size” fix (2024)** Kosa liliruhusu bytes chache za mwisho za sehemu ya RELRO kushiriki ukurasa na data inayoweza kuandikwa kwenye baadhi ya ujenzi wa ARM64, ikiacha **RELRO gap** ndogo ambayo inaweza kuandikwa baada ya `mprotect`. Upstream sasa inalinganisha `PT_GNU_RELRO` na mipaka ya ukurasa, ikiondoa hali hiyo ya ukingo.
---
## Marejeleo
* Hati za Binutils *`-z relro`, `-z now` na `PT_GNU_RELRO`*
* *“RELRO Kamili, Sehemu na Mbinu za Kuepuka”* chapisho la blog @ wolfslittlered 2023
{{#include ../../banners/hacktricks-training.md}}