Tenable’s first CTF took place past weekend. I really enjoyed the challenges! In the following, you can find some writeups for the Stego and Misc category.
Stego
Easy Stego - 25 points
Message
Can you find the flag?
Content
Solution
The image consisted of three seperate images, each in a different colour. I decided to use the tool stegsolve for getting a better look at it.
By executing the command java -jar stegsolve.jar
, stegsolve is started. Now, the image can be opened and viewed in different filters.
On the images, we can now see the flag:
flag{Bl4ck_liv3S_MATTER}
Secret Images - 125 points
Message
We discovered Arasaka operatives sending wierd pictures to each other. It looks like they may contain secret data. Can you find it?
Content
Solution
The two files look like they have both been encrypted with the same XOR key. This article gives a nice explanation for what XOR is and what properties it has. While XOR encrypting one image with a key is quite secure, repeating the same key twice makes it possible to find out the contents of the original, unencrypted images. By assuming that both files have been encrypted with the same key, we can figure the following equations.
img1 ^ key = enc_img1
img2 ^ key = enc_img2
As we have crypted1.png and crypted2.png given, we can make a new equation and solve it for the original images:
enc_img1 ^ enc_img2 = img1 ^ key ^ img2 ^ key
As XORing something with itself always returns zero, the two occurences of the key cancel each other out.
enc_img1 ^ enc_img2 = img1 ^ img2
This means that by XORing the two images given with each other, we’ll end up with an image of the unencrypted images XORed with each other. In practice, this can be done with the following command: (1)
convert crypted1.png crypted2.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" decrypted.png
Running the command confirmed the hypothesis that both images had been encrypted with the same key and I ended up with the following image:
flag{otp_reuse_fail}
(1) Note that you have to install imagemagick first, e.g. by running sudo apt install imagemagick-6.q16
(or any other version)
Resources
Misc
Esoteric - 25 points
Content
--[----->+<]>.++++++.-----------.++++++.[----->+<]>.----.---.+++[->+++<]>+.-------.++++++++++.++++++++++.++[->+++<]>.+++.[--->+<]>----.+++[->+++<]>++.++++++++.+++++.--------.-[--->+<]>--.+[->+++<]>+.++++++++.>--[-->+++<]>.
Solution
By simply putting the given string into a Brain Fuck converter, one could decipher the flag.
flag{wtf_is_brainfuck}
One Byte at a Time - 50 points
Message
challenges.ctfd.io:30468
Solution
Via nc challenges.ctfd.io 30468
, one could enter the part of the flag one already knew and if it was correct, the site returned the following:
My first approach was trying to brute force the site, but as it reacted extremely slowly I tried another approach. By knowing that the flags start with “flag{“, I figured I could obtain at least parts of the unknown IPv4 XORed with the following character of the flag. As XORing is associative and commutative, I could just XOR the suggested hex value for the parts of the flag I already knew. This way, I figured out three of the four octets in the IPv4 address: 119, 16 and 2.
Now, I XORed all three values with each hint the site gave me, chose the most plausible outcome, checked whether it was right and then repeated that process for the next letter. I ended up with the following flag:
flag{f0ll0w_th3_whit3_r@bb1t}
Broken QR - 100 points
Message
Can you scan this QR code for me?
File
Solution
In this task, above QR code had to be restored into a scannable format. My main resource for this task was the article Wounded QR codes by DataGenetics.
I started by restoring the positioning markers in the top left and top right corner by simply copying the one from the bottom left corner into their positions. Then, I fixed the left timing mark by copying the other one, rotating it by 90 degrees and putting it in the correct position. My last step was to copy a single black square and insert it at any position where remains indicated former black markers. However, that step was probably optional as it restored no markers essential for scanning a QR code. I used the open source image editor Krita.
Upon scanning the resulting QR code, I found the flag:
flag{d4mn_it_w0nt_sc4n}
Forwards from Grandma - 100 points
Message
My grandma sent me this email, but it looks like there’s a hidden message in it. Can you help me figure it out?
Content
Solution
By having a closer look at the subject of the mail, one could see a large amount of FWD: and RE:’s - which is not too unusual in a mail from grandma, but the swirly brackets in between caught my attention as it resembled the flag format.
My initial guess was it being binary with the FWD: as a 0 or 1 and the RE: as a 1 or 0, respectively, but as that lead to nothing I figured it was morse code instead. Knowing that the morse code before the opening of the swirly brackets had to be “flag”, I could confirm my hypothesis and find out the correct mapping.
"FWD:" => "."
"RE:" => "-"
Quick Note: If you paid attention to the header, you probably noticed that there were in fact double spaces in the header indicating the end of a morse code letter, meaning you could just decode it. If you are interested in reading how to decode morse without spaces, you can read on. Otherwise, just skip ahead to the flag.
The resulting morse code was: “..-..-…—.{….–.—……….–.-.—-.-..}”
The difficulty here was that no spaces were in between the morse code letters, meaning that there were a ton of possible solutions (like 1628277960) for the text between the curly brackets due to the ambiguity (e.g. “…” can mean eee, ie, ei or s).
After some while and running a function that would return me every possible combination of spaces inserted for more than six hours (Spoiler Alert: it didn’t finish), I noticed that words in the flags were usually seperated by underscores. The morse code for underscores is quite recognizable (..–.-) and occured two times in the encoded flag. With that information, I could now split my flag into three seperate words of much shorter length and thus less ambiguities.
“flag{.._--........_.----.-..}”
With the initial function for inserting spaces in combination with a function for decoding the morse code, I could now determine all possible solutions for my three words. As I thought the words would either be in a dictionary or be leetspeak and thus containing numbers, I implemented optional checks for both possibilities. (1)
By picking the most plausible words from the resulting list, I ended up with the right flag.
flag{i_miss_aol}
(1) That would have probably worked great, but when transcribing the FWD:’s and RE:’s to morse I had noted down one dot too much which lead to no sensical dictionary entries.