HackTheBox Flag Casino | Reverse Engineering CTF Writeups

Motasem Hamdan
3 min readOct 11, 2024

--

Introduction

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?

Walkthrough

Analysis: In this challenge, we were provided with a binary file that contains the flag, and our goal is to find a way to extract it. Let’s start by running the binary to gather some basic information about it.

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

We can use Ghidra to open the binary and start reverse engineering our way to better understand how the binary works.
After displaying the banner, the binary runs a loop from 0 to 0x1c. During each iteration, srand() is called using the character we provide as input. Then, rand() is called and the result is compared to a corresponding integer from the check array. If the result matches, we receive a success message and move on to the next iteration.

If all 0x1c entries match correctly, we complete the process successfully.

int32_t main(int32_t argc, char** argv, char** envp)
puts(str: "[ ** WELCOME TO ROBO CASINO **]")
puts(str: " , ,\n (\____/)\n (_oo_)\n (O)\n __…")
puts(str: "[*** PLEASE PLACE YOUR BETS ***]")
int32_t i = 0
while (true) {
if (i u> 0x1c) {
puts(str: "[ ** HOUSE BALANCE $0 - PLEASE COME BACK LATER ** ]")
return 0
}
printf(format: "> ")
char inp
if (__isoc99_scanf(format: " %c", &inp) != 1) {
exit(status: 0xffffffff)
noreturn
}
srand(x: sx.d(inp))
if (rand() != check[sx.q(i)]) {
break
}
puts(str: "[ * CORRECT *]")
i = i + 1
}
puts(str: "[ * INCORRECT * ]")
puts(str: "[ *** ACTIVATING SECURITY SYSTEM - PLEASE VACATE *** ]")
exit(status: 0xfffffffe)

rand() is a predictable random number generator—calling srand(x) followed by rand() will always produce the same result for a given seed. So, we can script a solution to uncover the mapping.

By using the ctypes library in Python, we can easily call C functions like srand() and rand() directly from our Python code to assist in this process.

Next, we’ll use the pwntools library to interact with the binary. This will allow us to open the binary and extract each target integer that we need to compare against during the process. By automating this with pwntools, we can streamline the extraction and verification of the necessary values.

In the for loop, to index into the check array, multiply the current index by 4 to account for the size of each 32-bit integer. Then, use e.u32() (from pwntools) to extract each 32-bit integer from the binary data. This allows us to read the correct values from the check array during each iteration.

Full solution python script:

import ctypes
libc = ctypes.CDLL('libc.so.6')mapping = {}
for i in range(255):
libc.srand(i)
mapping[libc.rand()] = chr(i)
flag = ""
from pwn import *
casino = ELF("./casino", checksec=False)
for b in range(29):
val = casino.u32(casino.sym["check"] + b * 4)
flag += mapping[val]
print(flag)

You can also watch:

--

--

Motasem Hamdan

Motasem Hamdan is a content creator and swimmer who creates cyber security training videos and articles. https://www.youtube.com/@MotasemHamdan