As the title hints, the solution involved using the ‘strings’ program on the given binary:
The -7 switch tells the strings program to only print words longer than 7 characters. Also, | head -n 24 just limits the amount of results that are printed on the screen(in this case, 24).
I could see parts of the flag, but I didn’t want to manually concatenate them. I remembered the executable asked for a password, so I ran it again and used ‘parola12’, which I also found in the program’s strings (the word ‘parola’ means ‘password’):
The players were also given an executable named ‘chall’ and a address that was supposedly running the challenge on a server. The binary simply asked if I had ‘control’:
I tried to overflow the buffer, but the binary wasn’t vulnerable. I also tried a format string attack, but that didn’t work either. To solve this challenge, I needed to open the program in IDA. The following image contains a part of the reassembled ‘main’ function:
I only tried the format string attack the first time I was asked for input! Knowing that the third answer will use printf with my input as the first argument, it was trivial to leak bytes from the program’s memory:
I used the folowing python script to exploit the format string vulnerability on the remote machine:
I didn’t know exactly where the flag was located, so I waited for the script to print some hex values that might decode to valid ASCII characters.
Offsets 136-153 seemed promising, so I decoded them and got a string that resembled the flag:
I’m still not sure what the role of those ‘X’ characters is, but removing them from the string produced the valid flag.
A web challenge! As always, it turned out I overcomplicated things. After making an account, I had the option of sending messages to admins:
Everything hinted at an XSS, so I entered <script>alert(1);</script> and clicked the submit button. As expected, the javascript code was executed.
This was the part where I got stuck. I managed to exfiltrate data from the admin’s browser, but I couldn’t get the flag. The flag, as it turned out, was in the User-Agent header. My final payload:
The request from the admin’s browser looked like this:
A great web challenge. Acessing the site with my browser only returned APIv2 @ 2020 - You think you got methods for this?, so I tried making a POST request with curl, saving the output to a file, and opening that file with my browser:
The new output offered a lot of information. First, the web app was powered by Flask. The server was using python 2.7 and a part of the app.py file was visible in the traceback:
My solution involved exfiltrating the flag character by character by raising an eception if the characters don’t match - like a blind SQL injection, but with pickle & python. To get an idea of how overcomplicated it was, here’s my original Exploit class:
After the competition ended, I found out the reason the number of solves was so high for this challenge: the flag could be obtained by simply acessing /flag. Since I solved this challenge the intended way, let’s suppose you don’t know about the file mentioned above. Here’s the source code of the index.php file:
The vulnerability was pretty easy to spot: the script uses escapeshellcmd whereas it should be using escapeshellarg. While I couldn’t directly execute other programs, I could pass other switches and arguments to find. Having used this program a lot, I already knew it had an -exec switch. Here’s the manpage in case you don’t know what it does already:
Basically, passing *%20-exec%20cat%20flag%20; (urldecoded: * -exec cat flag ;) to arg will output the flag a few times:
The problem, however, was that the output is encoded to base64 and then passed to strtoupper. I made the following script that attempts to decode the uppercase base64 string:
Each time the program asks you to choose between some strings, choose the one that starts with the longest valid string (keep in mind that the only allowed characters between ctf{ and } are 0-9a-f)
socat - the CTF player’s worst nightmare. There was no attached file, so I connected to the specified host with nc and played with the input until the program crashed:
The error suggested that the program was asking for a range. Entering 1 and 100 would print You can not read more then 10., so I entered 1 and 10 and got the following output (non-ASCII characters replaced with X for convenience):
The output looked like a png header, so I made the assumption that the program prints the bytes of an image file at offsetd start..end, where start and end represent the numbers entered by the user. Before showing you the script, there’s 2 things you need to know abou socat:
in this case, it appended ‘\x89’ before the bytes in the file
it tranforms ‘\n’ to ‘\r\n’
The ‘\x89’ byte is, however, the start of the PNG file signature, so my script had to add it automatically at the start of the file:
After about 5-10 minutes, the program extracted an image that contained a QR code. The QR code decoded to asdsdgbrtvt4f5678k7v21ecxdzu7ib6453b3i76m65n4bvcx, which is the password that unlocks the flag:
With no binary to download, I used nc to connect to the provided ip and port and started testing the service:
The hex string entered is different for 2 different inputs, but it does not change from session to session if the word entered remains the same. It’s also 138 characters long, which is exactly the length the flag would have if viewed as hex. These facts led me to test another string:
The first 8 bytes were 0, which meant that the program was somehow comparing the string entered with the actual flag. The operation could be a simple substraction, a XOR, or a very complicated algorithm, but the important thing was that the first 2*n nibbles would be equal to ‘0’ only if the flag starts with the first n characters of the input. With that information in mind, I wrote the following program to get the flag character by character:
The given pcap contained a lot of UDP packets. However, there were only 138 TCP packets, which was precisely the number of nibbles required to write a flag in hexadecimal. The solution involved treating each destination port as a nibble. Thankfully, tshark could extract all the port numbers without much effort on my part:
The atached file, gogu.exe, was an ELF 64-bit excutable. strings output suggested the binary was a compiled Go program. It goes without saying that the binary was stripped and trying to reverse it using IDA was impossible (for me).
The last hex string looked like a hash, so I thought it was somehow derivered from the flag. I tried to dump the memory of the program before/after the ‘hash’ was printed and then search it using strings and grep:
In case you are wondering: No, I do not know how to actually reverse a Go binary.
The given file had no extension, so I used the file extension to determine its type:
For this particular challenge, there’s no point of walking you step by step through my solving process, so here’s a summary:
Unzipping a file resulted in another archive, eventually leading to the flag. Presumably, the number of steps is too big for the challenge to be completed manually.
There were 3 different type of archives
.gz archives could simply be extracted by using gunzip (no password required)
.zip archives required a password to be unzipped. The password was different every time, but it was included in john’s default dictionary.
.7z archives also required a password to be extracted. This time, however, the password wasn’t included in the default dictionary, so I had to use rockyou.txt.
That being said, here’s my solve script:
When the program above finished its execution, the flag could be found in the archive file.
Before discussing the solution, I have to mention this great article. It basically contains all the commands someone would need to start using volatility.
That being said, my solution had nothing to do with volatility in the end. I just extracted the strings of the given memory dump (using strings, as well as strings -e l and strings -e b), opened the resulting file in sublime and started searching for the password.
After several hours of searching (and about one hour spent using volatility), I had a pretty good idea of what happened on the victim’s computer. Basically, the victim logged in on gmail and then downloaded a malicious file (ire.dmp.2032.rar.txt.pdf).
There were 2 likely locations for the passwords:
The malicious program’s memory, if the image was taken while the program was being executes (this wasn’t the case)
Chrome’s memory, because the user logged in using Chrome.
I tried to sign in on Chrome on my own machine and took note of different kinds of information about the page, such as text, url, and the password input’s id. Searching the file for the latter revealed the victim’s password: passwordflagwin. The flag is ctf{sha256('passwordflagwin')}
So, to sum this challenge up: strings e.bin | grep password | grep flag
After trying several steganography programs, the solution turned out to be quite simple. I opened the rain.wav file in Audacity and changed the view mode to ‘Spectrogram’. I then opened the Spectrogram Settings menu and tried several numbers for window size, eventually setting it to 4096. After zooming in a little bit, this is what the spectrogram looked like:
In case you can’t see it, the graph reads ‘Secret Code: spectrogram’. The flag is ctf{sha256('spectrogram')}.
This was definetly one of my favorite challenges. Here’s the source of the script that generated enc_message:
To retrieve the flag, I needed to reverse all 4 enc functions. Don’t worry, though - it’s not as complicated as you think.
The first function, enc1, takes a key of type int and arranges the characters of msg in a matrix, calculating the cipher variable by reading that matrix row by row instead of column by column. Truth is, you don’t need to know all of this. The only important information is that the function scrambles the characters of msg in some way. A clever way to reverse it is to call enc1 with a msg equal to '\x00\x01\x02...' and to use the resulting scrambled string to decrypt the real message. As the enc1 function does not take the characters of msg into consideration when scrambling them, the resulting permutation will be the same for all strings of the same length.
The enc1 function also pads msg with 'z' characters at the end, so the decryption function should strip them away. The dec2 function is just a pretty Caesar cipher implementation:
To obtain the decrypted string, we should just call the encrypt function again, this time with a key of 26 - (key % 26):
I will now skip to enc4, because enc3 is a bit trickier than the rest and needs more explaination:
As you can see above, enc4 is just an implementation of the Rail fence cipher. I could write a decryption function for railfence, or I could use the fact that this function also generates a permutation of the plaintext characters that is based only on the length of the plaintext and the key. That being said, the dec4 function is almost identical to dec1:
The major difference is that instead of calling enc4 with text='\x00\x01...', I call it with text='\x11\x12...'. I do this because the enc4 function strips all '\x10'='\n' characters.
Here’s my full ‘solve.py’ script:
I do share the same beliefs as the author’s father, but, unlike him, I use secure encryption methods.
I honestly have no idea what you’re doing here. Really. The writeup ended few lines before. However, since you’re already here, I can’t end this post without bragging that I’ve solved all the challenges publishing a part of the scoreboard and congratulating everyone that participated in the contest.
now please excuse me but I have to prepare my scholastic personality for an assessment test