StackHawk
Hamburger Icon

.NET Command
Injection: Examples
and Prevention

stackhawk

StackHawk|January 13, 2022

A .NET command injection is a potentially catastrophic attack your app can suffer if you're not careful. Read our guide to learn more.

The StackHawk blog routinely publishes posts about common security problems, how they work, and how to avoid them. There have been guides covering broken access control in Django, Spring path traversal, and Vue open redirect—and that's just to name a few post topics. If you're a .NET developer, this post is for you. We'll cover .NET command injection.

The post will open with some fundamentals: You'll learn what a command injection is, how it works, and why it's dangerous. Then we'll get to the .NET-specific portion of the post. You'll see examples of .NET command injection attacks and what you as a developer can do to prevent them.

Let's get started.

Requirements

If you want to follow along with the tutorial, you'll need

  • the .NET SDK installed (I recommend version 6.0),

  • at least some familiarity with C# and .NET, and

  • a code editor or IDE.

I'll be using Visual Studio Code, and if you use the same, it'll be slightly easier to follow along.

Additionally, bear in mind that as I write this guide, I'm on Windows. If you're using OS X or Linux, make the necessary adjustments to the commands I'll show.

.NET Command Injection: The Fundamentals

As promised, let's start with the very basics of command injections.

What Is a Command Injection?

A command injection, as the name suggests, is a type of code injection attack. Generally speaking, an injection attack consists of exploiting some vulnerability in an application to inject some malicious code that will interfere with the proper behavior of the application. The most famous type of injection attack is arguably SQL injection.

Command injections are also called OS command injections. In this exploit, a malicious actor is able to inject and execute commands on the operating system that the server is running on.

Why Are Command Injections Dangerous?

The results of a successful command injection can be catastrophic. An attacker who's able to run arbitrary commands on your server might be able to, among other things,

  • access, change, or delete files and directories;

  • read sensitive customer information;

  • extract sensitive information and send it to an external server;

  • access the list of current executing processes and kill one or more of them; and

  • as a result, take down important services and applications.

How Does a Command Injection Work?

An OS command injection, like other types of injection attacks, exploits applications that don't properly handle user input. In general terms, the attack works by "tricking" the application into accepting a seemingly harmless string and then concatenating that string of text to a command that is set to run.

The result of the concatenation is a malicious command that changes the original behavior of the application according to the design of the attacker.

.NET Command Injection: Let's See an Example

Let's see a simple example of command injection in practice.

Creating a Sample Application

We'll start by creating a new .NET MVC app:

dotnet new mvc -o injection-demo

Then, let's open the project using VS Code:

cd injection-demo
code .

With the project open, go to the Controllers folder and add a new file there:

.NET Command Injection: Examples and Prevention - Picture 1 image

Call the new file ReportController. Paste the following code in it:

using Microsoft.AspNetCore.Mvc;

namespace injection_demo.Controllers;

public class ReportController : Controller
{
    private readonly ILogger<ReportController> _logger;
    private readonly IWebHostEnvironment _environment;

    public ReportController(
        ILogger<ReportController> logger,
        IWebHostEnvironment environment)
    {
        _logger = logger;
        _environment = environment;
    }

    public IActionResult Generate(string? id)
    {
        ViewData["Client"] = id;
        var process = new System.Diagnostics.Process();
        var startInfo = new System.Diagnostics.ProcessStartInfo();
        var contentPath = _environment.ContentRootPath;
        var filePath = System.IO.Path.Combine(contentPath, id);
        startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        startInfo.FileName = "cmd.exe";
        startInfo.Arguments = $"/C echo teste > {filePath}";
        process.StartInfo = startInfo;
        process.Start();

        if (process == null)
        {
            return StatusCode(500);
        }
        else
        {
            process.WaitForExit();
            return View();
        }
    }
}

Next, go to Views and add a new folder:

.NET Command Injection: Examples and Prevention - Picture 2 image

Call the folder Report and create a file inside it called Generate.cshtml. Add the following text to it:

@{
    ViewData["Title"] = "Report";
}

<div class="text-center">
    <h1 class="display-4">Report for the client @ViewData["Client"]</h1>
</div>

Running the Sample App

We're now ready to run this app. If you configured your VS Code for debugging, just press F5. Otherwise, go to your terminal and execute dotnet run.

Regardless of how you do it, you should be able to go to https://localhost:7168/ and see the application live:

.NET Command Injection: Examples and Prevention - Picture 3 image

To test the app, go to the address bar and append /report/generate/<SOME-NAME> to the address. Of course, replace <SOME-NAME> with an actual name. Yours, for example. Then, press enter. Here's what I see after doing this using my name:

.NET Command Injection: Examples and Prevention - Picture 4 image

After you've done this, go to the project folder, and you'll see a file with your name:

.NET Command Injection: Examples and Prevention - Picture 5 image

That's proof the command was executed successfully. But what about the command injection?

Exploiting the App

This sample app is quite naïve in the way it handles user input. It simply accepts any input and concatenates it into a command to be executed by the underlying OS.

Generally speaking, you should never blindly trust any information that comes from the outside of your app. That includes

  • data from web forms,

  • URL parameters, and

  • data from POST/PUT/PATCH requests to API endpoints.

To demonstrate how exploitable this app is, you just need to perform a very simple test. With the application running, append the following to the address bar content:

&& dir > out.txt

Then, run the app again. This is what I see in my browser:

.NET Command Injection: Examples and Prevention - Picture 6 image

It might look like an innocent result. Don't fool yourself, though. Go to project's folder and you'll see a file called out.txt there:

.NET Command Injection: Examples and Prevention - Picture 7 image

That's right! The extra text you just added caused a second command to be executed. More specifically, the dir command was executed, and then its output was piped into a new file. Open the file, and its contents should look somewhat like this:

.NET Command Injection: Examples and Prevention - Picture 8 image

How to Prevent a .NET Command Injection

As you've seen, the silly sample app we created offers no protection whatsoever against command injections. The "attack" we performed was rather benign, but in the real world, such incidents can have dire consequences.

So, what can you do to prevent such attacks? The best way is to simply not run OS commands from your web app. There are often better alternatives (e.g., job scheduling) than running commands directly.

If you do need to run commands, do it without blindly trusting user input. Validate the received data using regular expressions or even an allowlist to only allow legitimate values.

Also, don't forget to leverage any tools you might have at your disposal. For instance, .NET offers many useful static analysis rules for security. One of them—CA3006—is about command injection. Don't deactivate these rules. Better yet, configure your project so they issue compiler errors instead of mere warnings.

Find and Fix Application Security Vulnerabilities with Automated Testing

.NET Command Injections: Know Them and Guard Your Apps Against Them

Pop culture has imprinted the stereotypical hacker into all of our minds. As it turns out, real-world exploits are much more mundane and often occur due to developers not being diligent enough when protecting their applications. Among the myriad exploits out there, code injection attacks are some of the most well known. Among its subtypes, we can cite SQL injections and command injections. This post was about the former.

In this post, we offered you an introductory guide to .NET command injections. You've learned about OS command injections, the danger they pose to applications, and what to do about them.

Thank you for reading, and until next time.

This post was written by Carlos Schults. Carlos is a consultant and software engineer with experience in desktop, web, and mobile development. Though his primary language is C#, he has experience with a number of languages and platforms. His main interests include automated testing, version control, and code quality.


StackHawk  |  January 13, 2022

Read More

Add AppSec to Your CircleCI Pipeline With the StackHawk Orb

Add AppSec to Your CircleCI Pipeline With the StackHawk Orb

Application Security is Broken. Here is How We Intend to Fix It.

Application Security is Broken. Here is How We Intend to Fix It.

Using StackHawk in GitLab Know Before You Go (Live)

Using StackHawk in GitLab Know Before You Go (Live)