Improper neutralization of special elements used in a command ('Command Injection')

ID

csharp.command_injection

Severity

critical

Resource

Injection

Language

CSharp

Tags

CWE:77, CWE:78, NIST.SP.800-53, OWASP:2021:A3, PCI-DSS:6.5.1

Description

Improper neutralization of special elements used in a command ('Command Injection').

Command injection vulnerabilities occur when an application passes untrusted input to a system shell command without proper validation or sanitization.

Such vulnerabilities allow attackers to execute arbitrary shell commands with the privileges of the user running the application, which may result in complete system compromise.

Attackers exploiting the vulnerability can then install a reverse shell, download and install malware or ransomware, cryptocurrency miners, run database clients for data exfiltration, etc.

Understanding and mitigating this risk is crucial, as it can facilitate data breaches, unauthorized data manipulation, or any type of attack that could be crafted via system commands.

Rationale

The System.Diagnostics.Process, and the System.Diagnostics.ProcessStartInfo classes in .NET are used to execute external OS processes that may allow for command injection if untrusted input is concatenated into command strings.

There are other apis in the .NET SDK and related libraries that may also be vulnerable to command injection, such as System.Management.Automation.PowerShell or the P/Invoke System.Runtime.InteropServices, as well as other popular .NET libraries such as CliWarp, MedallionShell, SharpProcess, among others.

The following is an example of a vulnerable C# code snippet using Process and ProcessStartInfo:

// Vulnerable to command injection
var psi = new ProcessStartInfo("cmd.exe", "/c ping -c 3 " + userInput);
Process.Start(psi);

Remediation

Avoid using the shell to execute commands, when possible. Use ArgumentList (from .NET 6+) to separate executable and arguments safely:

var ipOrHostname = ValidateIPOrHostname(userInput);

// No shell invocation, it is not needed
var psi = new ProcessStartInfo("ping")
{
    RedirectStandardOutput = true,
    RedirectStandardError = true,
    UseShellExecute = false,
    ArgumentList = { "-c", "3", ipOrHostname } // FIXED
};
Process.Start(psi);

Input validation is the first line of defense against injection-type attacks. In the previous example, userInput should be strictly validated as either an IP address or a hostname:

// <summary>
//     Validate the input as either an IP address or a hostname.
//     Throws an FormatException if the input is neither an IP address nor a hostname.
// </summary>
public static string ValidateIPOrHostname(string input)
{
    if (string.IsNullOrWhiteSpace(input))
        throw new FormatException("Input cannot be null or empty");

    // Try IP first
    if (IPAddress.TryParse(input, out _))
        return input;

    // Try hostname
    if (Uri.CheckHostName(input).Equals(UriHostNameType.Dns))
        return input;

    throw new FormatException($"'{input}' is neither a valid IP address nor hostname");
}

To safeguard against command injection, it is essential to adopt a series of preventive measures:

  1. Avoid Direct Command Execution with Untrusted Input: Avoid using functions for executing shell commands with untrusted inputs. Where command execution is necessary, parameterize inputs as separate command-line arguments, and do not concatenate untrusted inputs into shell commands.

  2. Input Validation and Whitelisting: Perform rigorous input validation to ensure that the input conforms to expected and safe formats. Whitelisting valid input patterns is preferable over blacklisting potentially harmful inputs.

  3. Escape Shell Metacharacters: If the input must be included in a command, ensure any shell metacharacters are properly blacklisted, escaped or sanitized using a dedicated library.

    Characters in { } ( ) < > & * ‘ | = ? ; [ ] ^ $ – # ~ ! . ” % / \ : + , \` are shell metacharacters for most OSes and shells.

    This is difficult to do well, and attackers have many ways of bypassing them so it is not recommended. You have been warned !

By implementing these practices, you can significantly minimize the potential for command injection vulnerabilities, enhancing the application’s resistance to this type of attack.

Configuration

The detector has the following configurable parameters:

  • sources, that indicates the source kinds to check.

  • neutralizations, that indicates the neutralization kinds to check.

Unless you need to change the default behavior, you typically do not need to configure this detector.

References