githubEditar

HackTheBox - FlagCasino

CHALLENGE DESCRIPTION

The team stumbles into a long-abandoned casino. As you enter, the lights and music whir to life, and a staff of robots begin moving around and offering games, while skeletons of prewar patrons are slumped at slot machines. A robotic dealer waves you over and promises great wealth if you can win - can you beat the house and gather funds for the mission?

Archivos iniciales:

  • casino: ELF 64-bit.

Análisis inicial

Tras ejecutar el programa una vez, vemos lo siguiente:

./casino
[ ** WELCOME TO ROBO CASINO **]
     ,     ,
    (\____/)
     (_oo_)
       (O)
     __||__    \)
  []/______\[] /
  / \______/ \/
 /    /__\
(\   /____\
---------------------
[*** PLEASE PLACE YOUR BETS ***]
> 3
[ * INCORRECT * ]
[ *** ACTIVATING SECURITY SYSTEM - PLEASE VACATE *** ]

Al parecer hay que introducir algo, pero no sabemos qué es. Miramos qué hace con ltrace y strace:

Aquí podemos ver que, al introducir algo (en este caso ABCD) se llama a srand() y se inicializa un seed, pero todavía no sabemos con qué, probamos con más inputs:

  • Con "5":

  • Con "ab":

Esto ya nos da una idea de lo que se hace. Vemos que se está tomando el primer carácter introducido y se está usando su número en ASCII para inicializar el seed:

  • A en ASCII: 65

  • 5 en ASCII: 53

  • a en ASCII: 97

Decompilando el binario

Todavía no sabemos qué hace el programa, más allá de lo visto, así que lo descompilamos con Ghidra, quedando algo así:

De aquí vamos viendo que pasan varias cosas cuando inicia el programa:

  1. local_c se inicializa a 0

  2. Mientras local_c sea menor o igual que 0x1d (29 decimal), el programa sigue.

  1. Se pide el char al usuario, si no se lee correctamente, se sale del programa. Si se lee correctamente, quedará guardado en local_d

  1. Se inicializa el seed con nuestro char (Guardado en local_d), luego se asigna iVar1 a un número aleatorio (el primero que se genera con local_d como seed).

  1. Se compara el número aleatorio (iVar1) con un número entero guardado en (check + (long)(int)local_c * 4). Aunque a simple vista parece extraño, esto no es más que un array:

  • Dirección base = check

  • Offset = local_c (se multiplica por 4 porque un int tiene 4 bytes) En definitiva, sería algo como:

Y finalmente, si iVar1 coincide con check[local_c], se suma 1 a local_c, se pide otro carácter, se inicializa de nuevo el seed y se compara con el siguiente valor del array check[]:

De forma gráfica, quedaría algo así:

Código final decompilado

Cambiando el nombre de las variables, reorganizando todo e ignorando algunas cosas no relevantes para entender mejor el código, quedaría algo así:

Fuerza Bruta

Sabiendo lo que hace el código, vemos que necesitamos encontrar 30 caracteres seguidos (que estén en la codificación ASCII) tales que el primer valor aleatorio producido al inicializar el seed con cada uno de ellos corresponda con los números guardados en el array. Como el array contiene datos estáticos, podemos verlos en memoria:

El único inconveniente de estos datos es que están en Little Endianarrow-up-right, estándar en Intel x86_64, por lo que habrá que reordenar los bytes, que quedarán 0x244b28be, 0xaf77805, 0x110dfc17, 0x7afc3a1... Ahora buscamos un set de caracteres tal que el primero de ellos, usado como seed, genere un valor aleatorio 0x244b28be, el segundo 0xaf77805, y así hasta los 30 valores.

Hacemos un programa en C++ que haga esto:

Al ejecutarlo:

Última actualización