Hack.lu 2015 CTF Write-Up: GuessTheNumber
The teacher of your programming class gave you a tiny little task: just write a guess-my-number script that beats his script. He also gave you some hard facts:
- he uses some LCG with standard glibc LCG parameters
- the LCG is seeded with server time using number format YmdHMS (python strftime syntax)
- numbers are from 0 up to (including) 99
- numbers should be sent as ascii string
You can find the service on school.fluxfingers.net:1523
Challenge Overview
The service is a text socket application with a self-explaining banner on connection:
Straight approach
As shown in other teams’ write-ups on CTFtime, the intended way to solve this challenge is to use the LCG random number generator in glibc with standard parameters and the seed given by the application itself. The only caveat is that the server generates 100 numbers, takes modulo 100 and checks in reverse order.
Using the server as an oracle
An alternative approach is to use the server as an oracle in order to obtain the correct sequence. As shown before in the example, in case of error, the server returns the correct answer. On every connection the server seeds the LCG with its actual timestamp so the leakage is limited to the first number of the sequence.
Nevertheless, as shown in the description, the LCG is seeded with server time using number format YmdHMS, so the seed gets updated once per second. Well, in a whole second we can make a lot of connections to the server right? ;) The trick is to create 101 connections to the server within one second: we need 100 connections to leak the 100 right answers and one more to get the flag!
We coded a simple script which spawn 101 processes communicating with the main thread through pipes.
Once we have established 101 connections to the server within the very same second we are done. Now we just need to retrieve the correct sequence, send it back with the 101th process and read the flag!
The first process is fed with number 1337 which, being greater than 99, is clearly wrong. So the server answers back with the first correct guess which, in turn, is sent to all the remaining processes to be transmitted. By feeding the second process with the same wrong value, we can now get the second correct guess in the sequence. Instead, the last process is fed with the last correct guess, finishing the challenge.
Eventually, the flag is printed as expected: