Home GitHub Twitter
31 December 2019

36C3 Senior CTF - SQLi through file metadata to PHP RCE - file magician

by Xh4H

Challenge description

Difficulty: easy (133 solves): round(1000 · min(1, 10 / (9 + [133 solves]))) = 70 points

Finally (again), a minimalistic, open-source file hosting solution.


We are given the following files:

index.php with the code that we will have to analyze, a Dockerfile to set up our service locally, and a folder with required stuff for the said service.

Let’s start by setting up a docker:

echo 'hxp{FLAG}' > flag.txt && docker build -t file_magician . && docker run -ti -p 8000:80 file_magician

Docker is now running on port 8000.

Let’s read the php code now:

The attack vector is in the following line of code:

$s = "INSERT INTO upload(info) VALUES ('" .(new finfo)->file($_FILES['file']['tmp_name']). " ');";

We have to perform SQLi using file metadata. After some research, .gz (gunzip) files have an interesting metadata string that will help us a lot.

Here is an example:

Check how running file over the created gunzip displays the name of the original file between double quotes, which will break the SQL sentence. In the following image we can see in red the double quotes that will break the SQL sentence, in gray is our file metadata and finally in yellow, the previous file name, where will be inject our SQL code.

So, I ran nano over the file and edited the previous file name into my SQLi sentence.

The green marked text is the SQL sentence that I will use to get RCE

My php code will be


Explanation of the code above:

Notice how I am attaching the DB on a file called k.php, if the file doesn’t exist, it will be created on the current directory, which, in our case, is a random folder:

if( ! isset($_SESSION['id'])) {
    $_SESSION['id'] = bin2hex(random_bytes(32));

$d = '/var/www/html/files/'.$_SESSION['id'] . '/';
@mkdir($d, 0700, TRUE);
chdir($d) || die('chdir');

The SQL sentence max char length was 95, so I had to create two different gz, create.gz and insert.gz

In create.gz I attach a new database to a php file and I create a table p with a column d text that will store my php code.

In insert.gz I attach the php sql connection into the newly created database and insert the php code:

We upload both files to the service and access our php file as following:

Click on the second file:

It will bring us to a link like this http://x.x.x.x:8000/files/70d80f242200060e52e596c9a324407287f40456164726b7d1278c06657e2dd1/2

Change the last 2 with k.php and we will be able to execute PHP code using the


that we placed before, as we will be accessing a php file that will be executed by the server. Use j as url parameter to execute any command within the host system.


In order to find the flag, as it was generated with random chars in its name, we can use * to expand chars over a file on the system such as cat /flag*:


Flag: hxp{I should have listened to my mum about not trusting files about files}

Thanks for reading :)

tags: 36c3 - senior - ctf - file - magician - file_magician - sqli - sqli_injection - php - php_rce - rce - remote - code - execution