Stripe CTF – Level 2

Note: For more information on this series of posts and the CTF exercise, please read the Background section of the first post in this series.

Level 02

Now that we’ve obtained the level02 password, we can login to the server with the username level02. 

Again we browse to the /levels directory and do a listing to identify the files for our next challenge.

We see that the files for our next challenge include a binary entitled level02 and what appears to be a PHP file entitled level02.php.  Based on the PHP file it seems this will involve some sort web attack, but let’s run the binary to see what information we can discover.

Our hunch is correct and it appears we need to fire up a browser and see what we have in store.  But first, let’s take a peek at the source for level0.php. I simply ran the cat level02.php and copied the output into a text editor (below).


<?php
 error_reporting(E_ALL);

 function random_string($max = 20){
 $chars = "abcdefghijklmnopqrstuvwxwz0123456789";
 for($i = 0; $i < $max; $i++){
 $rand_key = mt_rand(0, strlen($chars));
 $string .= substr($chars, $rand_key, 1);
 }
 return str_shuffle($string);
 }

$out = '';
 if (!isset($_COOKIE['user_details'])) {
 $out = "<p>Looks like a first time user. Hello, there!</p>";
 $filename = random_string(16) . ".txt";
 $f = fopen('/tmp/level02/' . $filename, 'w');

$str = $_SERVER['REMOTE_ADDR']." using ".$_SERVER['HTTP_USER_AGENT'];
 fwrite($f, $str);
 fclose($f);
 setcookie('user_details', $filename);
 }
 else {
 $out = file_get_contents('/tmp/level02/' . $_COOKIE['user_details']);
 }

?>

<html>
 <head>
 <title>Level02</title>
 </head>
 <body>
 <h1>Welcome to the challenge!</h1>
 <div class="main">
 <p><?php echo $out ?></p>
 <?php
 if (isset($_POST['name']) && isset($_POST['age'])) {
 echo "You're ".$_POST['name'].", and your age is ".$_POST['age'];
 }
 else {
 ?>
 <form action="#" method="post">
 Name: <input name="name" type="text" length="40" /><br />
 Age: <input name="age" type="text" length="2" /><br /><br />
 <input type="submit" value="Submit!" />
 </form>
 <?php } ?>
 </div>
 </body>
</html>

Looking at this code we can see that it will present a web page with some form of login screen.  The PHP code also appears to be manipulating some sort of cookie file.  Let’s browse to the page and see what it actually does.  After pointing to the initial URL, we’re presented with a basic authorization dialogue.  We know this isn’t the part of the challenge, but rather a measure to prevent users from accessing the challenge who haven’t yet passed level01.

Using the level02 credentials authorizes us to view the site and sure enough we’re presented with an apparent login screen.

Let’s see how the application behaves when entering in the basic information it’s requesting.

After entering in my name and a bogus age, we get this response:

Okay, so this appears to be drawing information from some sort of cookie that identifies who we are and includes our browser information and IP address.  Let’s take a closer look at the code to see where we might identify a vulnerability that we can exploit to extract the password for level03.  On line 37 the page states to echo the $out variable to the screen and then present us with the “login” section.  On lines 15 and 25, we see that $out is assigned based on the condition of a cookie being set with an attribute entitled user_details.

If the cookie is not set, line 15 states that $out is assigned the string stating that we’re a first time user.  It then proceeds to assign a random file name to a text file, sets our user_details cookie with the same file name, and stores the file in /tmp/levelo2/.

If the cookie is set, line 25 states that $out is directly assigned the contents of the file name presented in our user_details cookie.  Hopefully, you can see the glaring flaw in this logic, but notice that there is no sanitization conducted on the file name in the cookie prior to assigning its contents to $out.  The application is simply trusting that the file name being requested by our cookie is the appropriate file stored in /tmp/level02/.  This is a bad assumption, because we can manipulate the cookie and request the contents of any file we would like, provided the user the web server is running as has read access to the file.

So we know where the vulnerability lies, let’s see if we can manipulate our cookie data to request the /home/level03/.password file instead of the random text file.  To do this we will need to use a web proxy of some sort.  I’ll use Burpsuite for this example, but feel free to use any proxy you feel comfortable with.

We fire up Burpsuite and set our browser to send requests through it and proceed to browse to our page again.  Since we’ve already tested the functionality, notice that our cookie is set.

Now here is the excellent part of going through a proxy, we can manipulate whatever data we would like before it’s sent to the server.  So let’s change the file name in user_details to ../../home/level03/.password and see what happens. (Note: we need to insert the ../../ in order to “escape” out of the /tmp/level02 directory.  This is a simple directory traversal technique.)

And voila!  Instead of presenting us with the contents of the cookie file, we are given the contents of the password file!

Conclusion

This was a fairly basic exercise in wep application pentesting and hopefully we have all learned that you can never trust any input from a browser regardless of whether you think the data is “sent automatically”, “hidden”, or “protected”.  Web applications must sanitize all data from the the browser before inserting it into any other request or query.

Go ahead and save your password for level03 and let’s move onto the next challenge!