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

Setup and Environment

As already last year (2016/2017), the University of Helsinki (Finland) created 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 last year and I liked it. The last part of course is a CTF (Capture The Flag) challenge in jeopardy style.

In order to pass, you had to solve 80% of the "easy" challenges and 60% of the "medium" challenges. There were 12 "easy" challenges, 9 "medium" ones and five in the "hard" category. In order to see the challenges of the next level, you had to solve 80% of the previous level first. The "easy" ones were released on a Monday evening, the "medium" ones on a Tuesday evening and the "hard" ones on a Wednesday. The CTF was running for 8 days in total. On each release-evening, the different challenges were released in about 10-minute delays, because each challenge has the name of the first solver next to it and the delay helps to give everyone a chance to get their name into one.

My goals

Last year I solved 100% of the challenges (with extensive effort) and I did not get my name into any of the challenges as first-solver, because there were people who solved some easy challenges in seconds. This year I hoped it would be a bit easier for me, especially after knowing much more and having solved similar challenges. In this past year I also participated in a "real" sit-in CTF. Unfortunately I have to say that only the hardest challenge here is comparable to the difficulty level that you will find on such CTFs. On the other hand, this makes it more fun to solve these CTF challenges here, because having easy challenges motivates you. One challenge was really hard.

My goal was to finish again with 100% success rate and get my name into at least one challenge and also finish with more ease and earlier than last year. Well, I did achieve the 100% success rate (as one of six people that made it). I also got my name as "first-solver" into two easy challenges. For some more challenges I was second solver with just a few seconds behind. I was not at home on the second day for the "medium" ones and too slow for the "hard" ones. The "easy" challenges were indeed much easier for me and some challenges were repetitions of last year. But overall it was not totally easy for me, especially the Last Dr. Kyberzig, where I struggled until the last minute. I solved that last one just a few minutes before I thought the CTF was over. Due to time zone differences (the CTF didn't finish on Finnish time zone as it started, but in AoE time zone instead), it ran half a day longer. It took three days until someone managed to solve the Last Dr. Kyberzig and at the end only six people solved it at all.

Repetitions and Spoiling

One hour before the CTF started, I posted the link to my last year's write-up in the CTF chat channel and some people condemned this, saying "I having spoilt the CTF", because the rest of the course was identical as the content last year. Actually there were some almost identical challenges as last year, but I don't think this has spoilt anything. My last year's write-up is also easily findable if you google for it. The organizers knew about my write-up since last year. So I don't think this was a problem. Let me know if you participated and disagree. This also means that you can and should use this write-up here to prepare for next year or for other CTFs. Only two of the 26 challenges were to be made online (Cyber Bank) and all others can still be solved 100% offline and are available here for you.

Conclusion

There were three easy "rot13" related challenges. One of those would have been enough. In total, there were too many repetitions from last year. The bank challenges, the UPX reversing trick, some password reversing challenges, one hard stego, some hashing ones and maybe some more.

I would appreciate some more realistic challenges, like a SQL injection, maybe even one that cannot be exploitet with sqlmap. Or an application with a CSRF or XSS vulnerability or something like that (similar to the Cyber Bank application, but something new).

I really did like the Dr. Kyberzig challenges, although this shows that I lack knowledge in JavaScript frameworks. It also was very frustrating until I solved it. But that's actually a good thing.

Overall I liked this CTF a lot, although it did cost much of my health again. I'm looking forward in participating next year again. I'd like to thank the organizers and F-Secure for organizing this great education initiative.

Did you participate as well? If yes, did you take a completely different approach somewhere? Are there any mistakes in my write-up? Let me know in the comments below or contact me on Twitter @e4ch.

Title image for all solved
Now here are the solutions and how I got them.

Stegosaurus

Stegosaurus
"Something is not quite as it should be in this image. Can you find it? http://sec-mooc-1.cs.helsinki.fi/stegosaurus/45f3r/01/stegosaurus01.png"


This is the image:
stegosaurus01.png


So the easiest thing for this one would be that there is something in the binary at the end of the image, but unfortunately opening this in a hex editor didn't show anything interesting, except "tEXtComment.Secret", but this was not accepted as the flag. As it said "comment" there, I also looked at the file properties, but couldn't find anything interesting.
Then I tried some online tools and found the site https://29a.ch/photo-forensics that found something in the image itself:
Site 29a.ch showing that there is something written in lower-right corner
Unfortunately I still couldn't read what was written there. But as a knew there was something, I opened Photoshop Elements (yes, I have a license), cut out the lower right area, zoomed in and tried to enhance that area. This worked well:
Image enhancing with Photoshop
So there is our flag, "CraftyBugger".

Dr. Kyberzig's Key Validation Service Mk I

Dr. Kyberzig's Key Validation Service Mk I
"You have lost your key to Dr. Kyberzig's software and he is refusing to help you since he believes that those who are foolish enough to lose their keys don't deserve to use his products. Dr. Kyberzig has suggested that you try to figure out what your key was. You can use his key validation service that is available here: https://dr-kyberzig-8b0e66b8.now.sh/"

Here are the files from the Kyberzig challenges 1-4, compressed (7z format) and converted into base64. If you want to run it locally, then you need to fix the problem with creating the service worker (see a later Kyberzig-challenge on how to do that), or put it onto a website instead.

After opening the site in IE, I noticed that it is not working, for whatever reason. Just a blank page appeared. In Chrome it did work though:
Input screen of Dr. Kyberzig's Key Validation Service Mk I
Opening the developer tools with F12, opening and prettifying the js code and searching for "is not valid" got me to this code where a few lines above the error, you can already see the correct key:
Debugging Dr. Kyberzig 1
And indeed, this "VERY SECRET KEY" is our flag.

Stegosaurus II

Stegosaurus II
"Something is not quite as it should be in this image. Can you find it? http://sec-mooc-1.cs.helsinki.fi/stegosaurus/rwer3/03/stegosaurus03.jpg"

This is the image:

stegosaurus03.jpg

If we open the file with a hex editor, we see this at the end:
Hex editor of image stegosaurus03.jpg
And this is already our flag: Flag{ThisIsEasy}.

Dr. Kyberzig Mk II

Dr. Kyberzig Mk II
"Dr. Kyberzig is furious that you have cracked his key service! He has changed all of his keys and made a new validation service. Regain access. https://dr-kyberzig-18op1re4f2491.now.sh/"

Here are the files from the Kyberzig challenges 1-4, compressed (7z format) and converted into base64. If you want to run it locally, then you need to fix the problem with creating the service worker (see a later Kyberzig-challenge on how to do that), or put it onto a website instead.

While this challenge is pretty similar to the first Dr. Kyberzig, it did take me some time. First we open the page in Chrome, search for "not valid" in the prettified js file and find after a while the same "validateKey" area again.
Debugging Dr. Kyberzig Mk II


There is a "validator", which sets the valid state that is later used to set the result. So we set a breakpoint on the validator function and step in to it and we get to an interesting function:
Inside the validator function
So there we see some handling of character codes and stuff. As I didn't want to get into the details of all this, I simply entered this whole area into a "alert(...);" command into the Console window and got this result:
Entering the validator function into Console window
So in the window there you can see the correct new password, which is also our flag: "THESE KEYS ARE TOO EASY".

Stegosaurus III

Stegosaurus III
"Something is not quite as it should be in this image. Can you find it? http://sec-mooc-1.cs.helsinki.fi/stegosaurus/43241/04/stegosaurus04.jpg"

This is the image we see:
stegosaurus04.jpg
Opening up this image in a hex editor, we see the following at the end:
Stegosaurus III in HxD
We can see that there are some interesting characters and the ending of "ZH0=" plus a 0x0A. This ending indicates something base64-encoded. But where is the start? The first readable characters are ÿÙTWF. The 'ÿ' and 'Ù' are certainly not base64, so we'll leave those away. Entering that into some converter tool:
Converting the found text from Stegosaurus III from base64 to text
So there is our flag: ShouldNotBeTooHard

Alice's crypto party

Alice's crypto party
"Alice has chosen two primes p=41000021 and q=50000021 for her RSA modulus n and an encryption exponent of e=17. What is the decryption exponent d?"

So we have to solve a standard RSA challenge. As we don't have any big numbers, this should be easily solvable with online tools. I found this RSA tool usable for this challenge.
So let's enter the two values p and q (and select decimal from the two dropdowns). It then already shows for both values that the bitsize is 26, so let's select key size=56 bits from the dropdown (26+26=52, just a bit less than 56). This already calculates that Euler's phi(n)=2050001820000400.
In step 2 we enter the public exponent 11 (or switch to decimal and enter 17).
In step 3 we select decimal for both dropdowns and click "Generate keys". Then we get an error message that p>q is now fulfilled. So we need to swap the two value in the first step and repeat everything done so far. Then we get the modulus n=2050001911000441.
In the next step we get the private key 844118396470753, which is already our flag.
During the CTF it was actually a bit more complicated. I did get about 20 different "candidate keys" or something, which I all had to try manually if they fulfill some criteria. Either I did something wrong or they improved the website since then.

Cyber monkies

Cyber monkies
"Our advanced cyber monkeys have invented an encryption scheme that's supposedly impossible to crack. Can you prove them wrong? The message is: RmxhZ3tEaWROb3RUYWtlTG9uZzg3Nn0="

So there's some encrypted message. We notice the '=' at the end, so it's clear that this is base64 encoded. Any online base64 to text decoder quickly returns this text: Flag{DidNotTakeLong876}.

modhash

modhash
"Simple hashing involves encoding of strings of characters for example "hash -> hex 68617368 -> dec 1751217000". A hash function takes in strings of variable length and transforms them into fixed length strings. A simple example would be to take modulus 16 of the string. What would the mod be for string "FlagSix""

This is one of the two challenges where I was first. It's so easy that it could be solved in a few seconds. Well, actually you had to read it carefully, which already took the most of the time.

So they explain how their simple "hash" function works and that we should do the same with a different text. So let's do what they have done with the text "hash".

The text "FlagSix" converted to hex bytes is 46 6c 61 67 53 69 78, or in big endian 466c6167536978. If we convert this hex number into decimal (Windows calculator can do this) we get the decimal value 19822413970893176. Now this value modulo 16 (Windows calculator can do this) is 8. This is already our flag.

If you understand how this all works, then you understand that this is not really a real hash function; you could change any character in that text (except the last one) and it would not change the hash. And this understanding would also improve the solution speed; you could just convert the last string character to hex: "FlagSix" -> 'x' -> 0x78 and take the lower digit (8), which is the solution. This would be much faster to solve, but during the CTF I also took the first variant.

Last year there was an identical challenge, just with a different text.

Advanced Encryption?

Advanced Encryption?
"A Canadian Born person named Chad has received the mysterious message "8919A38892725B682688E41429DC3B98C6A13B37878F5B826F4F8162A1C8D879" that has been encrypted with his key "000102030405060708090A0B0C0D0E0F". Unfortunately, Chad forgot how to decrypt the message. Can you do it?"

So there's some encryption, probably AES as the name suggests. I used Cryptomathic:
AES decryption
So we get the decrypted output of 546869734973333435546865466C6167 and 16 Null-bytes. If we convert that to text, for example with the tool RapidTables, we get:
text conversion
So here we see our flag: ThisIs345TheFlag.
The last year there was a similar challenge. There they used CBC instead of ECB and many tools default to ECB. So this year this challenge was much simpler.

Admin panel

Admin panel
"Rumour has it that CyberBank (https://cyber-bank.testmycode.io/) has a secret admin panel containing top secret information. Your client wants you to find it and to 'obtain' its secrets. The panel supposedly leaked previously when a popular search engine accidentally indexed it. However, security has been tightened since then."


This is one of the few challenges that was exactly the same as last year. It is one of the two online challenges this year, so you cannot retry it again.
When you went to that link, you get a login page:
Admin Panel start page
It says you should log in with your TMC account, but either it didn't work at that time or only after the more difficult challenges opened up. But even if you did login, nothing useful was there.
The challenge says "there's something hidden" and talks about search engines, so let's have a look at the robots.txt file:
robots.txt
So we have a link in there: /super_secret_admin_panel_aaaaa
Opening that link shows this admin panel without authentication:
admin panel
And there you already see: Database password: "vacanthorsebackfunnel".
This is indeed our flag.

Password checker

Password checker
"Can you figure out the password? The binary file should work in 64-bit Linuxes. http://sec-mooc-1.cs.helsinki.fi/password-checker/tr5mg/PasswordChecker_aa"

If you download the file (link here as base64 encoded on Pastebin) you get a Linux binary. I was a bit reluctant to install Linux, so I simply opened it in a hex editor and found the password there:
HxD view of the executable
You can see the password there: CorrectPasswrdDEAA, which is also our flag.
I haven't done that during the CTF for time reasons, but as an alternative, you could also simply open this executable in BinaryNinja, an inexpensive but very useful tool and get this directly in the "main" function:
BinaryNinja view of the password check
Here you see the password very clear and you also see that it's used for calling the strcmp function.

Banana vault

Banana vault
"Cyber monkies have restricted access to their banana vault with a passphrase. They have left behind the following message: "un gurl unir ab vqrn gung gur cnffjbeq gb bhe onanan inhyg vf lryybjonanannnn". Figure out the passphrase."

This text already looks like rot13 encoded, so let's try rot13.com:
rot13 of Banana vault
So this translates to "ha they have no idea that the password to our banana vault is yellowbananaaaa".
And indeed, entering yellowbananaaaa confirms the flag. Straightforward and I was first in solving this challenge.

Stegosaurus IV

Stegosaurus IV
"Something is not quite as it should be in this image. Can you find it? http://sec-mooc-1.cs.helsinki.fi/stegosaurus/df84d/02/stegosaurus02.jpg"


Downloading the image gives us this one:

stegosaurus02.jpg
I tried various things with this image and while examining the image, I noticed that one of the online tools showed me the thumbnail of the image, which looked totally different than the image itself:

thumbnail
So that made me think that I should look at the thumbnail image a bit closer. Googling for how to extract it, I found this Stackoverflow article. The accepted solution in the Stackoverflow article describes how to find the image markers etc. and this means this can be done manually with a hex editor. But actually the second answer is much better for us; it says to use the tool exiftool. The parameters are also nicely given already:


extracting the thumbnail
Looking at the extracted image, we can already see the flag:
Windows Explorer with our flag
Only writing this write-up, I noticed that this challenge is a bit more complicated and I was just a bit lucky here. The Stackoverflow article (second answer, the exiftool command) has a comment that you should actually use a different command to extract all the thumbnail images if there are more than one. If we do that, we indeed get two thumbnail files:
better extraction of all thumbnails
2 extracted thumbnail files
The first file "PhotoshopThumbnail.jpg" is the correct Thumbnail image belonging to the original image. The second image is the "pointing finger" image that we already saw above. So both are not the flag what we were looking for.
But we can do the same again. As these are normal JPG images, they could also contain thumbnails again. And indeed, the second one does contain another thumbnail:
extracting the thumbnails of the second thumbnail
thumbnail of the thumbnail was extracted
And this is the file:
thumbnail of the thumbnail
So in this challenge there were some additional challenges built-in. The first thumbnail was the correct one and only the second one was the hidden data. And in the second one there was a pointing hand, but no flag. The flag was in the thumbnail of the second thumbnail. I didn't notice all that during the CTF, because I exiftool with the default command extracted the second thumbnail that we wanted to look at, and the flag was presented in Windows Explorer, because it renders the thumbnail per default. Seems that I was a bit lucky, but I also learned something for future CTFs now.

Dr. Kyberzig strikes back!

Dr. Kyberzig strikes back!
"Impressive... most impressive. You have successfully cracked all previous Dr. Kyberzig's key validators. But now he has a brand new site with anti-cheating technology to make your job harder. Can you still crack it? https://dr-kyberzig-943d53dnpp.now.sh/"

Here are the files from the Kyberzig challenges 1-4, compressed (7z format) and converted into base64.

If we open that web page and then open the debugger, the execution is being stopped by a function calling debugger, which acts like setting a breakpoint. This does not happen when we close the development tools. So there is some anti-debugging built-in and we need to find a way to remove this. In order to comment out this function, we need a way to change it. So I copied all files locally (with IE, which copies all dependent files and modifies any references). I also ran the JavaScript file through jsbeautifier to have it nicely formatted (without the need to rely on Chrome to do that every time). When we now open the web page locally, we get another anti-debugging feature presented. It shows a friendly box "illegal hacking detected" for a few seconds and then redirects to Google.
Thanks to this friendly error message, we can search in the JavaScript file for this error message and immediately find it:

source code for hacking detection
What we see there is that at the top the value "hackingDetected: !1" sets the value to zero (false) as initial value. In the key "hackingDetected" there is this error box, a setState hackingDetected: !0 (which sets that status to true / detected) and a redirect to Google after 3 seconds (3e3 milliseconds). In this block we also find a hostname.endswith(".now.sh"), which is probably the detection, because when we run it locally, we use a different hostname. So let's patch this:



patching the hostname detection

And we also need to patch the breakpoint falling into the debugger (at the end of the js file):
path to fall into the debugger all the time
If we run it now, we don't get any error messages or redirections anymore. But in the Chrome console, we see another error message:
console errors
The second error is the missing favicon.ico, which can be ignored. We could also copy the file from the production site to the local site and update the link in the main.htm page from <LINK href="/favicon.ico" to <LINK href="favicon.ico", so that the file can be found. But the first error is more interesting. It looks like some "ServiceWorker" doesn't work. Luckily Chrome displays the exact location of the error and clicking there shows the function:
source of error during service worker registration
Debugging this shows that this is less an anti-debugging feature, but probably more a bug in the code. The code "new URL("", window.location).origin" at the top should return something, but actually it fails with returning null.  I simply patched this by setting the URL to the value of the original site:
patch for service worker URL
Additionally we see just a few lines below that there is another check to verify if we are running locally:
code for localhost detection
During the CTF I also patched this, but if you look at the code carefully, you'll notice that it's not in use. The variable "a" is a local one and just after that statement the scope of this variable ends. So it cannot be used anywhere.
So now everything should be patched and working and we can start debugging this thing.
If we run it and enter some characters into the input field, we get some strange math values in the console log:
math values in console log
Maybe the authors used this while writing the code? If we jump to the location, we are again in our validateKey function, which is anyway the code we want to look at closer.
The most interesting thing there is probably the call to window.v(r) which controls the this.setState(), which is later used to set the key to valid or not. So let's set a breakpoint there.
location of our breakpoint
If we debug this now we notice that the value in "r" is the text that we entered in the input field. The function "v" evaluates correctness and then sets the "valid" state. So let's just single-step into that function. The code there seems to be heavily obfuscated, but after just a few steps, we can already see this:
showing the flag in the debugger
So there it says "DR KYBERZIG WILL PREVAIL AGAIN". Let's remove the breakpoint and try it out:
So this works and it is the correct flag.

Password checker II

Password checker II
"Can you figure out the password? The binary file should work in 64-bit Linuxes. http://sec-mooc-1.cs.helsinki.fi/password-checker/435ic821/PasswordChecker_d"

If you download the file (link here as base64 encoded on Pastebin) you get a Linux binary. I was a bit reluctant to install Linux, so I wanted to use other methods. If we open the binary in BinaryNinja and go to the main function, we see this:
Password checker II in BinaryNinja
We can see that there is a call to b64_decode (base64) and there is some comparison with the text "Q29ycmVjdFBhc3N3cmREQUZB". Without reading the code any further, we'll use an online base64 converter and get this:
And this is already our flag, "CorrectPasswrdDAFA". I think during the CTF I didn't even open any disassembler and already found that string in the hex editor, which yielded an even faster result.

In-laws of cyber monkeys

In-laws of cyber monkeys
"One of our cyber monkeys got a cipher text from his in-laws and cannot read it. Can you crack this ciphertext "Xli jpek mw xli jsppsamrk fererew evi gliet erh ejjsvhefpi"?"

This looks again like rot13, but it is not. The page rot13.com can be used for that. Luckily this web page has a nice dropdown, so we can try out other shift values too:
rot22
We see that that it is the same cipher, but with another shift, rot22 and the decoded message is "The flag is the following bananas are cheap and affordable". So the flag is just the last part "bananas are cheap and affordable".

Perfect encryption scheme?

Perfect encryption scheme?
"Our advanced cyber monkeys have invented an encryption scheme that's supposedly impossible to crack. Can you prove them wrong? "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 00001 00000 00000""

So there is some code that needs to be cracked. The first idea is that this is binary with ASCII values. But as there are zeroes of different length and other things that wouldn't make sense in binary, this can be ruled out quickly.
The next logical thing to try would be Morse code. I looked up the wiki page for it and found that it doesn't give any useful results; there were even codes that didn't match any character. So it was not Morse code.
Then I didn't know any further and gave up for the day (having solved all other "Medium" challenges and opened up the "Hard" ones already. The next day during work I thought a lot about this code. My next guess was that it's something like RLL or MFM or something like that, but I couldn't get anywhere with that either.
I then thought more about this and as the codes or letters were all a different length, I thought it must be something like a Huffman coding (which is actually not wrong). At that time someone already spoiled in the chat that the solution starts with "THIS". I already knew that if it is a Huffman code, that there must be some association between the digit groups and the letters. So even if I don't know the code exactly, I can always do some association. So I started with the "THIS" and quickly got "THIS IS THE VERY SECRET..." Unfortunately I didn't get the rest. So I googled more fore the code and found this challenge from Kevin Mitnicks book (Chapter 17). The code described there is Morse code with alternating bits. I tried to apply the same for our challenge and found out that I must have done something wrong initially, and it was simple and plain Morse code.
I decoded this manually by using the code from Wikipedia, but there are also online tools available (just replace the 0 with a . and 1 with a - first):
online decoding
So the flag is thisistheverysecretmessageflag455.

Hashing

Hashing
"Real hash functions are harder to crack but can be achieved with brute force of your own or someone else's. "5ed3a1b239f5689c4a6c773e204534d8""

So there's some hash of a password or something that is to be cracked. Let's try some online tool. I used Crackstation and it immediately found the hash:

Using on online hash lookup
So this is an MD5 hash that maps to the password "ilustred". This is also our flag.

Cyber monkeys' better encryption scheme

Cyber monkeys' better encryption scheme
"Our cyber monkeys try to be clever and invented a better scheme for encryption. Or did they? Can you prove them wrong? Ciphertext: "zzs dz dpncpe esle nlyyze dlj te qwlrczepwpgpy""

This looks again like rot13, but it is not. The page rot13.com can be used for that. Luckily this web page has a nice dropdown, so we can try out other shift values too:
rot11 decrypted
Actually I don't know why the organizers have chosen to duplicate this challenge. It is pretty much the same as the above "In-laws of cyber monkeys". So anyway, we've got our flag "flagroteleven".

Password expiration policy

Password expiration policy
"Charles's password is longlivethequeen2000 and the hash value of that password is '074ae09f55459c6698768ad38d36c360291102ba'. Charles changes his password, but keeps the beginning of the password the same and only changes the four numbers in the end into other numbers. The hash value of the new password is "783679aaebe5fbae5f4d7e2330698d543bdd153d" What is the new password? You should start from finding out What hash function is being used."


From the length and through a quick test we find that the given hash is SHA-1:
online tool for hash generation
As we cannot look up the given hash anywhere, we need to find another way. Last year this same challenge was presented and I solved it by creating 10000 files through some code, all with the content of "longlivethequeen" and then four digits from 0000 to 9999. I then ran a tool for calculating the hash value for each file that it wrote into a text file that I could search for the wanted value. This year I didn't want to write any code, so I thought I use a real hash cracker tool, so I downloaded hashcat and read through the documentation. First I thought I could just use a word list file with just the word "longlivethequeen" in it and apply some default rules. This didn't work. After some digging through the documentation, I used the command: "hashcat64 -a 3 -m 100 783679aaebe5fbae5f4d7e2330698d543bdd153d longlivethequeen?d?d?d?d" which gave me the wanted result:

hashcat in action
So we find that the hash matches the text "longlivethequeen5624" and this is our flag.

Hack a bank

Hack a bank
"The marketplace in CyberBank (https://cyber-bank.testmycode.io/) has information for sale that your 'friend' requires. Sadly, you lack the necessary funds to acquire this information. Use your hacking skills to obtain more currency and obtain the information."


This is the same online banking application as the earlier banking application (Admin panel). Now that the "Medium" challenges are open, you can now log in (with your TMC account). There is a page with "Recent transactions" and it shows that you own 1000.00 Euros. In the screenshot below you see a different value, because that's after playing the CTF.
Cyber Bank, Recent transactions
There are some pseudo transactions, but nothing else interesting except the amount that you own.
Then there's a page where you can convert the Euros you own to some cyber money:
Cyber Bank, Convert page
Converting cyber to Euros or vice versa can be done here. The input is limited to two digits and the conversion rate is shown. There is no fee for the bank. The tricky thing is that you don't see the transaction you made, so instead just your Balance will be updated. If you don't write down before and after the transaction, you don't know the amount changed. The conversion rates are correct and 32.00 Euros are 1 Cyber. The rate for the other conversion though is that 1 Euro converts to 0.03125 Cyber, but as you only get two digits on your account, there is some rounding required. If you can manage to get the rounding in your favor, then we win. A quick Excel sheet shows the best strategy:
Excel with win strategy
So the least amount to spend to get the maximum profit is 0.16 Euros, where you win 0.005 Cyber. Actually I found that sometimes 0.16 Euros gets rounded down to zero, but 0.17 Euros always worked.
I already noticed that this is the same or similar challenge as last year, but I didn't want to look up what I did last year. I simply used Burp to move the conversion of 0.17 Euros into Burp's Repeater (Burp Free Edition is sufficient) and after some minutes of converting (I also increased the number of threads to the maximum allowed), the bank account balance increased significantly.
After reaching 1200 Euros, I could go to the Marketplace page and buy that special product.
Cyber Bank Marketplace
After buying this product, we get the flag: "totallywronghorsebatterystable".

Dr. Kyberzig: Last stand

Dr. Kyberzig: Last stand
"Dr. Kyberzig has created yet another key validation tool that should have perfect security. Can you beat the odds and crack it? https://dr-kyberzig-last-stand.now.sh/"

Here are the files from the Kyberzig challenges 1-4, compressed (7z format) and converted into base64.

There were many hundred people participating in this course, 134 users solved the Stegosaurus II challenge, but this one was solved only by 6 people and the first solver took 3 days. This tells a lot about the difficulty of this challenge.

The challenge is similar to the previous Dr. Kyberzig challenge. There is an input field where you have to provide the correct password and somehow in the code there is a verification. The JavaScript is minified and has anti-debugging features. The most interesting code is heavily obfuscated and some code is dynamically generated.

In order to debug this thing, we had to apply the same techniques as previously used with the "Dr. Kyberzig strikes back!". I won't describe this here again, so please read the above one first. So I also here made the following changes:
  • beautified the js code
  • fixed link to manifest.json in htm file
  • fixed link to favicon.ico in htm file
  • call to debugger commented out
  • comparison for hostname.endsWith(".now.sh") commented out and replaced with true
  • in key: "hackingDetected" removed all the actions (set flag to hacking detected and redirect to Google)
  • The last function in the js file is testing against hostname being local. I replaced this also with Boolean(false), although this is probably never used anywhere.
I noticed that "hackingDetected" gets triggered often when entering two keystrokes consecutively. This is probably a bug in the code, but that's why I commented out the redirect to Google code entirely.

In addition to all the above, I attempted to understand the code a bit. For example there is some code eval(function(e, t, n, r, i, o){...}. This is evaluating (running) the following code (moved out of eval and formatted for better understanding):
one of the obfuscated functions
As you can see there, there is some check and if that fails, it also does an immediate redirect to Google.
As I didn't know what the requestAnimationFrame(loop) function does, I left that one in there and just replaced this whole part with the following code:
replacement code
Just a few lines later, there is another similar code. It also reads eval(function(e, t, n, r, i, o){...}. Debugging this, I found out that this is essentially doing this:
second deobfuscated function
This code runs the "bugFix" function every millisecond. If I remember correctly, then this is the function that is calling the debugger check. It seems that this is not doing anything else, so I simply commented out this entire call.
Looking through the code, I found this variable assignment:
$74 variable
The "atob" function decodes a base64 text. This decodes to "WebAssembly". So they are intentionally trying to hide this. I replaced this line to this:
$74 variable replaced
And all other uses of $74 as well.
Then there is another heavily obfuscated function that looks like this:
another obfuscated function

The string there (cut off in the screenshot) is actually 739674 characters long and many text editors have difficulties with this.
I replaced the above code with this better-looking deobfuscated code:

deobfuscated code
The array of numbers (bytes) I got simply by debugging this code.
Additionally I saved this array of bytes into a binary file, as this is the WebAssembly code.
I never heard of WebAssembly before, so I had to read into this quite a bit. Essentially you can compile C code (or other languages) to assembler (WebAssembly) and let it run within the web page. Not all browsers support this yet, but Chrome does. Chrome also nicely displays the WebAssembly (wasm) functions in the debugger, but stepping through JavaScript calls that step into wasm code doesn't break on the wasm code. If you set a breakpoint in the wasm code, it stops there, but removing the breakpoint doesn't stop Chrome from breaking there until you refresh everything and reload the page and cache. It also often crashes Chrome with the "Ups" message, so that you have to start over again. And in the debugger, the global variables are not displayed, only the local ones and the data stack. The wasm code had over 900 functions in it, so no chance to randomly find the one that is used for verifying the password. I did some stepping through, but got nowhere.

After the first 1-2 users solved this challenge, there was a hint given publicly that we should use some tools for static analysis. So I searched for wasm tools and quickly found The WebAssembly Binary Toolkit. A few days later this link was also posted in the public chat channel. Like many Linux tools, it was quite a challenge to get all dependencies (cmake) and get this code to compile, but I finally made it and got the tools on a Linux VM. I converted the wasm file from the binary from above into C code (see wasm.c and wasm.h), but I didn't get anything useful. It was then also told that the tools do preserve function names, but in the C-code I only saw the external names, which were not helpful. I also converted the code to wat, but didn't see any function names there either. Also the objdump (fullcontents, details, disassemble, headers) didn't help me much. The "canonical" flat format desugar was not much better either.

As I couldn't progress any further - I analyzed this code for many days - there was this public hint from the organizer (Henrik Nygren) where he told me to have a look at the function names again. There should be some hint in the function names that would simplify debugging. So I started with the wat file. First I renamed all the __extjs_xxx functions with the names from the JavaScript code. These functions in wasm are actually implemented in JavaScript and there is some mechanism for calling JavaScript. So for example I replaced __extjs_9f22d4ca7bc938409787341b7db181f8dd41e6df with __extjs_increment_refcount, which is much more helpful in understanding the code. After replacing these 10 names, there wasn't much change. So I started commenting the validator::validate function, as this had the most promising name. There was another function called main::validator though, but I had to start somewhere, so I started commenting it. That was a bit difficult on paper (editor actually), so I started looking at this with the debugger.
Just the validator::validate function was quite big (several hundred lines of WebAssembly), here is an example of how this function looks like:

WebAssembly (excerpt) of validator::validate
What is clearly visible is the call to a function called $md5::Context::compute. So would there be some MD5 code computed? That would mean that the password is not visible anywhere in clear text.
I got some more hints for debugging this big piece of junk: The "blocks" above are actually not loops, but more like coding blocks for scope. And the C-style function memcmp above is something I should take a closer look at.

Debugging this function, I noticed that the input password gets MD5 hashed, but the memcmp function is not comparing the hash. The memcmp is comparing 32 bytes and there is a lot going on in those loops or blocks or whatever that is there. I didn't understand all this, until I noticed what this all is. There is a conversion from binary MD5 to hex (ASCII) being done and the memcmp compares the hex (ASCII) converted strings!

Here's the critical point in JavaScript where the whole wasm code is called:
Chrome debugging wasm
So after finding the correct unnamed wasm function in the Chrome debugger, we set a breakpoint at the comparison:
Chrome debugging hash comparison
You can see there that on the data stack there are three values:
  • 262456
  • 262408
  • 32
This means that we compare 32 bytes from these two addresses. The first one (262456) points to the MD5 hash of our input string and the second pointer (262408) points to the hash we want. Looking this up in the data:
Chrome wasm memory view
MD5 hex ASCII password in memory at 262408
So I wrote down these values (55, 54, 102, ..., 100, 102, 101) and manually converted these ASCII values to characters. This resulted in the string 76fdfc268c2ce4fed988e977fb2cfdfe.

So now we "just" had to crack that MD5 hash.

Unfortunately all tools I tried didn't work:
  • Google search
  • https://crackstation.net/
  • http://reverse-hash-lookup.online-domain-tools.com/
  • https://hashkiller.co.uk/md5-decrypter.aspx
  • http://md5.my-addr.com/md5_decrypt-md5_cracker_online/md5_decoder_tool.php
  • https://isc.sans.edu/tools/reversehash.html
  • http://www.md5online.org/
So I already thought I had to crack it myself, but then this would probably not be adequate for such a CTF. After some more Google-foo, I found the site http://crackhash.com/, which had the hash in its list:
crackhash.com

Trying this password with the original site also works:
Correct password
And this (flaghunter) is our flag.

This challenge was really challenging to me. I thought I know JavaScript, but a lot has changed since the old Netscape 4.03 days. I now know in what areas I'm lacking knowledge:
  • fully understanding Promises
  • Closures
  • Ant framework
  • React framework
  • WebPack require
  • Babel runtime regenerator
  • WebAssembly (done)

Stegosaurus V

Stegosaurus V
"Something is not quite as it should be in this image. Can you find it? http://sec-mooc-1.cs.helsinki.fi/stegosaurus/5o3/stegosaurus05.jpeg"

This is the downloaded image:
stegosaurus05.jpeg
The first thing you notice is that this file is quite small, only 14KB, so hiding information in there is a bit difficult.

First we find that again the thumbnail image isn't matching and contains a different image. We can extract that as in the earlier challenge with the exiftool. We get this image:
Thumbnail of the stegosaurus05.jpeg image
The text says something like "Alm0stButN0tQu1t3", with some exchanged letters. As we just see the image, we are not sure if the second letter is a lower-case "L", the digit "1" or the upper-case "i" and similar problems with other characters, but we could guess.

So I thought that it might be some password-protected hiding with the tool steghide, which was also used last year. Last year there was a problem that the Windows version of the tool didn't work, but someone mentioned that there is an online version of steghide, so I tried that. No luck there. I now know that I typed in the password with some wrong letters, but it wasn't the solution anyway.
So I googled around a bit and stumbled over this write-up of a CTF stego challenge. While our challenge is completely different, it did mention the tool Stegsolve, which I then also tried. This is a very nice tool indeed and it displayed the following information:
Extra information found in the image
So it found additional bytes in the image after the end of the file. If we scroll further down, we can already see what it is:
Showing that the extra information is a ZIP file
So we see that the additional bytes are actually a ZIP file (ZIP files start with "PK"). So I copied this data out of the tool (or with a hex editor, I don't remember) and had the ZIP file. In order to extract the only contained file "foo", we had to provide a password, the password from the thumbnail above. After trying a few combinations of characters, we find that the password is "Alm0stButN0tQu1t3". Opening the extracted file with Notepad:
extracted file
So our flag is "TadaaFoundIt".

Password checker III

Password checker III
"Can you figure out the password? The binary file should work in 64-bit Linuxes. http://sec-mooc-1.cs.helsinki.fi/password-checker/c4324/secret_c"

So I downloaded the binary (here base64 encoded) and opened it in BinaryNinja. Here's the main function, already with some comments I added:
Main function in BinaryNinja
There we see that there is some separation between good and bad and then in the "good" case, there is some magic going on and the flag printed out. I couldn't quite understand the logic there in detail, so I thought I need to debug this. So I installed a Linux VM (Kali provides a VM ready for use) and I started debugging it with gdb. There might be better tools, but I'm not familiar with them. Please suggest me something if you know about some good debuggers.

Anyway, the first thing I tried was to manipulate the jne instruction that differentiates between good and bad, so that the execution jumped to the "good" path, even with a wrong password. That didn't work out as intended and just gave me a wrong result.

So I had to document this code a bit more and I found that in the top block a random value is generated, which is stored in [rbp-0x28] and then the user has to enter a password, which is converted into a DWORD with atoi and then both values are compared. I'm not sure why this random input is required for giving the correct result, but with this knowledge I could influence the execution. These are the commands in gdb that I had to issue:
  • gdb
  • file secret_c
  • break main
  • run
  • layout asm
  • break *0x400891 (just after the rand call)
  • continue
  • (enter some user name)
  • info registers
  • (rax=0x503aa9f6 1346021878, a different value each time)
  • q
  • continue
  • (enter the password 1346021878 from above)
  • (We get the output "secret flag is Flag4537".)

Stegosaurus VI

Stegosaurus VI
"Something is not quite as it should be in this image. Can you find it? http://sec-mooc-1.cs.helsinki.fi/stegosaurus/6fvnr54/stegosaurus06ar.bmp"

This is the image:
stegosaurus06ar.bmp
We already notice that the file is quite large - it's a bmp file with 41MB in size. There was a similar challenge last year, so we use this knowledge and solve it with zsteg:
Running zsteg
And there we already have our flag "Randompart347856Flag".

Password checker IV

Password checker IV
"Can you figure out the password? The binary file should work in 64-bit Linuxes. http://sec-mooc-1.cs.helsinki.fi/password-checker/l43f4/PasswordChecker_l"

So I downloaded the binary (here base64 encoded) and opened it in BinaryNinja.
Actually here a static disasssembler failes. There were many things built-in, like jumping to a subrouting and in the subroutine as first thing was that the return address was removed from the stack, so that it will never return and other nice obfuscations. I debugged this code for several hours with gdb until I remembered that last year there was a similar challenge. Could this be the same again? Yes, this file was simply UPX packed! A Linux command line tool unpacks it and returns the unpacked executable. Looking at this unpacked executable again, we now have a much nicer picture in BinaryNinja:
View at the unpacked binary
And there we already see our flag; "CorrectPasswrdABBAB".

***

Comments

Popular posts from this blog

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

Insomni'hack Teaser 2018 CTF