Over the past few days, my team and I participated in Redpwn CTF 2019. We came out fourth and we enjoyed the experience.
As in almost any CTF, some challenges were good, and some consisted purely on guessing. I will present only the challenges that I helped solve, however, I must say that my teammates contributed a lot, as this CTF was a team effort.
The words ‘really short’ hint us that we can bruteforce the hashed string. We can make a simple Python script that does exactly that:
My script was a bit too complicated, as the hashed string consisted of only one character:
Flag: flag{^}
Trinity – Cryptography
This was one of the most frustrating challenges. My team and I tried some very complicated stuff and failed to solve the challenge. 12 hours later, less than an hour after the hint was released, I finally figured it out. The ciphertext was actually Morse Code, 0 represented a dot (.), 1 represented a dash (-) and 2 a space.
After getting the flag in Morse code, we can just use an online converter like this one.
The binary text does not fit in the challenge box, so let me turn it into text for you:
Let’s connect to the service and see the output:
That’s a lot of 1s and 0s! Let’s convert some of the lines to ASCII:
The first line translates to “ultimate encryption service”
The second line decodes to “WARNING: I only say 0 or 1”
The third line starts with “(N, e): ” and is followed by a RSA public key pair that changes every time we connect to the service (actually, only N changes. e is always 65537)
The fourth line starts with “ENCRYPTED MESSAGE: ” and is followed by a number, probably the encrypted flag.
We can also submit some numbers in binary and the program will return either a 0 or a 1. After the admins fixed the challenge (at first it didn’t always give the correct output), we immediately figured out it was an RSA LSB oracle. You can read more about it here.
The script to check if the service is an LSB oracle:
Script that gives the flag:
In order to get the flag, the script needs to get the output of about 1024 numbers, so it might take a while until it finishes, depending on the server’s speed.
I honestly don’t know if this is the intended solution, but it worked for me. The key is to see that the makeId() function doesn’t make a random id:
This means that we can call /api/flag with incrementing user ids until we get the flag:
I do think there’s a more clever way to do this challenge, but given that it has 100+ solves I assume that most players used this method.
Flag: flag{th3_AdM1n_ne3dS_A_n3W_nAme}
Blueprint – Web
The following piece of code is vulnerable:
Note that _ is actually the lodash module. The thing is that this module is outdated :
The server is using a version of lodash that is vulnerable to prototype pollution. This means that we can manipulate the properties of all the user’s blueprints. Read more about it here.
The following script will make all of your blueprints public (including the one that contains the flag):
After you run the script, just access the site and get the flag:
The zip file contains 2 files: a .png that contains pixel values for an image with a word and a password-protected zip file that contains the next 2 files. The password for the zip file is the word in the picture. I used an OCR, but sometimes it would fail, so I had to write about 100 words to get the flag. (you needed to unzip 1000 files)
This final script:
The script is a bit messy, but it works.
Flag: flag{th3s_1s_tru3_d3d1cAt10N!!!}
genreicpyjail – Misc
One of my teammates got the flag 1 minute before I solved the challenge. His payload is pretty simple to understand:
My payload also works:
Flag: flag{bl4ckl1sts_w0rk_gre3344T!}
genericpyjail2 – Misc
This time, I told my team I was working on this challenge. The final payload:
Flag: flag{sub_sub_sub_references}
He sed she sed – Misc
This was a simple command injection challenge.
Flag: flag{th4ts_wh4t_sh3_sed}
expobash – Misc
Fishy is trying to hack into secret government website! The 10 digit passcode is very secure, but in order to generate the passcode, a secret algorithm was used. Fishy was able to figure out the algorithm, but he doesn’t know how to calculate the passcode quickly? Can you help fishy calculate all the passcodes?
The algorithm for the password is as follow: There are 2 arrays given to you of length n: a and b. For each subsequence of a that can be created by deleting some (maybe all) of the elements a, we calculate the value of the subsequence by taking the XOR of the ith element of subarray with b[i]. Your goal is the find the last 10 digits of the sum of the values of all possible subsequences of a.
At first, this seemed like an easy coding challenge. However, the dataset had n=50, so generating all subsequences and calculating the required sum won’t work. It was clear that I needed to discover a rule between the ith element of a XOR the jth element of b and its coefficient in the sum. To do this, I first named the elements in a 101, 102, … and the elements in b 201, 202, … . After that, I made a simple script that would show the coefficients of a[i] ^ b[j]:
We pass n as an argument when we run the script:
It didn’t take me very long to find the rule. The first line always consists of 2 ^ (n – 1) and then n-1 0s. To generate line number x, we use the formula a[x][i] = a[x – 1][i – 1] / 2 + a[x – 1][i] / 2. I don’t know if this is a well-known formula; I discovered it during the CTF by myself.
The script that solves the challenge:
Flag: flag{c4n_1_h4v3_4_c0mb_pl0x}
Conclusion
Overall, this CTF was ok. However, I have 2 suggestions for anyone who wants to organize a CTF competition:
DO NOT publish untested challenges. I understand, mistakes happen. However, when you publish MULTIPLE unsolvable challenges, it starts to annoy players.
If a challenge is unsolvable, even if you can’t modify it, at least tell everyone on the Discord channel so they don’t loose their time trying to solve it.