Path Traversal

Path Traversal is a fancy name for what is basically just accessing different directories in the URL. “Say what?” I hear you say. This is a very basic form of attack, but let’s go through it step by step.

What is it?

Sometimes you see this in your URL of a website:

The uploads/IMG0624.JPG sure looks like a file system path. The / gives it away, probably Linux. It’s just like browsing files on your computer.

When changing the image name to IMG0625.JPG chances are you’re going to see another image. This means changing that path to anything will display the file (if it exists). So ?file=config.json could perhaps show us something interesting. Guessing like this takes a long time of course, so there are tools like DirBuster that are able find your files through brute forcing.

Attacking

If the server is truly vulnerable to Path Traversal, with some knowledge about the file system, you could access anything on the server.

Judging from the forward / we can assume the server is running on Linux. And Linux has a very specific file system structure. For example one of the more sensitive pieces of information we could attain would be /root/.ssh/id_rsa which is the private key of the server (notice the / at the beginning, the root directory is situated at the very beginning of the file system). By retrieving the key one could get access to the server using SSH and acquire valuable data that is accessable to that Private Key, like git repositories and other servers that are associated.

Another way to get to the beginning of the system is to use ../../../../../../root/.ssh/id_rsa. It basically goes up in directories as far as it can (you can have as many ../ as you like, because Linux doesn’t try to go passed the beginning of the file system, it will always end up in the / directory).

This specific example probably wont work on a basic server, unless the administrator who set it up gave the web application root permissions (never do that). So you’ll need to be clever to figure out what information you can access. Of course, the software engineer could have easily protected against Path Traversal in the first place.

Defending

There is no single fix to protect the whole server, but there are several security measures.

Server permissions

The web application (node.js, PHP etc) should not have more permissions than are absolutely necessary. Separating the app from the rest of the system with permissions means that even if the hacker gets access to your files, it can’t read the really sensitive information – like your ~/.ssh/id_rsa file as demonstrated above. This of course helps with other kinds of vulnerabilities too.

Don’t use direct file referencing

Usually developers create this functionality for easy uploads management, but it’s just not very safe. There are many ways around it like referencing the file by a randomly generated file ID or keeping your files on another server, like the popular Amazon S3. The general rule of thumb is to keep one server for one purpose to have it as tight as possible.

Input validation

This is taking the parameter value and making sure it’s up to the standard. There are many ways to do this.

Restrict access to just a single file. So in PHP basename(realpath($_GET['filepath'])) would only return the filename. This way you can be sure no one gets anything from any other directory. Of course this isn’t a very flexible solution.

Whitelisting directories. It’s best to have a concrete path where user access is allowed.

$allowedPath = "/var/www/useruploads/avatars";
$userinput = "../../index.php";
$fullpath = realpath($userinput);
if (substr($fullpath, 0, strlen($allowedPath)) === $allowedPath) {
// $fullpath starts with allowedPath
}

So what happens there is that $allowedPath . $userinput becomes /var/www/useruploads../../var/www/index.php, but realpath converts that into a sensible /var/www/index.php (if it finds the file in the first place). Then you check if the new path actually matches the $allowedPath. In this case not so the hacker is caught.

Whitelisting filenames or file types. If for example you would like to only allow .pngfiles to be allowed you would simply ask if the input string ending matches what you need.

$path = $_GET['filepath'];
if (substr($path, -3) !== ".md") {
// File is not .md
}

Filtering suspicious strings. You can make sure that the input string does not start with a / and does not contain any ../. This isn’t really a solution however, because you probably can’t think of all the possibilities the attacker can use plus they have an arsenal of bypassing methods (like encoding).