[AHOV 1] Directory Traversal

by Charles Miller on November 9, 2003

Part 1 of A Handful of Vulnerabilities

Category: Input Validation

Short Description: A user supplies a specially crafted filename to a program (usually a server) that allows them to access files in areas of the filesystem that should be unavailable.

Alarm-bell Code: File file = new File(safeBaseDirectory, userInputFilename);

Discussion

Many applications create a direct mapping between user input, and files on the filesystem. This can happen explicitly, for example the way a webserver maps URLs to the filesystem, or it could be harder to spot: for example if issuing the "HELP FOO" command causes the underlying program to display the resource "help/foo.txt".

The most common directory traversal attack comes from a user making a request for '../../foo': using the '..' construct to escape to the directory above that in which the files should be found. This is, however, not the only unsafe pattern: several exploits have used '.|.' instead.

This is a very common vulnerability. It is most prevalent in P2P software, or in applications that "grow" some kind of fileserver bolted on the side: since fileserving isn't the core area of expertise for the developer, the dangers are often overlooked. For example, when ICQ was first shipped with a personal webserver, it was vulnerable to the simplest of directory traversal attacks.

One possible solution is to validate the input filename, filtering dangerous-looking characters. (Or more safely, only allowing through characters that are known to be safe). The advantage of this method is that you know exactly how it works. The disadvantage is that it is limited by your knowledge of what is, or is not a safe character. This is especially a problem with applications that may be deployed onto a platform you are unfamiliar with.

For example: The IIS Unicode exploit, one of the vectors for the Code Red virus, took advantage of the fact that IIS's input validation wasn't filtering the Unicode representation of the '/' character. As such, the string '..%c0%af../winnt/system32/cmd.exe' was being translated to '../../winnt/system32/cmd.exe', after the input validation had taken place.

There is another solution built into the Java standard library: the <a href="http://java.sun.com/j2se/1.4.1/docs/api/java/io/File.html#getCanonicalPath()">File.getCanonicalPath()</a> method. This method returns the direct path to a file with all symbolic links and path-traversal symbols already resolved. Thus, the following code will make sure that the file you're reading is really inside the directory you want it to be:

File file = new File(safeBaseDir, untrustedFileName); if (!file.getCanonicalPath().startsWith( &nbsp;&nbsp;safeBaseDir.getCanonicalPath())) { &nbsp;&nbsp;&nbsp;&nbsp;throw new InvalidFileRequestException(fileName); }

Of course, there may be bugs in getCanonicalPath. This is inevitable, but hopefully there are less likely to be bugs there than in your home-cooked solution. In addition, if a bug is found in the library method, you're more likely to find out about it and someone else will write the fix for you.

Previously: A Handful of Vulnerabilities: Introduction

Next: Australian Idol: A Licence to Print Money (Unless you win it)