What is Directory Traversal?

During a directory traversal attack, the attacker will submit a filename containing characters that will allow them to access files outside of the intended directory. For example, a single dot (.) refers to the current directory and two dots (..) the parent directory. During an attack the aim will be to access and read restricted files using PHP’s elevated privileges. For example files outside the root directory (public_html for example in Apache) are not accessible from the internet, but PHP will most likely have privileges to read and execute these files. Another example would be viewing the contents of PHP files on the server which might contain valuable information such as database credentials.

Basic example

A website that serves static content from files with no file extension via a PHP script.

$page = $_GET;  
$filename = "/pages/$page";  
$file\_handler = fopen($filename, "r");  
$contents = fread($file_handler, filesize($file));  
fclose($file_handler);  
echo $contents;   

Intended use

view.php?page=about    

This would display the contents of /pages/about which could contain the markup for the about page. This method is commonly used to create multiple pages in a single

Malicious use

view.php?page=../admin/login.php    

In this example instead of getting a file from the pages directory the ../ traverses to the parents directory so instead gets the file /admin/loin.php. This is very bad news as it will most likely contain admin or database credentials; if not it could contain paths to other PHP files that will contain this information. The attacker could then use the same method again to get these other files and gain valuable information. These credentials could then be used to perform a more devistating attack of stealing user details, defacing, deleting files/records or hijacking the site spreading malicious software … to name a few.

Expand on this topic: Common PHP attacks: Poison Null Byte

Solution

You may be tempted to try and use regex to remove all ../s but there are some nice functions built into PHP that will do a much better job:

$page = basename(realpath($_GET));  

basename - strips out all directory information from the path e.g. ../pages/about.php would become about.php
realpath - returns a full path to the file e.g. about.php would become /home/www/pages/about.php, but only if the file exists
Combined they return just the files name but only if the file exists.