The PiggyBank corporation has dediced to open source its new gambling application, SlumdogMillionaire! Since then, it has become a world phenomenon. They are particularly proud of their new algorithm and hope to prove their game is fair by giving "Carte Blanche" for anyone to audit their code!
SlumdogMillionaire, part of source code
#!/usr/bin/python2.7
import random
import config
import utils
random.seed(utils.get_pid())
ngames = 0
def generate_combination():
numbers = ""
for _ in range(10):
rand_num = random.randint(0, 99)
if rand_num < 10:
numbers += "0"
numbers += str(rand_num)
if _ != 9:
numbers += "-"
return numbers
def reset_jackpot():
random.seed(utils.get_pid())
utils.set_jackpot(0)
ngames = 0
def draw(user_guess):
ngames += 1
if ngames > config.MAX_TRIES:
reset_jackpot()
winning_combination = generate_combination()
if winning_combination == user_guess:
utils.win()
reset_jackpot()
Solution
So, how to guess the next winning combination?
Looking at the code(python2.7), the combination is a random sentence based on a custom seed.
#!/usr/bin/python2.7
...
random.seed(utils.get_pid())
...
The seed is some linux pid number, and remains the same for your session/IP until you hit the config.MAX_TRIES==10000
. We don't have access to config
but you can discover this by bruteforce, forcing the jackpot reset.
Well, if you guess the seed, you are able to generate all the next winning numbers for current session.
Under Linux, the maximum process ID is given by the pseudo-file
/proc/sys/kernel/pid_max
There's only 32768
possible seeds! But, which pid my session is using?
- Go to website and get some of the latest winning numbers. If you no longer have access to the first 10 numbers, bruteforce it until hit 10k max tries and reset the session.
- Pick the first winning number and check which seed matches on a
python2.7
loop in range0..32768
. - Using the matched seed, generate the next winning numbers.
- Win.
Final code
#!/usr/bin/python2.7
import random
user_guess = "39-67-24-84-62-02-71-37-03-67" #current session first winning number
for i in range(0,32769):
def generate_combination():
numbers = ""
for _ in range(10):
rand_num = random.randint(0, 99)
if rand_num < 10:
numbers += "0"
numbers += str(rand_num)
if _ != 9:
numbers += "-"
return numbers
random.seed(i)
winning_combination = generate_combination()
if winning_combination == user_guess:
print user_guess
for _ in range(0,10):
print generate_combination()
Alternative solution
If you are fast enough, running a multi-thread script you are able to get the last winning combination and replay before the server fully processes the last request.
It did not work for me because the server was all time overloaded, but I think it's possible.