Smashing Rabbit – Explotacion de un «random» value y XOR con una key (IV)

Muy buenas a todos, seguimos con esta serie de entradas relacionada con la explotación de binarios haciendo los retos de pwnable.kr. Esta entrada será más básica que las anteriores pero si aún así no quedan conceptos claros sobre reversing, podéis visitar entradas de iniciación: Diseccionando Binarios

Código fuente

En este reto principalmente el problema radica en la función rand() debido a que debería de haber inicializado con srand() la generación de números aleatorios pasandose por argumento la hora actual del sistema como seed. Si no se le pasa nada, usa como seed por defecto el valor 1. Entonces solo necesitamos resolver: key ^ rand() == 0xdeadbeef. Si usamos esta función en un script propio nos daremos cuenta que siempre genera el mismo valor:

Código fuente

Si ahora ejecutamos este pequeño binario veremos claramente que no genera un valor aleatorio.

Análisis estático del binario

Usaremos PEDA (Python Exploit Development Assistance for GDB) para realizar tanto el análisis estático como el dinámico, y su correspondiente explotación usando Bash. Instalación:

git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit

Tenemos que tener presente una idea general de la función main() y ver que llamada se realiza a otras funciones. Un ejemplo es la llamada a rand() donde el valor que retorna la función se almacena en EAX moviéndose a RBP-0X4. Seguidamente se realiza la llamada a la función scanf() para poder introducir el valor Key almacenandose con la instrucción MOV en el registro EAX. Por último hace un XOR del valor correspondiente a EAX y el valor «random» generado. Si conseguimos saber cual es ese valor, podremos obtener la Key necesaria que debemos introducir cuando llama al scanf().

  • random ^ 0xdeadbeef = key

Si el resultado de la instrucción comparación CMP es igual a cero y como la instrucción es JNE (JNZ), saltará si no es igual o salta si no es cero. El salto se efectúa si su eflag ZF esta desactivada, por tanto no saltará se ira por el camino «rojo» y llamará a la función system(), en concreto al binario cat para visualizar la flag o solución del reto.

Análisis dinámico

Hemos visto por encima el código en ensamblador para hacernos una idea de los hitos necesarios para resolver este reto:

  • Conocer el valor «random» generado por la función rand().
  • Una vez lo conozcamos, usaremos Bash para automatizar el proceso de explotación.

Introducimos un Breakpoint después de la llamada a la función rand()

disassemble main
break *main+18
run

En el registro RAX encontramos el valor devuelto por la función correspondiendo con el valor random que buscábamos.

Ejecutamos con el comando «ni», y vemos en el Stack como mueve MOV el valor de EAX (32 bits) a RBP-0x4. Colocamos otro breakpoint después de la llamada a la función scanf() y si queremos conocer información sobre nuestros registros y de nuestros breakpoints:

i r rbp
info registers
continue

Seguidamente tenemos que pasar a decimal el valor «Random» anterior y hacer el XOR que mencionamos al principio: 1804289383 ^ 0xdeadbeef = 3039230856

Introducimos cuando nos pide el valor y saltamos al segundo breakpoint +53. Si vemos en el registro RDI tenemos el valor Key que teníamos que encontrar a partir de obtener el valor «random». Y RAX el valor 0xdeadbeef que coincide con la comparación que hace con CMP. No saltará como vimos debido a que es un JNE  llamará a system() y obtenemos la flag.

root@naivenom:~/exploiting# expect -c 'spawn ssh random@pwnable.kr -p2222 "sync; sync; echo '3039230856' | ./random"; expect "assword:"; send "guest\r"; interact'

Demo

Entradas relacionadas

Pwnable challenges – Overwriting GOT (III)

Diseccionando binarios – 0x05 Crackmes Hardcoded