Relro
Reading time: 6 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking'i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Relro
RELRO, Relocation Read-Only anlamına gelir ve bir bağlayıcı (ld
) tarafından uygulanan bir önlemdir; bu, ELF'nin veri segmentlerinin bir alt kümesini tüm yeniden konumlandırmalar uygulandıktan sonra yalnızca okunur hale getirir. Amaç, bir saldırganın program yürütülmesi sırasında dereferans edilen GOT (Global Offset Table) veya diğer yeniden konumlandırma ile ilgili tabloların girişlerini yazmasını engellemektir (örneğin, __fini_array
).
Modern bağlayıcılar, RELRO'yu GOT'u (ve birkaç diğer bölümü) .bss'den önce yerleştirerek ve – en önemlisi – dinamik yükleyici yeniden konumlandırmaları uyguladıktan hemen sonra R–X
olarak yeniden haritalanan özel bir PT_GNU_RELRO
segmenti oluşturarak uygular. Sonuç olarak, .bss'deki tipik tampon taşmaları artık GOT'a ulaşamaz ve keyfi yazma ilkelere, RELRO korumalı bir sayfanın içinde bulunan işlev işaretçilerini yazmak için kullanılamaz.
Bağlayıcı tarafından yayımlanabilecek iki seviye koruma vardır:
Kısmi RELRO
-Wl,-z,relro
(veyald
'yi doğrudan çağırırken sadece-z relro
) bayrağı ile üretilir.- Sadece GOT'un non-PLT kısmı (veri yeniden konumlandırmaları için kullanılan kısım) yalnızca okunur segmente konur. Çalışma zamanında değiştirilmesi gereken bölümler – en önemlisi lazy binding'i destekleyen .got.plt – yazılabilir kalır.
- Bu nedenle, bir keyfi yazma ilkesinin hala bir PLT girişini yazması (veya ret2dlresolve gerçekleştirmesi) mümkündür.
- Performans etkisi önemsizdir ve bu nedenle neredeyse her dağıtım yıllardır en az Kısmi RELRO ile paketler gönderiyor (2016 itibarıyla GCC/Binutils varsayılanıdır).
Tam RELRO
- Her iki bayrak ile üretilir:
-Wl,-z,relro,-z,now
(diğer adıyla-z relro -z now
).-z now
, dinamik yükleyicinin tüm sembolleri önceden çözmesini (istekli bağlama) zorlar, böylece .got.plt bir daha yazılmak zorunda kalmaz ve güvenli bir şekilde yalnızca okunur olarak haritalanabilir. - Tüm GOT, .got.plt, .fini_array, .init_array, .preinit_array ve birkaç ek iç glibc tablosu yalnızca okunur bir
PT_GNU_RELRO
segmentinin içine yerleştirilir. - Ölçülebilir bir başlangıç yükü ekler (tüm dinamik yeniden konumlandırmalar başlatıldığında işlenir) ancak çalışma zamanı yükü yoktur.
2023'ten itibaren birkaç ana akım dağıtım, sistem araç zincirini (ve çoğu paketi) varsayılan olarak Tam RELRO ile derlemeye geçti – örneğin, Debian 12 “bookworm” (dpkg-buildflags 13.0.0) ve Fedora 35+. Bu nedenle, bir pentester olarak her GOT girişinin yalnızca okunur olduğu ikili dosyalarla karşılaşmayı beklemelisiniz.
Bir ikilinin RELRO durumunu nasıl kontrol edersiniz
$ checksec --file ./vuln
[*] '/tmp/vuln'
Arch: amd64-64-little
RELRO: Full
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
checksec
(bir parçası pwntools ve birçok dağıtım) ELF
başlıklarını ayrıştırır ve koruma seviyesini yazdırır. Eğer checksec
kullanamıyorsanız, readelf
'e güvenin:
# 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
Eğer ikili çalışıyorsa (örneğin, bir set-uid root yardımcı programı), yürütülebilir dosyayı /proc/$PID/exe
üzerinden inceleyebilirsiniz:
readelf -l /proc/$(pgrep helper)/exe | grep GNU_RELRO
Kendi kodunuzu derlerken RELRO'yu etkinleştirme
# 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
hem GCC/clang ( -Wl,
sonrasında geçildiğinde) hem de doğrudan ld için çalışır. CMake 3.18+ kullanırken, yerleşik ön ayar ile Tam RELRO talep edebilirsiniz:
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")
Bypass Teknikleri
RELRO seviyesi | Tipik ilkel | Olası istismar teknikleri |
---|---|---|
Yok / Kısmi | Keyfi yazma | 1. .got.plt girişini üzerine yaz ve yürütmeyi yönlendir. 2. ret2dlresolve – yazılabilir bir segmentte sahte Elf64_Rela & Elf64_Sym oluştur ve _dl_runtime_resolve çağrısı yap.3. .fini_array / atexit() listesinde fonksiyon işaretçilerini üzerine yaz. |
Tam | GOT salt okunur | 1. diğer yazılabilir kod işaretçilerini (C++ vtables, __malloc_hook < glibc 2.34, __free_hook , özel .data bölümlerindeki geri çağırmalar, JIT sayfaları) ara.2. libc'yi sızdırmak ve SROP/ROP into libc gerçekleştirmek için göreceli okuma ilkelerini kötüye kullan. 3. DT_RPATH/ LD_PRELOAD aracılığıyla bir sahte paylaşılan nesne enjekte et (eğer ortam saldırganın kontrolündeyse) veya ld_audit .4. GOT'a dokunmadan kontrol akışını saptırmak için format-string veya kısmi işaretçi üzerine yazma istismar et. |
💡 Tam RELRO ile bile, yüklenen paylaşılan kütüphanelerin GOT'u (örneğin libc'nin kendisi) yalnızca Kısmi RELRO'dur çünkü bu nesneler yükleyici yerleştirmeleri uyguladığında zaten haritalanmıştır. Eğer başka bir paylaşılan nesnenin sayfalarını hedef alabilen bir keyfi yazma ilkesine sahip olursanız, libc'nin GOT girişlerini veya
__rtld_global
yığınını üzerine yazarak yürütmeyi yönlendirebilirsiniz; bu, modern CTF zorluklarında düzenli olarak istismar edilen bir tekniktir.
Gerçek dünya bypass örneği (2024 CTF – pwn.college “aydınlanmış”)
Zorluk Tam RELRO ile gönderildi. İstismar, bir yığın parçasının boyutunu bozmak için bir off-by-one kullandı, tcache poisoning
ile libc'yi sızdırdı ve sonunda __free_hook
'u (RELRO segmentinin dışında) bir gadget ile kod yürütmek için üzerine yazdı. Hiçbir GOT yazma gerekmiyordu.
Son araştırmalar & güvenlik açıkları (2022-2025)
- glibc 2.40
__malloc_hook
/__free_hook
'u kullanımdan kaldırıyor (2025) – Bu sembolleri kötüye kullanan modern yığın istismarlarının çoğu artıkrtld_global._dl_load_jump
veya C++ istisna tabloları gibi alternatif vektörlere geçmek zorundadır. Kancalar RELRO'nun dışındadır, bu nedenle kaldırılmaları Tam RELRO bypass'larını zorlaştırır. - Binutils 2.41 “max-page-size” düzeltmesi (2024) – Bir hata, RELRO segmentinin son birkaç baytının bazı ARM64 derlemelerinde yazılabilir verilerle aynı sayfayı paylaşmasına izin verdi ve
mprotect
'ten sonra yazılabilecek küçük bir RELRO boşluğu bıraktı. Üst akım artıkPT_GNU_RELRO
'yu sayfa sınırlarına hizalıyor ve bu kenar durumunu ortadan kaldırıyor.
Referanslar
- Binutils belgeleri –
-z relro
,-z now
vePT_GNU_RELRO
- “RELRO – Tam, Kısmi ve Bypass Teknikleri” – blog yazısı @ wolfslittlered 2023
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking'i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.