CTF Challenges from Cyber Security Base with F-Secure 2018/2019

Introduction

As already last year (2017/2018) and the year before, the University of Helsinki (Finland) organized an online course on mooc.fi called Cyber Security Base with F-Secure. You could get 10 ECTS credits for participating. "By the end of the course, hard working participants are expected to possess the skills required from those who work as Junior Security Consultants in the industry." I participated the first year and I liked it. The last part of the course is a CTF (Capture the Flag) challenge in jeopardy style, which I participated in both previous years. It's a beginner-level CTF to get people into the topic, which is very appreciated.

Unfortunately this year a few things went wrong. The communication was broken; nobody could be contacted and there was no chat channel, so that the two broken challenges were not solvable (more on that later). The instructions on the info page didn't match the reality and the starting date and time was not only delayed several times without communication, but also it started then unexpectedly on a Wednesday instead of Monday. That wasn't a big problem though, as the "first blood" feature was removed. It also wasn't clear when it ended, as the CTF was open for seven weeks instead of one week. Actually it's still open, but the grading is done, so I can publish this write-up now.

This year there was no online challenge among the tasks, so all challenges are now available here for replay. It's good if you want to retry and learn, but not so good regarding the reduced number of topics; many challenges were about stego - a topic that was not covered in the course as far as I know, so you had to investigate yourself.

The "first blood"-name feature was also not present this year. This was on one side a bit sad as it removed some interesting competition, but on the other hand it calmed down the solving rush, so from that point of view it was good. Some rumours say that it was removed due to GDPR.

Overall I think it's still a good idea to get into CTF playing for people new in this field, as the overall difficulty level is not too high. And there are still a few difficult challenges for those that have some experience. This also brings you back onto the ground if you think you can solve anything after having solved the other easy challenges.

My Goals

As I had solved 100% in all previous years, it was clear that I wanted to reach the same this year as well. Unfortunately I couldn't solve two challenges. One "easy" one and one "hard" one. The "hard" one is a challenge that nobody solved. More on these two challenges in their description. As I didn't solve those two challenges (and especially not the "easy" one that some others did solve), I was quite disappointed for me personally.
View of the CTF screen

Challenges

So here are the challenges. All source material is available here as well, so you can solve all challenges yourself, just stop reading after the challenge description. Have fun!

1: Stega cat 1 (Stega cat)

Stega cat 1 challenge
There was a jpg image given and asked to find some stego flag in there. The following is the original image (click on it to get the full image) in case you want to have a look yourself.
Stega cat 1
This challenge should've probably been a very simple one. It is almost the same as the Stegosaurus 1 challenge in the 2017/2018 competition. With various tools it was viewable that in the upper right area of the image there was some text hidden. Enhancing this text (it was only one single color, slightly different than the white background) didn't yield anything readable:
Unreadable enhanced text within the image
It probably reads "Flag{mumgle_34e0_One}" or something like that. I also searched for the original image (found it) and compared that to the given image. It didn't result in anything different though.
After this CTF, during this write-up, I got the result from a colleague that I can post here:
"You just had to squeeze your eyes and use your imagination."
"Flag{Simple_3320_One}"
"Some trial and error, but you know that often flags are like Flag{something}. The "_One" at the end is clear and I guessed that the first part was "Simple," as this would make sense (Simple One). Then in-between it was a bit more difficult, but clearly is was a number starting with 33 and probably ending with 0."
To me, this was all but "clear" that it ends with "One", but I had guessed that part as well. The first part ("Simple") was not readable to me. And why should there be just a number in the middle? I think this is far from an "Easy" challenge and thought that the organizers must have saved the jpg twice by mistake, causing more distortion than necessary. On the other hand, 28 people found the solution, so that means that several people could guess it somehow. I couldn't. I actually printed out the enhanced text in the office and nobody could guess it walking by. I also tried to use online OCR and AI systems without success. Clearly this is not an "Easy" challenge and having to brute-force the solution system cannot be a good challenge. I think the organizers just thought that the image enhancing task was the difficult part, but that was solved in a few minutes. Luckily you didn't have to solve 100% of all the Easy challenges to get to the next level like previous years, otherwise this would've been a disaster.

2: Stega cat 2 (Stega cat II)

Stega cat 2 challenge
Another stego challenge with a cat image:
Stega cat 2
This is actually the same challenge as the "Cats" two years ago or the "Stegosaurus II" from last year. There are some additional bytes at the end which are easily visible in a hex editor:
Stega cat 2 in HxD
So here we see the flag at the end: Easy2210Enough.

3: Stega cat 3 (Stega cat III)

Stega cat 3 challenge
Another stego challenge with a cat image:
Stega cat 3
This is actually the same challenge as the "Stegosaurus III" from last year. This time I solved it with StegSolve, which clearly showed the additional bytes at the end:
StegSolve shows the additional bytes
We could also find these bytes with a hex editor, but StegSolve shows nicely the beginning.
This looks like base64, so converting this back gives us the flag:
base64 conversion to get the flag
So we have our flag: ShouldNotBe2110TooHard.

16: Stega cat 4 (Stega cat IV)

Stega cat 4 challenge
Another stego challenge with a cat image:
Stega cat 4
Analyzing this image with the online 29a tool immediately shows us the flag:
Analysis of Stega cat 4 with the online 29a tool
We can see here that the flag is stored in the thumbnail. So our flag is Part0111.

20: Stega cat 5 (Stega cat V)

Stega cat 5 challenge
Another stego challenge with a big cat image (bmp):
Stega cat 5
This reminded me to a previous years challenge, and indeed this was the same as the "Too curious cats" in the challenge two years ago, respectively the same as the "Stegosaurus IV" from last year. We can use zsteg to solve this:
running zsteg on Stega cat 5
So there we have our flag: lsbsecretrandom7987978965751partflag.

22: Stega cat 6 (Stega cat VI)

Stega cat 6 challenge
Another stego challenge with a cat:
Stega cat 6
This is actually the same challenge as the "Stegosaurus V" challenge from last year.
If we open the file in 29a tool, we see this thumbnail:
29a tool showing the thumbnail
The text says Alm0stButN0tQu1t3 ("almost, but not quite"), so there's something more.
The StegSolve tool shows us that there are again additional bytes at the end of the original image file:
StegSolve showing additional bytes
Looking at these bytes, we already see that it's starting with "PK", which stands for a ZIP file. So we copy those bytes into a hex editor and save this new file. The ZIP file can be opened and shows a single file with the name "foobar_a" in it. Opening it doesn't work, because it's password protected, so we need 7-zip or another tool to extract the file and the right password of course. But we already know the password from above, so we can extract the file. The file foobar_a is a text file, so we can open it and it contains our flag:
extracted file foobar_a with our flag
So the flag is ThisFlag3211isDope.

4: Cyber monkeys 1 (Cyber monkeys)

Cyber monkeys 1 challenge
So we have to somehow decrypt the message RmxhZ3tEaWROb3RUYWtlTG9uZzI4NzZ9.
We find that base64 decodes this text:
base64 decode
So the flag is DidNotTakeLong2876.

5: Cyber monkeys 2 (Cyber monkeys II)

Cyber monkeys 2 challenge
So we somehow have to decrypt the message SyntEnaq jura pbapngrangrq jvgu Cnegfrira vf gur Synt.

This immediately looks like rot13, and indeed it is:
rot13 deciphering
So we get the text "FlagRand when concatenated with Partseven is the Flag". Not much thinking about this results in the flag FlagRandPartseven.

11: Cyber monkeys 3 (In-laws of cyber monkeys)

Cyber monkeys 3 challenge
So we have the text "Tpm nwttweqvo FtioRivlwu epmv kwvkibmvibml eqbp Pizbnqdmaqfamdmv" that we have to decrypt somehow.

This again looks like rot13 and using the site already gives us almost the result (with rot18):
rot18 deciphering
So with that, we get the text "Lhe following XlagJandom when concatenated with Hartfivesixseven".
We can see in this text that all the upper case characters are wrong. If we look at the original text again, we see that the first letter was an "T", exactly what we need in the result. And the same with "FlagRandom". So we replace all upper case letters back with their originals and get the following text: "The following FlagRandom when concatenated with Partfivesixseven".
If we concatenate the two words together, we get the flag: FlagRandomPartfivesixseven.

12: Cyber monkeys 4 (Ubreakable encryption?)

Cyber monkeys 4 challenge
So here we have the message "1 0000 00 000 00 000 1 0000 0 0001 0 010 1011 000 0 1010 010 0 1 11 0 000 000 01 110 0 0010 0100 01 110 00011 00011 00111 00001 01111" that we have do decrypt.
This is actually the same challenge as last year "Perfect encryption scheme?".
Does "Ubreakable" stand for "you break" or is this simply a typo? Who knows.

We find that this is Morse code and converting the 0s to a dot and the 1s to a dash, we get the following Morse code: - .... .. ... .. ... - .... . ...- . .-. -.-- ... . -.-. .-. . - -- . ... ... .- --. . ..-. .-.. .- --. ...-- ...-- ..--- ....- .----
Using any online tool, we can convert that to text:
online Morse conversion
So we have the text THISISTHEVERYSECRETMESSAGEFLAG33241. This did not get accepted, but trying a bit around with this text finds that the flag is simply flag33241.

14: Cyber monkeys 5 (Cyber monkeys strike back)

Cyber monkeys 5 challenge
So here we have another message to decrypt: Znk bkxe yavkx ykixkz oy lrgmxuzyodyzkvy.

This again looks like rot13 and we find that this is indeed rot20:
rot20 of our message
So we get the text The very super secret is flagrotsixsteps. And indeed, our flag is simply flagrotsixsteps.

6: Hashing 1 (A simple hashing scheme)

Hashing 1 challenge
This is the same challenge as last year's 'modhash' challenge.
As we have to take the modulus 16, we can just take the ASCII code of the last character '7', which is 0x37 and the mod 16 would be 7, which is our solution.

13: Hashing 2 (Long live the queen)

Hashing 2 challenge
password: longlivethequeen2000
hash: 074ae09f55459c6698768ad38d36c360291102ba
new hash: 94fd1d4525ce518fc514ea086ad9f909d6841b26.

This is actually the same challenge as the "queenrulez" from two years ago and the same as the "Password expiration policy" from last year.

We can solve this with the following hashcat command:
hashcat64 -m 100 -a 3 94fd1d4525ce518fc514ea086ad9f909d6841b26 longlivethequeen?d?d?d?d

hashcat in action
And we find that the new four digits are 8356. The flag is longlivethequeen8356.

15: Hashing 3 (Hash functions)

Hashing 3 challenge
Here our task is to brute-force the hash 3993159714d338335d856019cbde9e6a.

This is the same challenge as "Hashing" from last year and also "Killing hashes" from two years ago. It already says "or someone else's", so we can simply google it. We find it immediately at Hashkiller (MD5):
HashKiller finds it
So we get our password, which is also our flag: cyber111190.

7: Crypto 1 (Mysterious message)

Crypto 1 challenge
Message: 81942246B6355A22389698B43C979141B7A32A2FAE094E1DECA31DD92063C226
key: 000102030405060708090A0B0C0D0E0F

This is the same or similar challenge as the "Awkward Ending Syndrom" from two years ago and the "Advanced Encryption?" from last year.

As this is a short key, it must be symmetric cryptography and therefore probably AES. We use some online tool:
AES decrypt
So this already gives us the flag Thisis5410flag.

8: Crypto 2 (Alice's crypto party)

Crypto 2 challenge
p=45000107, q=48000089, e=17, d=?

So we have to do RSA.

This challenge is the same as the last two years, both times with the same title.

To solve this, we can use the online tool at https://www.mobilefish.com/services/rsa_key_generation/rsa_key_generation.php.

Running this tool gives us n=2160009141009523 and d=635296778826273. The value for d is also our flag.

17: Crypto 3 (Hidden message)

Crypto 3 challenge
The given text file can be downloaded here: Textfile in Pastebin (zipped and base64'd).
So somehow there's some hidden message in this text file.
This is the challenge that was solved only by five users, so it was probably the hardest challenge of all (besides the one that didn't get solved by anyone).

If we open the file in Notepad, we just see the text:
Notedpad of the given text file
As we cannot see anything in the text itself, I assumed it must be in some Unicode characters. The text is indeed a UTF-8 text. So let's open it in a hex editor:
The text file in HxD
So we can see there that there are additional hidden characters in the text. The first (marked) one is E2 80 84 (U+2004) and is "Three-per-em space". So essentially some whitespace character. We can also discover E2 80 85 (U+2005), which is a "Four-per-em space".
The question is now, what code could that be? First of all, I checked if it is in any way related to the text itself. This can clearly be excluded, as the text is a publicly known text - I found out that it is the English translation of the famous Lorem ipsum text. This means that there is nothing hidden in the text itself.
What immediately came into my mind, is the Umpox project to hide data in text with hidden spaces. This is quite impressive; try it out yourself. But unfortunately it is a different code.
If you google a bit, you can find that there are more such projects:


And the last one is a Bingo! It already mentions FOUR-PER-EM SPACE and THREE-PER-EM SPACE, exactly what we use.
Here's the documentation: https://github.com/izderadicka/unistego/blob/master/README.md
And here's the main source code for it: https://github.com/izderadicka/unistego/blob/master/unistego/stream.py
I've studied the source code a bit and from there you find the algorithm, so that you could also manually decrypt it:

  • There are some text markers (comma, full stop, semi-colon, etc.). Remove those and the following space.
  • The character "Three-per-em space" marks the start and stop of the hidden message. There are exactly two such characters. Remove all text before the start and after the stop (and those two characters as well).
  • Remove all letters
  • Replace a regular space with a 1 and the "Four-per-em space" with a 0.
  • Group the resulting bits to 8 bits and convert to ASCII (big endian)

Or simply use the given tool:
Solving the challenge using Ivan Zderadicka's Unistego tool
So the flag is NotSpacesA.

9: Password 1 (Password)

Password 1 challenge
Here's the given binary (zipped and b64'd) on Pastebin.

Actually this could already be solved by opening the file in Notepad (or the Linux strings command), but opening it in the Ghidra decompiler showed the result even much clearer:
line 28 shows the correct password
So we have the flag right there; CorrectPasswrdDEAA.

10: Password 2 (Password II)

Password 2 challenge
Here's the given binary (zipped and base64'd) on Pastebin.

This is pretty much the same as the Password 1 challenge, but base64'd.
decompiled source code
So we just convert the Q29... to text and get the flag CorrectPasswrdDAFA.

18: Password 3 (Password III)

Password 3 challenge
Here's the given binary (zipped and base64'd) on Pastebin.

So let's look at the source code in Ghidra again:
Source code in Ghidra
We don't have to care about the input, but the output of the correct flag is what the printf in line 29 returns. So we have there some bytes (46 6c 61 67 34 35 33 46). Those bytes converted to text results in our flag: Flag453F.

19: Password 4 (Password IV)

Password 4 challenge
Here's the given binary (zipped and base64'd) on Pastebin.

This is the same challenge as "Cracking the lost password" from two years ago and also the same as Password checker IV" from last year; it was simply UPX packed. Last year I unpacked the binary with the Linux command line as this is a built-in function. This time I found the Windows binary (downloaded) and decompressed the executable. Then running Ghidra on it, we get some simple code again:
decompilation of the UPX decompressed executable
So we see there that the flag is CorrectPasswrdABBAA.

21: Stego sound (Something sounds off)

Stego sound challenge
Given was the huge sound file (7-zipped and base64'd here) (4'032'044 bytes, SHA-2 hash: 001F780D07DAA9EE6CCA2D4DB653122BDB5A70D89FA058F5369CCDD20DB54A36)

There are several ways to store data in audio files. The most common way is probably to use the LSB (least significant bit) of the audio data. Another spectacular way that was used in another CTF is visualizing the audio spectrum on a frequency-time chart that shows some written text in the visualized spectrum. This can't be the case here though, as the audio is clearly something natural. A third method would be to hide data in the metadata or after the audio file in the same file. It could also be that there is some spoken message somewhere in a long audio file, but ours was just 42 seconds and I listened it entirely (many times actually).

First I tried several existing stego tools, but none of them worked. Either there was a password required or it simply couldn't find any hidden data in the audio file. I also tried StegCracker with some password lists and let it run for many hours.

So I started documenting the binary audio file in order to see if there is any metadata or additional data:

  • 000000 52494646 "RIFF"
  • 000004 24863D00 file size 003D862C
  • 000008 57415645 "WAVE"
  • 00000C 666D7420 "fmt "
  • 000010 10000000 len of format chunk (000010)
  • 000014 0100     1=WAVE_FORMAT_PCM (values other than 1 indicate some form of compression)
  • 000016 0200     2 channels
  • 000018 C05D0000 24000 samples/second
  • 00001C 00770100 96000 bytes/second (=1 sample uses 2 bytes per channel)
  • 000020 0400     BlockAlign=NumChannels*BitsPerSample/8=2*16/8=2*2=4
  • 000022 1000     BitsPerSample=16
  • 000024 64617461 "data"
  • 000028 00863D00 length of data chunk (3D8600=4032000d)
  • 00002C ...      data
  • 3D862C          file ends

For the data format:
2 bytes per sample and per channel as mentioned above, 2 channels

  • byte 0: lower byte (little endian) first sample left channel
  • byte 1: higher byte (little endian) first sample left channel
  • byte 2: lower byte (little endian) first sample right channel
  • byte 3: higher byte (little endian) first sample right channel
  • byte 4: lower byte (little endian) 2nd sample left channel
  • byte 5: higher byte (little endian) 2nd sample left channel
  • byte 6: lower byte (little endian) 2nd sample right channel
  • byte 7: higher byte (little endian) 2nd sample right channel

and in our example:
16-bit samples are stored as 2's-complement signed integers, ranging from -32768 to 32767.

  • 02000100 left: 0002, right: 0001 -> left 2, right 1
  • 00000100 left: 0000, right: 0001 -> left 0, right 1
  • 00000300 left: 0000, right: 0003 -> left 0, right 3
  • 0200FFFF left: 0002, right: FFFF -> left 2, right -1
  • 01000000 left: 0001, right: 0000 -> left 1, right 0
  • FEFFFFFF left: FFFE, right: FFFF -> left -2, right -1
  • 03000100 left: 0003, right: 0001 -> left 3, right 1
  • FEFFFFFF left: FFFE, right: FFFF -> left -2, right -1

This matches with what Audacity shows.

From this documentation, we see that there is no additional data and that the raw data starts at 0x00002C in the file.

Then I wrote a program to extract the LSB, starting at all different positions with various spacing and output all text. This in various formats (little and big endian, bit shifted, with/without limiting result to printable characters, etc.). Unfortunately, there could be no flag found this way either.

Additionally I used the output of my LSB extractor and fed that to Gynvael's Entropy visualizer. There was also nothing interesting found; all looked pretty uniform.

The next thing I tried was to find the original audio file. I assumed it must be from some public source before the data was hidden in it. If I could find that and compare it against our file, I would quickly find the differences and could at least confirm that the data is in the LSB. Or maybe just in every 271th LSB or something like that. Unfortunately, even after spending many hours, I couldn't find the original sound source. Finding sounds is a bit difficult on the Internet due to copyright concerns. There is no easy way to find existing files that begin with some bytes or so. You had to go to well-known big freeware sound collection sites and search there for "woods" or "birds in forest" etc. with similar lengths etc., but I couldn't find our file.

My best guess for this challenge is that there is some obscure Linux tool already available somewhere, that nobody found so far.

If anyone finds the solution for this one, please post a comment.

Comments

Popular posts from this blog

Insomni'hack 2024 - Award Challenge

Capture The Flag Challenges from Cyber Security Base with F-Secure 2017/2018

Insomni'hack Teaser 2018 CTF