External control of file name or path - PHP

External control of file name or path - PHP

Need

Secure file handling and storage

Context

  • Usage of PHP 7 for server-side scripting and web development
  • Usage of Request for making HTTP requests

Description

Non compliant code

        public function upload(Request $request)
{
    if($request->hasFile('file')) 
    {
        $file = $request->file('file');
        $path = $request->input('path');
        $file->move(public_path() . $path, $file->getClientOriginalName());
    }
}
        
        

In the code snippet above, there is a function named upload which is supposed to handle file uploads. The function first checks if the request contains a file. If it does, it retrieves the file and the path where the file should be saved. The path is also retrieved from the request.

The vulnerability lies in the line where the file is being moved to the specified path. Here, the path is directly taken from the user input without any validation or sanitization. This makes it possible for an attacker to manipulate the path and control where the file gets saved.

For instance, an attacker can provide a path that points to a critical system or application file, thus overwriting it with the uploaded file. This can lead to a variety of attacks, such as code injection, data tampering, or even denial of service if a critical system file is overwritten.

This is a classic example of the "External Control of File Name or Path" vulnerability. It is a serious vulnerability that can lead to full system compromise if exploited correctly. It is therefore crucial to fix this vulnerability by properly validating and sanitizing the user-provided path.

Steps

  • Validate the 'path' input to ensure it's a safe path. This can be done by checking if it contains any '..' or similar path traversal characters.
  • Do not allow the user to specify the full path. Instead, use a predefined directory and append the user's input to it after validation.
  • Use a server-generated filename instead of the original filename to prevent any possible injection attacks.
  • Consider using a library or built-in function to handle file uploads, as they often have built-in security measures.

Compliant code

        public function upload(Request $request)
{
    if($request->hasFile('file')) 
    {
        $file = $request->file('file');
        $path = $request->input('path');

        // Validate the path
        if (strpos($path, '..') !== false) {
            // Invalid path
            return response()->json(['error' => 'Invalid path.'], 400);
        }

        // Predefined directory
        $safePath = '/uploads/' . $path;

        // Server-generated filename
        $filename = Str::random(10) . '.' . $file->getClientOriginalExtension();

        $file->move(public_path() . $safePath, $filename);
    }
}
        
        

The above code fixes the vulnerability by implementing the following changes:

1. Path Validation: The code checks if the user-provided path contains '..' which is a common technique used in path traversal attacks. If '..' is found, the function returns an error response.

2. Predefined Directory: Instead of allowing the user to specify the full path, a predefined directory '/uploads/' is used. The user-provided path is appended to this predefined directory after validation.

3. Server-generated Filename: Instead of using the original filename, a server-generated filename is used. This is done by generating a random string and appending the original file extension to it. This prevents any possible injection attacks that could be done by manipulating the filename.

4. File Upload Handling: The file upload is handled using Laravel's built-in file handling functions which have built-in security measures.

By implementing these changes, the code is now protected against attacks that try to manipulate the file name or path.

References