Directories

Last updated on
20 September 2016

For starters, always make sure that actions on uploaded files (upload, view, download, delete) are taking place in the 'files' directory or another designated directory. Beware that in the following code samples a hardcoded directory "files" is used to simplify the examples, in reality this directory is configurable.

Users have no business reading or deleting important system files (such as /etc/passwd or sites/default/settings.php). While the examples concentrate on deletion, keep in mind that reading arbitrary files is also undesirable.

/** Example 1 - Insecure 
  * Arbitrary file deletion.
  *  
  * $file is path/filename (eg files/myfile.txt) provided by the user.
  */
file_delete($file);

A malicious user can abuse the trust granted to him/her in Example 1 by providing filenames in different directories, such as /sites/default/settings.php. The attack is clearly limited by the permissions of the user account that executes Drupal (often the webserver) on these files.

/** Example 2a - Insecure
  * Arbitrary file deletion.
  *
  * $file is a filename (eg. myfile.txt) provided by the user.
  */
file_delete("files/$file");
/** Example 2b - Insecure
  * Arbitrary file deletion.
  *
  * $file is path/filename (eg files/myfile.txt) provided by the user.
  */
// Check whether $file is files/file
if (strpos($file, "files/") === 0) {
  file_delete($file);
}

Both Example 2a and 2b try to mitigate the attack by either prepending the filename with a fixed directory or by checking whether the supplied path begins in files/. Both examples are vulnerable to attack with parent paths (..).

What would happen if a malicious user would provide Example 2a with ../sites/default/settings.php and Example 2b with files/../sites/default/settings.php as path?

Both would attempt to delete sites/default/settings.php.

To properly check the real path of a file, use the Drupal function file_check_location.

/** Example 3
  * No longer vulnerable to parent path (..) attacks.
  *
  * $file is path/filename (eg files/myfile.txt) provided by the user.
  */
// Check whether $file is files/file
if (file_check_location($file, 'files') {
  file_delete($file);
}