Tags: game misc prng perl
(For a more complete writeup: http://www.johnfren.ch/Black-Jack/)
The goal here is to find "a strategy" to win 27 blackjack games in a row.
You're given an encrypted rar file and a perl script which implements a blackjack game. If you win 27 games in a row (with at least one "blackjack" win), the game will decrypt the rar file, using the remaining cards in the deck to generate the key.
This is an obvious indication that the solution will only work for a given deck order, which means you must need to do something to the PRNG which is used to shuffle it. The PRNG is seeded with time(). There's also a mysterious bit of text in the game's instructions which give a date (Sept. 28 2016) and timezone (GMT) but no time, as well as references in the description to "a blackjack event" of some kind. This is a hint that the 27-game winning streak can be achieved by seeding the PRNG with a time which falls on Sept 28 2016 (in GMT).
After a few false starts, my solution to find the seed which lets you win was to change the PlayerMove subroutine to fork, and try both drawing a card (on one side of the fork) and standing (on the other). This is a super-simple way to just brute-force every possible game of blackjack for a given seed. if it's possible to reach the winning condition, one thread will make it and decrypt the flag; if not, all threads will die.
I set this up to run with every possible timestamp which falls within Sept 28 2016 GMT. It took about an hour before it decrypted the flag.
For details & code see the link.
I liked the fork approach, thought of it but didn't realize other possibilities would die soon.
Also, can you explain why we need to seed a time from Sept 28, 2016 ? If we are exploring all the possibilities then it should work for any given time ? or the order of shuffled deck matter ?
The password for the rar file is generated directly from the remaining cards in the deck, and the deck order is "random" and determined by the PRNG seed. So there must be one particular seed which will give the correct password. (Another possibility might be a very bad PRNG, but that was not the case here.)
So while it may be possible to find a different seed which allows you to meet the win condition, it won't give the correct password. And, I'm not sure how common those seeds are, but I'm guessing they happen a lot less often than once per day (1 in 86,400), so limiting the search to a 24-hour window narrows down the search space considerably.
The decrypted file which contains the flag also provides some insight into the inspiration for this challenge:
"ACCDFISA (a.k.a. Anti Child-Porn Ransomware)
One of the early ransomware that uses 3rd party tools for encryption; specifically, WinRAR.
In an attempt to recover encrypted files, several teams studied the malware. Rather than looking "brute forcing" WinRAR (which would take years), most concentrated on how the malware generates the password.
The malware uses a PseudoRandom Generator, with GetTickCount as its seed. (GetTickCount returns the number milliseconds that have elapsed since the system was started). While still billions of possible combinations, this is a lot manageable than the original 50+ characters used by the ransomware.
If the user (or some logs) could give the (1)time the machine was powered on and (2)the time the ransomware was executed (e.g. File CreateTime); the number of possible combinations would drop to less than 200 million. A few hours of password brute-forcing should be enough to succeed."