Command Injection in Aspnet
How Command Injection Manifests in Aspnet
Command injection in Aspnet applications occurs when untrusted user input is passed directly to operating system commands or shell processes. Aspnet's tight integration with the Windows ecosystem and .NET runtime creates specific attack vectors that developers must understand.
The most common Aspnet command injection patterns involve Process.Start() calls with unsanitized input. Consider this vulnerable Aspnet Core controller:
[HttpGet("/api/files")]
public IActionResult GetFiles([FromQuery] string path) {
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = $"/c dir {path}",
RedirectStandardOutput = true,
UseShellExecute = false
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
return Ok(output);
}
An attacker could exploit this with: ?path=C:\&&whoami, causing the command to execute dir C:\&&whoami and reveal system information.
Another Aspnet-specific pattern involves Process.Start() with arrays where arguments aren't properly validated:
public IActionResult ExecuteCommand([FromQuery] string executable, [FromQuery] string args) {
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = executable,
Arguments = args,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
process.Start();
return Ok(process.StandardOutput.ReadToEnd());
}
This allows arbitrary command execution since both parameters are user-controlled. Aspnet's default configuration doesn't sandbox these processes, giving attackers the same privileges as the application pool identity.
System.Diagnostics.Process is the primary vector, but Aspnet applications also face risks from:
- System.IO.File operations with path traversal combined with command execution
- Process.Start() with UseShellExecute = true, which can invoke file associations
- System.Diagnostics.ProcessStartInfo's EnvironmentVariables collection manipulation
- Windows Management Instrumentation (WMI) calls from Aspnet code
The Aspnet Core hosting model on Windows Server adds another layer of risk. If the application runs under a privileged service account and uses impersonation incorrectly, command injection can escalate to SYSTEM-level access.
Aspnet-Specific Detection
Detecting command injection in Aspnet requires both static code analysis and runtime scanning. Static analysis tools should flag Process.Start() calls where arguments contain user input without validation.
middleBrick's black-box scanner identifies Aspnet command injection by sending payloads through all HTTP parameters and analyzing responses. For Aspnet applications, it specifically tests:
- Process.Start() with common Windows commands (cmd.exe, powershell.exe, wmic.exe)
- Argument splitting patterns that Aspnet's ProcessStartInfo might misinterpret
- Environment variable injection through ProcessStartInfo.EnvironmentVariables
- Path traversal combined with command execution attempts
The scanner uses Aspnet-specific payloads like:
?input=valid.txt%26echo+INJECTED
?input=C%3A%5C%26whoami
?input=test%26%26net+user
These URL-encoded payloads test whether the Aspnet application properly sanitizes input before passing it to system commands.
For development teams, middleBrick's GitHub Action can be configured to scan Aspnet APIs in CI/CD pipelines:
name: API Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run middleBrick Scan
run: |
npm install -g middlebrick
middlebrick scan https://your-aspnet-api.com --fail-below B
continue-on-error: false
This ensures command injection vulnerabilities are caught before deployment to production Aspnet servers.
Runtime detection in production Aspnet applications should include monitoring for unusual Process.Start() patterns and logging all system command executions with their originating user context.
Aspnet-Specific Remediation
Remediating command injection in Aspnet requires a defense-in-depth approach. The primary fix is eliminating Process.Start() calls entirely when possible, replacing them with managed .NET APIs.
For file operations that might tempt developers to use shell commands:
// Vulnerable - uses dir command
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = $"/c dir {path}",
UseShellExecute = false
}
};
// Secure - uses .NET APIs
var directory = new DirectoryInfo(path);
var files = directory.GetFiles();
var directories = directory.GetDirectories();
return Ok(new { files, directories });
When system commands are unavoidable in Aspnet applications, implement strict input validation and use ProcessStartInfo.ArgumentList (available in .NET 5+) instead of Arguments string:
public IActionResult SafeExecute([FromQuery] string filePath) {
if (string.IsNullOrEmpty(filePath) ||
filePath.Contains("..") ||
filePath.Contains(":") ||
!filePath.EndsWith(".txt")) {
return BadRequest("Invalid file path");
}
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "powershell.exe",
ArgumentList = new List<string> {
"-Command",
$"Get-Content '{filePath}'"
},
RedirectStandardOutput = true,
UseShellExecute = false
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
return Ok(output);
}
ArgumentList prevents argument injection by treating each element as a separate argument, even if they contain spaces or special characters.
For Aspnet Core applications, configure the process execution context with minimal privileges:
public void ConfigureServices(IServiceCollection services) {
services.Configure<ProcessOptions>(options => {
options.StartInfo = new ProcessStartInfo {
UserName = "app_user",
LoadUserProfile = false,
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory
};
});
}
Additionally, implement a custom middleware in Aspnet to log and validate all Process.Start() calls:
public class ProcessSecurityMiddleware
{
private readonly RequestDelegate _next;
private static readonly HashSet<string> AllowedCommands =
new() { "git", "dotnet", "node" };
public ProcessSecurityMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var originalStart = typeof(Process).GetMethod(
"Start", BindingFlags.Instance | BindingFlags.Public);
var safeStart = new Action<Process>(process => {
var command = Path.GetFileNameWithoutExtension(
process.StartInfo.FileName);
if (!AllowedCommands.Contains(command)) {
throw new SecurityException($"Command {command} not allowed");
}
process.Start();
});
await _next(context);
}
}
This middleware approach provides runtime protection against unauthorized command execution in Aspnet applications.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |