While a lot of developers are turning to Rust-lang for its long list of benefits, it has its fair share of caveats. For instance, new developers will associate built-in memory safety with overall Rust applications security. This often leaves Rust applications vulnerable to a wide range of attacks. Of particular interest to this post is the Rust path traversal vulnerability.
Path traversal is an attack that hackers apply in order to access the directories and files on application servers. This type of attack can be used on both "vanilla" Rust applications and framework implementations of the programming language.
This guide will take you through the various path traversal vulnerabilities that Rust applications are susceptible to. Breaking down each of the examples will help you understand and remedy Rust-lang path traversal attacks.
Rust Path Traversal: How It Works
On our way to fully grasping and patching Rust path traversal vulnerabilities, let's start by examining just what makes the attack possible. For one, this attack works on applications that allow user input of any type. A good example is a URL as users browse the pages of a Rust framework web application.
Stand-alone Rust-lang applications for which server requests are not bare fall victim to path traversal attacks once an attacker starts using advanced network analysis tools like Kali.
The most obvious points of entry for path traversal attacks are front-end form elements. For one, they directly lead to directories that store input files on the server. The Rust code around such forms can make or break the security of an entire application. As you'll see once we look at actual vulnerabilities, if an application shares storage with any other sensitive files or applications, they too will become vulnerable.
Once an attacker gains access to the document tree behind an application, they can either take it down or keep a live trap to take advantage of unsuspecting users. Let's zoom in on an example to illustrate how a Rust path traversal attack actually takes place.
Rust-Lang Path Traversal Example
The code below is a simple implementation of an upload() function. As you can see from quickly reading through the snippet, the FormData variable is passed from the user with either a successful reply or a simple rejection error.
This particular code example has an array of error codes based on an evaluation process: form.try_collect(). However, common errors that spring from said trials often focus on file size and allowed extensions. Although this is a low-strength protective layer, attackers can simply outmaneuver any set rules.
Immediately you should see that you can limit uploads to just PNG images and PDF files. You can also limit the size of files uploaded. However, that's far from being sufficient when protecting your directory tree from unauthorized access.
With just the code above as your form logic in Rust, attackers can pass cURL commands and plant malicious files in your directory.
curl --location --request POST 'http://127.0.0.1:8080/upload' \
--header 'Content-Type: multipart/form-data' \
As innocent as the cURL file upload command syntax may appear, attackers can get sneaky with it. For one, staying within the allowed extension options list, attackers can append the name of their file with "../../../../" options that basically ask your server to reveal directories outside of the assigned upload location.
The resulting command would then not only save a persistent vulnerability springboard in the form of this new file but take the attacker to the application's root folder. By default, Rust requires that the endpoint for any API verb be an actual file. In this attack scenario, that requirement is provided for by actually saving a file. It's easy for an attacker to then upload a default file (index.html) that reflects out the rest of the directory.
Rust Framework Vulnerabilities
This type of attack is also easily passed to any Rust framework. It essentially takes advantage of the primitive form implementations on the front end. If left as is, they leave loopholes all over the resulting web applications.
As a rule of thumb, remember that just because code has been published as open source and even forked hundreds of times, that doesn't make it safe. The same applies to cargos found on the Rust crate registry. Once you attach already-functioning code to your project, you also inherit any vulnerabilities it may possess.
How to Fix and Prevent Rust Path Traversal Vulnerabilities
Path traversal exploitations are best coded out of your applications during test cycles. This requires knowledge of actual threat level familiarity beforehand, which sometimes is not the case. Even then, patches might require that you redo entire sections of your code. If speed is a big concern, you can also add security patches by infusing known crates with your project.
As you take either route, the line of thinking around fixing Rust path traversal attacks remains the same:
Sanitize all input passed to your server through forms.
Explicitly declare default folder endpoints.
Incorporate tests into every code commit.
Sanitize Rust Form Input
To start with, modern coding practices include cleaner functions that you can attach to input for quick cleansing effects. In Rust, the PathBuf method allows you to work on user input (paths) before they pass to the server. Essentially, you stave off any attempts by hackers to climb out of the allowed file storage directory.
Declare Default Folder Endpoints
Say a hacker manages to access a folder containing sensitive files and can now traverse in either direction on the entire directory tree. Having a default index or home files planted along your folder tree is a good way to limit how much they can do. For one, they'll be restricted to that file alone. Also, these files can help you audit just how many of your storage locations have been compromised.
Run Security Tests With Every Commit
It's not uncommon for new vulnerabilities to join your codebase as an application scales. This is why every commit should be scanned for potential threats before it goes into production. And this is all the more important when appended code brings entire functional modules into your own. It's best practice to be paranoid of any externally sourced pieces of code. Always suspect cargos and freelancer-obtained code.
The Rust programming language is fast gaining popularity, and with this fame could come a new breed of vulnerabilities. As far as Rust path traversal is concerned, you're best safer than sorry. Prevention of attacks is always a better strategy than troubleshooting vulnerabilities with patches in hand.
Your Rust application can be attacked through user input forms and navigation bars. This makes framework-based web applications just as vulnerable as "vanilla" Rust-lang projects. Either way, letting your team be aware of the persistently high threat of Rust path traversal attacks is a great starting point.
Once everyone is in the know, applying tools like StackHawk to monitor the security threats potentially included as your lines of code grow is a good strategy. This way, each time a new piece of code that contains vulnerabilities joins the codebase, you get warnings and fix each discovery before it matures into an active attack. With hackers demanding hundreds of billions of dollars from their victims on a yearly basis, you're best staying on the safe side with preventive measures.
This post was written by Taurai Mutimutema. Taurai is a systems analyst with a knack for writing, which was probably sparked by the need to document technical processes during code and implementation sessions. He enjoys learning new technology and talks about tech even more than he writes.