Arbitrary Command Injection is a type of command injection vulnerability, which can be triggered to execute arbitrary command or in simple words any of the available command within the application server.

In the following guide, we will look at how Arbitrary Command Injection vulnerability can be triggered to execute a simple command such as id on a sample vulnerable application.

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 navigating to http://127.0.0.1:8080/upload.php webpage. 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.

In the above screenshot, If you may have noticed, we have three options for each image file uploaded:

  • View: To view the image on the browser
  • Download: To download the image file from the application
  • Delete: To delete the file from the web server

Go and try all the available operations.

view operation

By clicking the View, the user can be able to view that uploaded image from the web application.

Download operation

By clicking the Download button downloads that particular uploaded image to the system.

delete operation

The last operation permitted within the web application, is to delete the image from the web application.

The application prompts for the confirmation to permanently delete the file from the server. Once confirmed, the web server deletes that particular image.

If you may have noticed during the delete operation, the following endpoint is accessed in the browser:

http://127.0.0.1:8080/delete.php?file=pompompurin.jpg

And as, the file is being deleted from the system there is a possibility that the developer have used a remove system call or rm command to delete the file from the server’s file system.

Now, we need to figure out some way to execute other commands instead or along with rm command.

Note

In a Linux system, multiple commands can be executed in a single line by separating each command via semi-colon ;

So, we will try to append semi-colon and see whether we have encountered any error or not while removing the file from the server.

http://127.0.0.1:8080/delete.php?file=pompompurin.jpg;

Note

As the file has been already deleted from the webserver, a different image is needed for carrying out our analysis or the same file can be re-uploaded. In our demonstration, we have re-uploaded the same file after every delete operation.

Interesting to note that, the above location access did not encountered any error and we have successfully deleted the pompompurin.jpg file.

So, delete.php is inherently using a command line utility to execute a command to remove the file from the server. Let’s try to execute the id command to check whether commands are being executed or not.

http://127.0.0.1:8080/delete.php?file=pompompurin.jpg;id

Voila Fellow Asuras!!! We have successfully executed the id command on the web application, confirming the presence of Arbitrary Command Injection vulnerability.

Question

Can you think about some other vulnerability which may be present in the Gallery application. Hint: It’s something related to file upload.

Source Code Evaluation

To evaluate the source code of the application and find the root cause of the vulnerability, we need to evaluate the delete.php file, as the vulnerability exists in the delete.php endpoint of the web application.

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

docker exec -it command_injection /bin/bash

The truncated source code of delete.php is as follows:

<?php
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    if (isset($_GET['file'])) {
        $output = [];
        $returnVar = 0;
 
        // Ensure the file name is sanitized to prevent security issues
        $fileToDelete = basename($_GET['file']);
        
        // Attempt to delete the file from the uploads directory
        exec("rm uploads/" . $fileToDelete, $output, $returnVar);
 
        if ($returnVar == 0) {
            $message = "File deleted successfully.";
        } else {
            $message = "There was an issue deleting the file.";
        }
 
        // Display output from the exec command, if any
        $message .= "<br><br>";
        foreach ($output as $line) {
            $message .= htmlspecialchars($line) . "<br>";
        }
    } else {
        $message = "No file specified.";
    }
} else {
    $message = "Invalid request method.";
}
?>

During the evaluation, you may notice a interesting function call i.e. exec(), which is used to Execute an external program 1.

Bug

A direct call to exec() is made without checking the arguments which are being passed as filename.

The above operation only requires us to delete the file from the web server. So, we can use PHP’s native file operations to do the task, instead of directly executing the rm command in the shell.

The following code removes the use of exec(), and uses PHP native unlink()2 file operation to delete a file from the server.

<?php
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
    if (isset($_GET['file'])) {
        $returnVar = 0;
 
        // Ensure the file name is sanitized to prevent security issues
        $fileToDelete = basename($_GET['file']);
        $file = 'uploads/' . $fileToDelete;
        
        if (file_exists($file)) {
            if (unlink($file)) {
                $returnVar = 0;
            } else {
                $returnVar = 1;
            }
        } else {
                $returnVar = 2;
        }
 
        if ($returnVar == 0) {
            $message = "File deleted successfully.";
        } else {
            $message = "There was an issue deleting the file.";
        }
 
        // Display output from the exec command, if any
        $message .= "<br><br>";
    } else {
        $message = "No file specified.";
    }
} else {
    $message = "Invalid request method.";
}
?>

After mitigating the vulnerability, let’s again try accessing the web page again with the id command:

http://127.0.0.1:8080/delete.php?file=pompompurin.jpg;id

Now, the output shows did not triggered the command and resulted in an error, therefore we were successfully able to mitigate the arbitrary command injection vulnerability.

In the next part of the series, we will learn about Arbitrary File Upload.

Footnotes

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

  2. https://www.php.net/manual/en/function.unlink.php