السلام عليكم ورحمة الله وبركاته
Today we are going to face an nice challenge called roulette here the challenge gives us a roulette that we need to get 13 37 times but how can we do this let’s examine the source code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
| from hashlib import sha256
import secrets
def get_color(number):
"""Determine roulette color for a given number"""
if number == 0:
return 'green'
return 'red' if number % 2 == 1 else 'black'
def main():
print("Welcome to Provably Fair Roulette!")
with open('flag', 'rt') as f:
FLAG = f.read()
streak_13 = 0
while True:
# Generate server seed and its hash
server_seed = sha256(bytes(secrets.randbits(17))).hexdigest()
server_seed_hash = sha256(server_seed.encode()).hexdigest()
print(f"Server seed hash (verify later): {server_seed_hash}")
# Get client seed
print("Enter your client seed (press enter to generate): ", end="")
client_seed = input().strip()
if not client_seed:
client_seed = secrets.token_bytes(8).hex()
print(f"Generated client seed: {client_seed}")
# Generate game hash
combined = f"{server_seed}:{client_seed}"
game_hash = sha256(combined.encode()).hexdigest()
hash_int = int(game_hash, 16)
# Calculate roulette result
roulette_number = hash_int % 37 # 0-36
roulette_color = get_color(roulette_number)
# Get user's bet
while True:
print("Place your bet (number 0-36 or color red/black/green): ", end="")
bet = input().strip().lower()
if bet in ['green', 'red', 'black']:
break
try:
num = int(bet)
if 0 <= num <= 36:
bet = str(num) # Standardize to string for comparison
break
print("Number must be between 0-36")
except ValueError:
print("Invalid bet. Enter number (0-36) or color (red/black/green)")
# Determine result
result_str = f"{roulette_number} ({roulette_color})"
print(f"\nThe wheel lands on: {result_str}")
# Check win conditions
win = False
if bet.isdigit():
win = int(bet) == roulette_number
else:
win = bet == roulette_color
if win:
print("Congratulations! You win! ")
if roulette_number == 13:
print("...and you got 13, double congratulations!")
streak_13 += 1
else:
print("But it's not 13, no streak for you")
streak_13 = 0
else:
print("Sorry, you lose!")
streak_13 = 0
# Verification information
print()
print("Verification Details:")
print(f"Server seed: {server_seed}")
print(f"Client seed: {client_seed}")
print(f"Combined string: {combined}")
print(f"Game hash: {game_hash}")
print(f"Calculated number: {roulette_number}")
print(f"Resulting color: {roulette_color}")
if streak_13 == 37:
print("How? How is it possible? What was the chance?! "
f"Anyway, here's your flag, congratulations... {FLAG}")
exit()
if __name__ == "__main__":
main()
|
here if you notice the code used “randbits(17)” here lies the weakness that a random 17 bits is 131072 possible numbers and this is easy to brute force so we can after receiving the server hash we can calculate the the server hash here we can advance to next step.
Here how is the roulette number generated ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| print("Enter your client seed (press enter to generate): ", end="")
client_seed = input().strip()
if not client_seed:
client_seed = secrets.token_bytes(8).hex()
print(f"Generated client seed: {client_seed}")
# Generate game hash
combined = f"{server_seed}:{client_seed}"
game_hash = sha256(combined.encode()).hexdigest()
hash_int = int(game_hash, 16)
# Calculate roulette result
roulette_number = hash_int % 37 # 0-36
roulette_color = get_color(roulette_number)
|
So here either the client seed is an input from the user or generated from the server so here to get 13 we need to calculate a client seed.
Here is a code snippet the calculates the server seed and client seed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| def compute_server_seed(server_seed_hash):
for i in range(131072):
candidate = b'\x00' * i
server_seed = hashlib.sha256(candidate).hexdigest()
hashed = hashlib.sha256(server_seed.encode()).hexdigest()
if hashed == server_seed_hash:
return server_seed
raise Exception("Server seed not found")
def find_client_seed_for_13(server_seed):
i = 0
while True:
client_seed = f"{i:08x}"
combined = f"{server_seed}:{client_seed}"
hash_int = int(hashlib.sha256(combined.encode()).hexdigest(), 16)
if hash_int % 37 == 13:
return client_seed
i += 1
|
and this is how you solve the challenge.
Hope you enjoyed the write-up.
