The Catch 2019 writeup
The Catch is an online CTF competition organized by the local internet infrastructure non-profit CESNET.
Last year we placed first as a team and got to attend the Trend Micro CTF finals in Japan. This year the CTF was an individual competition and I managed to get the second place.
Contents
The Infiltration
Payment Terminal
Vacuum Cleaner
Colonel Roche
The Infiltration
Here we are provided with a remote HTTP server which returns Python code generating a password and expects the password back in 5 seconds (this is handled by using a session cookie we have to keep around).
Unfortunately the Python code is malformed and changes per each request.
In the end, this was mostly drudge work, figuring out what heuristics are “good enough” to fix the code without breaking it is some other way. I suspect one could harness something like pylama to do a bit more precise fixups, but that was not necessary here.
This does not work in all cases, but running the script several times will eventually get a fixable input code that produces the correct result.
Payment Terminal
We get a PCAP containing an exchange that captures configuration upload to a Cisco router.
First we look at the TFTP exchange. Following the appropriate UDP stream in Wireshark yields this file:
TACACS is some ancient protocol for configuring network devices. Our dump contains it, so we should look at that next.
Fortunately Wireshark supports decrypting TACACS exchanges. Unfortunately the preshared key is in some “encrypted” Cisco format. This can however be easily reversed using this online tool.
Looking through the decrypted TACACS requests yields the flag as a request parameter.
Vacuum Cleaner
Here we have a PCAP containing a large amount of encrypted 802.11 traffic. Running
aircrack-ng
shows that it contains an authentication handshake for the
suggestively named “ThisIsTheWay” network.
After some messing with wordlists, I got lucky with the one from OpenWall, cracking the password in under a minute.
After configuring Wireshark to use the password to decrypt the Wi-Fi traffic, the flag can be found inside a TXT DNS exchange. For whatever reason, I needed to generate a PSK first instead of entering the password directly.
Colonel Roche
This one definitely took me the longest.
We get the following ciphertext:
(linewrapping added by me)
We also get reference to someone called “Colonel Roche”. This guy was a French aeronautical engineer who also dabbled in cryptography. Finding any references to his cryptographical work is extremely hard though. An 19th century textbook can be found that references a cipher named after him but as I do not know any French, it was of very little help. The fact that a street named after him exists housing multiple academic institutions does not help the situation at all.
Out of desperation, I attempted to google a result in Czech and bingo, I got a decade old popsci article about “Colonel Roche’s Transposition Cipher”.
As finding anything about this in English is next to impossible, let me reproduce the method here. The cipher is basically a column transposition cipher except that the columns can have variable lenghts.
First we pick a key, such as robot
and number each of the characters
depending on its alphabetical order. Note that if we have repeating letter,
it does not get assigned the same number twice.
Now we construct variable columns with length limited by their appropriate numerical value. Then we start writing the plaintext in the rows. If a row is already at its maximum character count, we skip it.
Here we take colonelroche
as our ciphertext.
Notice that I padded the message with -
to fill all columns. This will be
important later.
Reading the columns in the top-down order results in the ciphertext cec-ollorhnoe--
.
Decryption is just the process in reverse - We fill columns first and then read the rows.
Now we can make an important observation. As the ciphertext is always padded to fill up columns from 1 to the key length , it’s length is constrained to be an integer solution of the following:
Looking at the ciphertext can give us another important clue — the flag
has to contain characters like {
and if we hex-decoded before applying the
decryption, there would be no way of getting those characters. Thus it is clear
we have to apply the algorithm to the hexadecimal digits directly.
Now we come to the main issue. We have digits and as such there is no integer solution for . The closest we can get is and .
At this point I was hopelessly stuck, attempting to rearrange the blocks manually, generating the block sizes using various more or less sane methods. The challenge hints that the key is a day of week, but what if the block sizes are generated from the hexadecimal digits of the key or something.
After a large amount of effort I finally decided to try the obvious — dividing the ciphertext to fixed-size substrings and using the decryption algorithm on them individually, concatenating the result at the end.
For our given we can divide it with lengths of monday
, tuesday
, friday
and sunday
.
Now I just tried all the possible keys and got the result.
Note that both monday
and friday
produce the same numerical key.