Overview

Path traversal vulnerabilities are a common class of web application vulnerability, where an attacker aims to access files outside of the intended directory by using “../” patterns to traverse directories or by using absolute paths. These vulnerabilities are commonly found in file upload or download functionality of an application.

While doing a code-assisted assessment on a .NET web application recently, I found a surprising feature in the Path.Combine function of the .NET Core. Path.Combine takes two file paths as arguments. It concatenates the two to get a full path, which is typically followed by a call to read or write to that file. In the context of a web application, the first parameter is generally an absolute directory path pointing to the storage location of images or user documents. The second parameter is often user controlled, to some degree. For example, a request such as:

https://example.org/download?filename=a.png

might have code that looks like this:

		public static bytes[] getFile(String filename) { // Disallow filenames with the dot-dot path traversal sequence. if (filename.Contains("..") {   throw new ArgumentException("error"); }  String imageDir = "\\FILESHARE\images\"; filepath = Path.Combine(imageDir, filename); var ext = Path.GetExtension(filePath); return File.ReadAllBytes(filepath);}	

The documentation talks about several different scenarios based on whether the first or second parameters are absolute paths or not. The surprising case to me is that if the second parameter to Path.Combine is an absolute path, then the result is just that path. The first parameter will be ignored. The implications here are significant for web applications that have code similar to the above example. It means that a user who sends this request:

https://example.org/download?filename=C:\\inetpub\wwwroot\a.png

will get exactly that file. So an application that prevents path traversal by checking for “../” patterns in user input is still vulnerable to this use of Path.Combine.

Prevention

To prevent path traversal, the Path.GetFileName function may be used to look up the “base name” of a given path. If the given argument is a safe filename without path characters, it returns the filename. If the given argument is either an absolute path or a relative path with directory traversal characters, it returns the base filename without these path characters.

		public static bytes[] GetFile(String filename) { // Ensure that all path elements are safe path elements. if (string.IsNullOrEmpty(filename) || Path.GetFileName(filename) != filename) {   throw new ArgumentNullException("error"); }  String filepath = Path.Combine("\\FILESHARE\images", filename); return File.ReadAllBytes(filepath);}	

Testing for the Issue

As a security engineer, the easiest way to test this is with a quick DNS lookup. A file path starting with a “\” will trigger a DNS lookup for the alleged file share. If this works, you know that the Path.Combine issue exists.

https://example.org/download?filename=\\smb.dns.praetorianlabs.com\a.png