Command Execution - pallavitewari21/Secure-Code GitHub Wiki
Remote code execution is a major security lapse, and the last step along the road to complete system takeover. After gaining access, an attacker will attempt to escalate their privileges on the server, install malicious scripts, or make your server part of a botnet to be used at a later date.
If your application calls out to the operating system, you need to be sure command strings are securely constructed, or else you risk having malicious instructions injected by an attacker. This section outlines a few approaches to protecting yourself.
Try to Avoid Command Line Calls Altogether
Modern programming languages have interfaces that permit you to read files, send emails, and perform other operation system functions. Use APIs wherever possible – only use shell commands where absolutely necessary. This will reduce the number of attack vectors in your application, and will also simplify your codebase.
Escape Inputs Correctly
Injection vulnerabilities occur when untrusted input is not sanitized correctly. If you use shell commands, be sure to scrub input values for potentially malicious characters:
;
&
|
`
Even better, restrict input by testing it against a regular expression of known safe characters. (For example, alphanumeric characters.)
Restrict the Permitted Commands
Try to construct all or most of your shell commands using string literals, rather than user input. Where user input is required, try to whitelist permitted values, or enumerate them in a conditional statement.
Perform Thorough Code Reviews
Check system calls for vulnerabilities as a part of your code review process. Vulnerabilities often creep in over time – make sure your team knows what to look for.
Run with Restricted Permissions
It is a good practice to run your server processes with only the permissions that they require to function – the principle of least privilege. This can help limit the impact of command injection vulnerabilities as a second line of defense.
Make sure each web server process can only access the directories that it needs, and narrow down the directories in which they write or execute files. Consider running the process in a chroot jail if you are running on Unix. This will limit the ability of maliciously injected code to “climb out” of a directory."
The code samples below illustrate how to safely make command-line calls in various languages.
Python
New processes are spawned in python using the modules popen2, os, commands, and subprocess. subprocess is the preferred API (the others are deprecated and replaced by it). The subprocess module has built-in protection against command execution:
from subprocess import call
# An invocation of the call(...) function will ensure only a single
# command is run.
call([""ls"", ""-l""])
This protection can be disabled – be on the lookout for anything that opens a process in the following manner:
from subprocess import call
# shell=True disables command injection checking.
call(""cat "" + filename, shell=True)
Ruby
Ruby offers a multitude of ways to make command line calls:
eval ""ls -l""
system ""ls -l""
`ls -l` # Backticks indicate an OS command to be executed.
Kernel.exec(""ls -l"")
%x( ls -l )
open(""|date"") do |cmd|
print cmd.gets
end
If you must use command line calls in your application, be sure to sanitize inputs using the Shellwords module:
open(""| grep #{Shellwords.escape(pattern)} file"") { |pipe| # ... }
Java
Since Java is run in a virtual machine, command-line calls are generally discouraged. They can be executed using the java.lang.Runtime API, however:
Runtime.getRuntime().exec(""ls -l"");
The call to exec(...) will tokenize the input and make sure only a single command is run. Just be sure not to write your own tokenizer!
.NET
There are a couple of ways to access the command line in C#, though .NET has a very comprehensive set of standard libraries, so you will rarely need to:
System.Diagnostics.Process.Start(""CMD.exe"", ""ls -l"");
var process = new ProcessStartInfo();
process.UseShellExecute = true;
process.WorkingDirectory = @""C:\Windows\System32"";
process.FileName = @""C:\Windows\System32\cmd.exe"";
process.Verb = ""runas"";
process.Arguments = ""/c ls -l"";
Process.Start(process);
Node
The usual way of invoking shell commands in Node is using the child_process module. This is a wrapper around bin.sh, so concatenating command strings is risky:
var child_process = require('child_process');
child_process.exec('ls -l ' + input_path, function (err, data) {
console.log(data);
});
Instead, use one of the functions that take arrays as arguments:
child_process.execFile('/bin/ls', ['-l', input_path], function (err, result) {
console.log(result)
});
var ls = child_process.spawn('/bin/ls', ['-l', input_path])
PHP Making command-line calls in PHP is fairly common, and there are a number of ways to make them:
shell_exec ""ls -l""
exec ""ls -l""
passthru ""ls -l""
system ""ls -l""
`ls -l`
Be careful to sanitize the inputs to any of these functions.