kmh's blog

ångstromCTF 2018

Mar. 22, 2018

I helped organize ångstromCTF this past week, and it was a huge success with over 1,500 scoring teams. Here are the challenges I wrote:

Sequel

This was a simple SQL injection challenge. One of many ways to solve it is using ' or 1# as the username. If you don’t know why this works, w3schools has a nice overview.

Weird Message

This challenge gave a single text file, containing a message. From the hint xn--, it could be determined that this was punycode. Punycode can be decoded in Python with:

"<string>".decode("punycode")

When you do this, you find that the part of the message after the last dash has been removed, and the one before it has changed. Since punycode appends a dash each time a string is encoded, you know that this was probably encoded many times. Trying to decode again, however, gives an error because of unicode characters. Upon further inspection, the end of the string now has homoglyphs. Replacing these with the similar ASCII characters, the string can be decoded again. However, since there are about 200 dashes, the string was probably encoded 200 times. Decoding by hand would take a very long time. Luckily, this is not too hard to automate. You can either build up a mapping of homoglyphs to regular characters manually, or use a prebuilt list like I did.

After decoding fully, you get the flag.

File Storer

You are given a link to a (incredibly ugly) website where you can create accounts and upload files. However, if you try a common name like test for a file, it says the file already exists! This means all files are stored in the same place. Going a step further, the files may be stored in the same place as the rest of the website. Trying to access files/index.py (it can be determined it is Flask from the 404 page) gives a special message, so there are protections against reading it, but it is confirmed it is reading from the root directory of the website. Through the hint or just knowledge of common web vulnerabilities, one decides to try to access files/.git, and, luckily enough, it says the directory exists.

However, git can not be downloaded the normal way since there is no directory listing. For this, you can either manually reconstruct git from known files or use a pre-made script to do that. Once you have .git, you can checkout the files and see the source of the website.

Looking at index.py, you see a “beta feature” that uses getattr to get information about a user. The user class has two attributes: username and __password. Accessing username works just fine, but the password does not! Why could this be? This is the fault of name-mangling. If you instead access _user__password for admin, you get the flag.

There were also a few unintended solutions involving accessing various files.

The Best Website

You are provided with a seemingly useless website. Upon further inspection, it is a legitimately useless website. However, in the source of index.html you see a comment directing developers to record their changes in log.txt. Visiting log.txt, you see that a super secret flag was added to the database, and there is a timestamp. This will be important later.

Continuing your inspection of the website, you see it makes a network request to /boxes?ids=<id1>,<id2>,<id3>. From either the hint or previous knowledge, you can determine that these are MongoDB object ids. Googling what makes up a MongoDB object id, you find how it is made. The machine and process ID are shared, the counter can just be incremented by one, and the timestamp can be gotten through this useful website (be careful of time zones though).

After reconstructing the object id, substituting it for one of the current ids gives the flag.