## Solution
### Quick Explanation
We exploit the pseudo random number generator used, which is the __Mersenne Twister__. We are then able to predict the next key used and get the flag.
### Full Solution
I have omitted the parts of `server.py` that are not really necessary.
```pythonimport random
class ThreadedServer(object):	def getKey(self, r):		return str(r.getrandbits(32)).rjust(16, '0')
	def listenToClient(self, client, address):		client_flag = self.flag		r = random.Random()		key = self.getKey(r)		client_flag = self.encrypt(key, client_flag)		while True:			try:				client.send('Please insert the decryption key:\n')				key_guess = client.recv(16)				if key_guess == key:					client.send('Correct! Your flag is: ' + self.decrypt(key, client_flag) + '\n')				else:					client.send('Wrong! The key was: ' + key + '\n')					client_flag = self.decrypt(key, client_flag)					key = self.getKey(r)					client_flag = self.encrypt(key, client_flag)```
We get two insights:
1. A single instance of `random.Random()` is used per connection2. Bits generated are eventually leaked to us
The [documentation](https://docs.python.org/2/library/random.html) of python's `random` module states:
> Python uses the Mersenne Twister as the core generator... However, being completely deterministic, it is not suitable for all purposes, and is completely unsuitable for cryptographic purposes.
We use eboda's [MTRecover](https://github.com/eboda/mersenne-twister-recover/blob/master/MTRecover.py) to do this, and we get the flag.
```Correct! Your flag is: noxCTF{41w4ys_us3_cryp70_s3cur3d_PRNGs}```
__For implementation see the link__