.NET Path Traversal
Guide: Examples
and Prevention

stackhawk

StackHawk|February 9, 2022

By the end of this article, you'll have an understanding of the concepts of .NET path traversal and be qualified to use mitigation strategies.

In this article, we will be exploring the concepts of path traversal attacks, and what approaches we can take to mitigate them.

We will first briefly explain what path traversal attacks are. Then we will explore some typical examples you can find on the web. And finally, we will suggest some possible fixes to address these exploits.

By the end of this article, you'll have a basic understanding of the concepts of path traversal and be qualified to implement mitigation strategies on your projects.

Note: This article is aimed at .NET developers. Therefore, we expect that you have a basic understanding of the .NET development stack. 

If you haven't explored this platform yet, please check this site for more information.

What Is Path Traversal?

Broadly speaking, path traversal is an attack that takes advantage of flawed access control implementations on the server side, particularly for file access.

In a path traversal attack, a bad actor would attempt to access restricted files in the server by injecting malicious user input into the application. 

Think of it as SQL injection but on directories instead of the database.

Now, obviously, it is pretty clear why users having unauthorized access to server files is terrible news. An ill-intended individual can wreak havoc in our systems and take over the platform with this kind of power. 

This is why it is paramount to have proper security mechanisms in place.

This is a brief and simplistic explanation of the concepts of path traversal, and exploring further goes beyond the bounds of this article.

In that post, we dive much deeper into the oddities that make this vulnerability possible and why the system your server is running in matters.

Now, let's move on and see a few examples of path traversal attacks.

Path Traversal Attacks

So, what does a characteristic path traversal attack look like, you may ask?

Well, it's as simple as this.

../../etc/passwd

Surprising, right?

Path traversal essentially boils down to finding ways to get to folders that the developer and application didn't intend for you to access. So, if you have a basic understanding of path logic and Linux or the command line, you can go places on an unprotected application.

Now, let's look at some specific types of path traversal attacks.

Relative Path Attack

A relative path attack is what we illustrated above. 

By exploiting the user input validation, or lack thereof, attackers might attempt to access restricted files in the server. In this case, the passwd file contains our secrets on the server.

A simple way to mitigate this vulnerability is, of course, to apply proper user input validation. By including a command as simple as path.normalize() and sanitizing the user input—something you should always do, by the way—you can save yourself from a lot of headaches and issues down the road.

Poison Null Bytes Attack

Providing a null byte, or \0, at the end of a string in an HTTP request allows an attacker to bypass the string validation used to sanitize user input and get access to unauthorized files and directories.

What would that look like on the web? Well, something like this.

/../../../../../../../../../../../../../../../../etc/passwd%00

Do you see the %00 at the end? Unfortunately, our poor validation would end up translating this to something like \0.txt\0 and potentially give access to the passwd file. Yikes!

To prevent this kind of attack from thwarting our security, you only need to validate the user input with the following.

if (user_input.indexOf('\0') !== -1) {
return respond('Access denied');
}

Relatively straightforward, right?

As we mentioned before, path traversal attacks are not incredibly sophisticated. Instead, they depend on poor access control implementations or edge case vulnerabilities by poorly updated code. 

However, they can be very dangerous, and we should mitigate them as much as possible. 

The good news is that it's not that hard to do so.

.NET Path Traversal Guide: Examples and Prevention image

Other Mitigating Approaches to Path Traversal Attacks

Luckily, there are many things we can do to cover the possible gaps in our security. We've listed a few here.

Path Prefix Validation

But what about allowing some level of traversal in your application? There might be cases where you want the application to enable the user to find files in different folders, such as profile pictures and essays, both in their folders. 

You can implement hardcoded path validations like variables used when requesting specific resources. However, you could open yourself to prefix path traversal attacks by doing so.

An attacker can freely traverse the directories if the user can enter dots and slashes in the application without validating the resulting string. 

To mitigate this, we need to validate that the user input does not contain these characters and strip them or flat out display an error.

Something as simple as this would do:

public bool IsPathTraversing(string path) {
bool result = false;

if (String.IsNullOrWhiteSpace(path)) {
return result;
}

// Url decode to reveal sneaky encoded attempts e.g. '%2f' (/) or '%2e%2e%2f' (../)
var decodedPath = HttpUtility.UrlDecode(path);

if (decodedPath.Contains("/") ||
decodedPath.Contains(@"\") ||
decodedPath.Contains("$") ||
decodedPath.Contains("..") ||
decodedPath.Contains("?")) {

result = true;
}

return result;
}

Safelisting

Safelisting is a straightforward and relatively effective method to reduce the potential for exploits. Of course, you won't always be able to use it, but you should when you can.

A straightforward example of safelisting is validating that the user input conforms to a certain standard predefined. For example, if you have coded your application only to create and work with files with lowercase alphanumeric characters, you can validate that the user only inputs such characters.

protected string readFile(string location) {
Regex regex = new Regex(@"([a-zA-Z0-9\s_\\.\-:])+(.dat)$");
Match match = regex.Match(location);

if (match.Success) {
if (File.Exists(location)) {
using (StreamReader reader = new StreamReader(location)) {
return reader.ReadToEnd();
}
} else {
return "File not found";
}
} else {
return "File name not valid";
}
}

By adding this validation to user inputs, you can have an extra layer of protection against malicious attacks.

Path Concatenation

Finally, one way to address all these gaps and create a robust solution to all the potential vulnerabilities we might face is to implement a general validation scheme that comprises all these tests and makes a secure final path string.

One example of a solution would look something like this.

protected string readFile(string location) {
Regex regex = new Regex(@"([a-zA-Z0-9\s_\\.\-:])+(.dat)$");
Match match = regex.Match(location);

if (match.Success) {
if (File.Exists(location) && Path.GetFullPath(location).StartsWith(@"C:\Applications\Documents", StringComparison.OrdinalIgnoreCase)) {
using (StreamReader reader = new StreamReader(location)) {
return reader.ReadToEnd();
}
} else {
return "File not found";
}
} else {
return "File name not valid";
}
}

As you can see, we have incorporated all the checks and validations already discussed to encompass any potential abuse of our system.

Find and Fix Application Security Vulnerabilities with Automated Testing

Stop Path Traversal Before It Happens

As simple as it might seem, it is essential to make sure that we enforce good path traversal security policies and cover as many potential gaps in our application.

Technology will continue to evolve, and more robust and comprehensive solutions will mitigate these issues. 

Nevertheless, don't forget that we can always cover for the lack of our systems, as long as we are thorough and creative with our approaches.

Given that .NET is such a mature and robust platform, there are various ways to go around this. Just make sure you find something that satisfies your needs and adequately test your approach and implementation.

This post was written by Juan Reyes. Juan is an engineer by profession and a dreamer by heart who crossed the seas to reach Japan following the promise of opportunity and challenge. While trying to find himself and build a meaningful life in the east, Juan borrows wisdom from his experiences as an entrepreneur, artist, hustler, father figure, husband, and friend to start writing about passion, meaning, self-development, leadership, relationships, and mental health. His many years of struggle and self-discovery have inspired him and drive to embark on a journey for wisdom.


StackHawk  |  February 9, 2022