DVWA - File upload

4 June 2019

Starting the challenge

Refer to the post start DVWA with Docker to learn how to start DVWA. I will mostly use Burp Suite to solve the challenges. To configure Burp suite refer to the post configure burp suite for DVWA. Click on the File upload button on the left menu to access the challenge.

Low Level - Understanding the application

We reach a page allowing us to upload an image.

Application home

If we choose an image an upload it the application returns the relative path to the uploaded image on the server : ../../hackable/uploads/coconuts.jpeg succesfully uploaded!.

The image is transmitted in a POST request :

POST /vulnerabilities/upload/ HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
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
Referer: http://localhost/vulnerabilities/upload/
Content-Type: multipart/form-data; boundary=---------------------------57639004077907672938394449
Content-Length: 50688
Connection: close
Cookie: PHPSESSID=2qdgiu3g3iqib3k2ptd18rntl7; security=low
Upgrade-Insecure-Requests: 1

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

Content-Disposition: form-data; name="uploaded"; filename="coconuts.jpeg"
Content-Type: image/jpeg

Upload vulnerability

The idea behind an upload exploit is to manage to upload an executable file to the server and trick the server into executing it for us. In our case we suspect that there is little to no control over what's being transmitted. We know that the server uses PHP, so if we manage to upload a php file we can probably make the server execute our php code.

In our case, to verify our theory we craft a very simple file name phpinfo.php with the following content:

<?php phpinfo() ?>

If we try to upload our file the server responds positively.

Low attack

Now from the relative path given by the server we try to access our file to trigger its execution. As we can see below, our attack was successful since the server displayed the results of the phpinfo() command.

Low attack

Low Level - Vulnerable code

The issue here is that the server expects to receive images but never verifies that the user did send an image. There are multiple ways to ensure that an image is being sent by the user:

  • by verifying the file extension
  • by verifying the magic bytes
  • by using libraries conceived to perform such verifications

Medium level

In this level the previous attack does not work. When we try to upload our php file the server throws an error saying that it only accepts PNG and JPEG files.

Medium security measures

One way of verifying that a file is a PNG or JPEG is with the Content-Type header. When we sent the php file the following message was sent :

Content-Disposition: form-data; name="uploaded"; filename="phpinfo.php"
Content-Type: application/x-php

The browser told the server that the file type is application/x-php. This line is probably filtered by the server. If we use Burp Repeater to repeat our previous request and replace the content type with image/png the server responds positively.

Medium security measures

Now we can access our file to execute our code.

Medium Level - Vulnerable code

The problem here is that the verification lies on a property modifiable by the user : the Content Type.

    // Is it an image?
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
        ( $uploaded_size < 100000 ) ) {

Medium Level - Remediation

The server should perform verifications on the file itself to ensure that it is indeed an image.

High level

In this level the previous tricks do not work. The server throws the same error message as the medium level.

The problem here is that the extension of the file is always checked. There is no way to upload a file with an extension different from .png or .jpg. What we have to do is exploit a fault in the php server to execute php code hidden in the EXIF data of the image file.

To do so we can either use a file prepared for us in IntruderPayloads images or we can create it ourselves with exiftool.

The command to add some php code in the image myimage.jpg is :

exiftool -DocumentName="<?php phpinfo(); __halt_compiler(); ?>" myimage.jpg

Here we add the code

<?php phpinfo(); __halt_compiler(); ?>

__halt_compiler() halts the execution of the compiler, so any code located after will not be interpreted.

Let's upload our image now.

Medium attack

Everything goes well since it was a real image, with the right extension. Now to exploit the vulnerability we need a way to give this file to the PHP interpreter. To do so we use a file include exploit by navigating to the url localhost/vulnerabilities/fi/?page=file1.php%0A/../../../hackable/uploads/image.jpg :

Medium exploit

Impossible level

The impossible level protects itself by stripping metadata that could be interpreted.

// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
    $img = imagecreatefromjpeg( $uploaded_tmp );
    imagejpeg( $img, $temp_file, 100);
else {
    $img = imagecreatefrompng( $uploaded_tmp );
    imagepng( $img, $temp_file, 9);
imagedestroy( $img );