Above is the picture of the challenge on the site. Below are the files linked.
We are given a network capture for a series of port knocking attempts. Port knocking is a special form of SSH where you must ping a series of ports before you're allowed to SSH in. These ports are generated through an insecure RNG function called the Mersenne RNG. Our goal is:
For step one, I wanted to download knockd
and try knocking on my localhost port, but that one fell through due to my own networking issues. So I read through the main function and noticed that we should get two ports per RNG entry; one port is the most significant 16 bits of the entry and the second port is the least most significant 16 bits of the entry. To enter the ssh successfully, you must knock through the order of port1
, port2
, and to close the ssh, the protocol will knock via port2
, port1
.
After manually reading through the Wireshark packet capture, I noticed the following pattern (source -> destination):
So, in order to scrape all the port1
and port2
ports, I looped through all the destination ports in the pcap file; I iterated by pairs, and if a reversed pair was spotted fewer than 5 pairs later, then I would add it to a list.
Finally, I was able to solve this because I did Cryptopals like a year ago. I copied my code for reversing a Mersenne Twister based on 624 usages of the cipher. The premise is that the Mersenne Twister's bitwise operations can be reversed to a single Twister state element with every RNG output, and the state element is initialized to 624 members at the start.
My solution is below.
Below is qr.png
Below is qr.encrypted.png
Below is flag.encrypted.png
I tried observing the plaintext, ciphertext pair QR codes. I noticed that every 16 rows of pixels, the encrypted picture would repeat some sort of pattern. I noticed that if I squinted really hard, I could see the original QR image, but some data would be missing.
I loaded the pictures in matlab and noticed that while the plaintext picture array was all 0s and 1s, the ciphertext was filled with decimals. I formed a theory that I might be able to get a better version of the ciphertext if I:
The resulting picture after I applied my theory looked like
After this, I thought of a way to "fill" the gaps, and found that if I took a point, and it had a black pixel within 10 pixels down, then I should make it black. Of course, the bottom 10 rows wouldn't have 10 pixels down; for those pixels, I would search 10 pixels up.
I then used the same always black ciphertext floats, always white plaintext floats to decrypt the flag.
Here is my work below:
I solved this one after the competition with the help of this writeup. I'm only going to include my solution code with comments.