Mission Brief: Your team has breached a derelict gambling hall from the pre-war era. Amidst the dust and skeletal remains of former patrons, the automated staff has reactivated. A robotic dealer offers you a game of chance. The prize? Funding for the mission. The catch? The house always wins unless you can reverse engineer the odds.
Objective: Analyze the provided binary, identify the flaw in its random number generation, and extract the flag.
Phase 1: Initial Reconnaissance
Before diving into the assembly, we observe the binary’s behavior in a controlled environment. We run the executable to gauge the user interaction.
$ ./robo_casino
[ ** WELCOME TO ROBO CASINO **]
, ,
(\____/)
(_oo_)
(O)
__||__ \)
[]/______\[] /
/ \______/ \/
/ /__\
(\ /____\
---------------------
[*** PLEASE PLACE YOUR BETS ***]
> 5
[ * INCORRECT * ]
[ *** ACTIVATING SECURITY SYSTEM - PLEASE VACATE *** ]
Observation: The program prompts for input (bets). Upon entering a value (5), it immediately fails and terminates. This suggests a classic password check or value comparison logic hidden beneath the casino theme.
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)
0 comments