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:
Aen ASCII: 655en ASCII: 53aen 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:
local_cse inicializa a 0Mientras
local_csea menor o igual que 0x1d (29 decimal), el programa sigue.
Se pide el char al usuario, si no se lee correctamente, se sale del programa. Si se lee correctamente, quedará guardado en
local_d
Se inicializa el seed con nuestro char (Guardado en
local_d), luego se asignaiVar1a un número aleatorio (el primero que se genera conlocal_dcomo seed).
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 =
checkOffset =
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 Endian, 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