Link Search Menu Expand Document

Unrestricted File Download in PHP

Vulnerable Example

The example below shows a vulnerable Symfony controller that serves files from a directory in an unsecure way:

class FetchFileController extends Controller
{
    const ROOT = '/path/to/root/';

    /**
     * @Route("/", name="fetch_file_index")
     * @Method("GET")
     */
    public function indexAction(Request $request)
    {
        $file_name = $request->query->get('filename');
        $file_data = @file_get_contents(self::ROOT . "/$file_name");
        return $this->render('fetch_file/index.html.twig', ['file_data' => $file_data]);
    }
}

The file_name query parameter is controlled by the user; it is possible to retrieve arbitrary files in the filesystem by injecting ../ in the file_name parameter as shown below:

http://example.com/fetch_file/?file_name=../../../../../etc/passwd

This results in the absolute path /path/to/root/../../../../../etc/passwd, and its canonicalized form: /etc/passwd.

Prevention

Make sure to avoid using the user-provided value to escape the designed directory by means of ../. The basename function can be used to extract the base component of a path.

To remediate the vulnerability in the previous example, the $file_name variable should be fixed as follows:

$file_name = basename($file_name);

The previous attack would result in reading the /path/to/root/passwd file (which does not exist).

References

Owasp - Path Traversal