The following write-up details a solution to one of the Nuit Du Hack qualification phase challenges.
Nuit Du Hack is a french security event which takes place for its 15th edition in Disneyland Paris on the 24th and 25th of June, 2017.
Two contests take place during this event, a public and a private one.
The private contest is reserved for the 10 winning teams of the qualifications phase, which took place on the 1st of April, 2017. Four members of Devoteam were among the competitors.
The contest featured several types of challenges, from traditional web/exploit/forensics to steganography.
The Slumdog Millionaire challenge
The challenge, categorized as Web, is described as follows :
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 !
We have then access to an online casino web page http://slumdogmillionaire.quals.nuitduhack.com/ and the source code of its algorithm.
The source code does not cover the whole application and is a simple snippet from their internal logic, using some internal libraries.
As shown in the screenshot below, the application consist of a simple input field and returns some information. The expected input follows the pattern 01-23-45-67-89-01-23-45-67-89 with all 10 numbers being random.
If the submitted pattern is incorrect, the winning combination is displayed and regenerated.
A history table with the 10 last winning combinations is also showed at the bottom of the page.
While the application is tagged as web the vulnerability was not a typical web vulnerability but more a logic flaw in their gambling algorithm.
The focus has been put on the logic source code :
It can be noticed in this source that the code is using Python Random library to generate the winning combination.
The logic seems OK at first sight : generation of the winning pattern at each try and a maximum number of tries. Otherwise, there is a typical weakness in the random numbers generation : the seed choice.
In this case the seed is based on the process’ identifier (PID) and used to generate the 10 random numbers. A PID is an integer which ranges from 0 to 32768 (usual default value, which is also the 32 bits systems’ maximum).
A seed is used to initialize random numbers generators. Using Python’s randint function with the same seed will generate the same outputs.
This is where the vulnerability lies, since there is a feedback on the last winning combination, it is possible to pre-calculate the 32768 first generated combinations and guess the PID by comparing the web server first answer with this list.
We reuse the generate_combination() function and process the first two values : one to use in order to guess the PID and the second one to validate the challenge.
We have now a list looking like the following extract :
We submit a bad value to the input and get 22-74-39-76-48-37-79-28-13-61 first winning combination.
Cross checking with our list, it can be deduced that the PID is 7729.
We then submit second value to the page and… Challenge solved !
Thanks to NDH staff for organization & challenges.