FCSC Prequals 2020 - Bestiary
Web challenge of the annual CTF organized by the ANSSI, where PHP sessions can be used to perform a LFI.
This CTF is run yearly by ANSSI, in order to get 30 people qualified for another (shorter) CTF. The winners will play the ECSC CTF in Viennes as part of the official French team.
I didn’t manage to be qualified, but I played this CTF because the challenges are always very fun and their goal is to learn you something.
Here is my writeup for a web challenge quite easy to solve, but which taught me a really nice technique to perform PHP code injection from a local file inclusion vulnerability.
We just ask you to find the flag.
URL: http://challenge2.france-cybersecurity-challenge.fr:5004/
Website discovery
When we land on the index page, we see a very minimalist website.
Let’s play its game and select a monster.
Nice! A Dungeons and Dragons theme. But that doesn’t make us omit this GET parameter up there: ?monster=
.
As I always do first, I replace the legit value mind_flayer
by a single quote %27
.
A PHP error betrays the presence of an include()
function called on the monster
parameter value. So this is probably a LFI here.
Before doing more tests, let’s open up Burp Suite which is more convenient for injecting dynamic parameters thanks to its Repeater tab. Then, we try the classic /etc/passwd
inclusion.
The fact that it works instantly tells us that there isn’t anything appended at the beginning or the end of the monster
value, like “file_” or “.php” for example. Therefore we can maybe inject a PHP filter, very useful for obtaining the server’s source code. This payload php://filter/convert.base64-encode/resource=index.php
is a classic one which will output the base64-encoded index.php
page.
Once decoded:
|
|
The goal is to get the the flag.php
file’s content. We could use the exact same technique as for the index.php
file, but here we are facing a constraint: the word flag
cannot appear in URL. Additionally, I tried the wrappers data
, expect
and input
but without success.
LFI exploitation via PHP sessions
By scrolling down PayloadAllTheThings’s file inclusion page, I found something that could be applicable in our case, as it involves PHP sessions to execute PHP code. Maybe not a coincidence, there is a suspicious line session_save_path("./sessions/");
at the very beginning of the index.php
page.
Indeed, in PHP, $_SESSION
variables rely on files to store their content. By default those files are located in the /var/lib/php/sessions
or /var/lib/php5/sessions
directories, with permissions like drwx-wx-wt root root
. So ordinarily, with a PHPSESSID=3a717e2a84b5a538f9d78251b49506c
cookie, there would be a /var/lib/php/sessions/sess_3a717e2a84b5a538f9d78251b49506c
file, but unreadable using LFI.
Here, the session_save_path
line indicates that the sessions files are located alongside the source code. Maybe we can even read them. Besides, according to the line $_SESSION['monster'] = $monster;
, we fully control what is contained in our session file: it’s what we put previously in the ?monster=
value.
Let’s test this by putting a dumb value like ?monster=bouzygouloum
id the URL, send the request, and then try to include our session file, and see its content.
So we effectively can include our session file, and control what is inside, which is passed into an include()
function. Now, the PHP documentation tells us “The include statement includes and evaluates the specified file” => PHP code will be executed if it goes through it.
By knowing that, this PHP code should do the trick.
|
|
So we first send a request containing our URL-encoded payload:
?monster=%3C%3Fphp%20echo%20base64%5Fencode%28file%5Fget%5Fcontents%28%22flag%2Ephp%22%29%29%20%3F%3E
And then include it: ?monster=sessions/sess_3a717e2a84b5a538f9d78251b49506c
And this is a flag
This challenge wasn’t too hard and had a lot of solves, but I learnt that trick which is kind of cool.
Finally, here, system
function was disabled. But if you have access to it or passthru
, etc., you can even achieve RCE from this LFI!