Rating:

# NoxCTF 2018: Plot Twist
***Category: Crypto***
>*Can you get the flag from the flawlessly written server?*
>
>*nc chal.noxale.com 5115*
## Solution
For this challenge, we are given the [source code](server.py) for the server.

After reading through the source code, we see we are put in an endless loop and the only way to get to the flag is if we can guess a 16 character key:
```python
if key_guess == key:
client.send('Correct! Your flag is: ' + self.decrypt(key, client_flag) + '\n')
```
the flag is encrypted using a random key, which is initially generated using:
```python
def getKey(self, r):
return str(r.getrandbits(32)).rjust(16, '0')
```
```python
client_flag = self.flag
r = random.Random()
key = self.getKey(r)
client_flag = self.encrypt(key, client_flag)
```
If we guess incorrectly, it will give us previous the key, generate a new key, and reencrypt the flag with the new key:
```python
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)
```
This got me thinking where the vulnerability would be. There weren't any parts in the code where we could intercept the ciphertext or the key before it changes. The only other option was being able to guess the key correctly. This led me to look at how the key is generated, so I pulled up the documentation for the `random` module. Specifically, I looked at the [.getrandbits()](https://docs.python.org/2/library/random.html#random.getrandbits) function since that was what was being used to generate the key. In the documentation for `.getrandbits()`, I see this:
```
This method is supplied with the MersenneTwister generator
```
After a couple of Google searches, I was able to find out the numbers generated by the `MersenneTwister generator` can be predicted after 624 iterations. For this to work, we need to know what previously generated values are, which is conveniently given to us by the program, and feed it into the predictor. A couple more Google searches later and I found a [predictor](https://github.com/kmyk/mersenne-twister-predictor) that was already written for us.

After finding this, I wrote a quick [script](solve.py) to implement the attack:
```python
import socket
from mt19937predictor import MT19937Predictor

host = 'chal.noxale.com'
port = 5115
a = MT19937Predictor()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
for i in range(624):
s.recv(64)
send = ' ' * 16
s.send(send)
a.setrandbits(int(s.recv(64).split()[-1]),32)

s.recv(64)
send = str(a.getrandbits(32)).rjust(16,'0')
s.send(send)
print s.recv(64)
```
It takes the program a while to run through all 624 iterations, but after a minute or so, we get:
```
Correct! Your flag is: noxCTF{41w4ys_us3_cryp70_s3cur3d_PRNGs}
```

***Flag: `noxCTF{41w4ys_us3_cryp70_s3cur3d_PRNGs}`***

Original writeup (https://github.com/scai16/CTF/tree/master/2018/NoxCTF%202018/Plot%20Twist).