Schwenk and pwn

HITB Lockdown CTF 2020 - pfs

Disclaimer: Both of us are not familiar with Ruby.

Service overview

This service was a web service written in Ruby with a small Perl Web server to serve the functionality. It was straightforward: one could store some data and retrieve this data again. Storing was performed by issuing a PUT request to /<path>. The HTTP Body was the data to be stored, and the path acted as the identifier to retrieve the data later on. A GET request to /<path> retrieved the data again. The game server stored flags in random paths following the pattern [a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}.

Exploit 1: SQL injection

Looking into the ruby file, one notices that this is mainly database interaction, but in a FuseFS class. FuseFS seems to translate database actions to the file system. The PUT request created a new file in the pfs-data directory, and the GET request read this file again. The next interesting thing to notice is that the SQL statements use something that looks like a concatenation syntax and an “exec” statement. This strongly indicates a SQL-injection vulnerability in the path, as every method in this class receives the path as a parameter.

We tried a to check for a SQL injection with injecting a ' as breakout for the SQL string and it resulted in an internal error on the stdout of the docker. The only challenge left was to create an injection via the path that produces no error in the SQL queries before the read but actually leaks the flag during the read function. We came up with the following exploit:

i = 0
while True:
        r = requests.get(f"http://{target}:3000/anyfile\' OR path LIKE '%-%' OFFSET {i} -- a")
        if r.status_code >= 400:
        i += 1

Due to the path being used in every SQL statement on the server-side we used OR path LIKE '%-%' to select all Gameserver entries. Because only the first row from the QuerySet that was returned by the Database is actually sent as a response, we used OFFSET i to iterate over all flags.


Replace the relevant SQL queries with a prepared statement (see documentation).

Exploit 2: Path traversal

In theory, we could include ../ in the path to read other files in the system. We thought this could be used to leak a log file where the docker stdout is present. The Ruby script printed out the name of the accessed “files” to its stdout, which is redirected to the docker stdout. This would leak the paths that the game server used to store the flags, which would enable us also to retrieve those flags. However, we were unable to come up with a file that contains this information, rendering this vulnerability useless in this case.


As we did not find a way to exploit this, we did not bother fixing.