Skip to main content

OS Command Injection

Need

Prevention of OS command injection attacks

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of sys.process for executing system processes in Node.js
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework

Description

Non compliant code

import sys.process._
import play.api.mvc._

class VulnerableController extends Controller {
def executeCommand(command: String) = Action {
val result = command.!
Ok(result.toString)
}
}

This Scala code with Play Framework is an example of an OS command injection vulnerability.

The executeCommand function takes a command string as an argument that is then directly used in the execution of a system process (command.!). This means any string passed into this function will be executed as a command in the system's shell.

This is highly dangerous as it allows an attacker to execute arbitrary commands on the server where the application is hosted. For example, an attacker could pass a command to list all files in the server's file system, delete files, or even download and execute malicious software.

The vulnerability exists because the application does not sanitize or validate the command input in any way before executing it. This means the application implicitly trusts all input to be safe, which is a dangerous assumption.

To exploit this vulnerability, an attacker simply needs to pass a malicious command string to the executeCommand function. For example, ; rm -rf / would delete all files on the server if the application has sufficient permissions.

In conclusion, this code is highly vulnerable to OS command injection attacks and should be fixed immediately by sanitizing and validating all inputs, and by avoiding the direct execution of system commands whenever possible.

Steps

  • Validate and sanitize user input: Before executing any command, ensure that the input is properly validated and sanitized to prevent any malicious commands from being executed.
  • Use parameterized commands: Instead of directly executing user input as a command, use parameterized commands or prepared statements to ensure that the input is treated as data and not as executable code.
  • Implement command whitelisting: Maintain a whitelist of allowed commands and validate the user input against this whitelist to restrict the execution to only trusted commands.
  • Limit privileges: Run the application with the least privileges necessary to execute the required commands. Avoid running the application with root or administrator privileges.
  • Implement input validation: Validate the user input against a strict set of rules to ensure that it only contains the expected characters and does not include any special characters or command separators.
  • Implement proper error handling: Handle any errors or exceptions that may occur during command execution to prevent sensitive information from being leaked to the attacker.
  • Regularly update and patch dependencies: Keep all dependencies, including the Play framework, up to date with the latest security patches to mitigate any known vulnerabilities.
  • Perform security testing: Regularly conduct security testing, including penetration testing and code reviews, to identify and fix any potential vulnerabilities in the application.

Compliant code

import sys.process._
import play.api.mvc._
import scala.util.matching.Regex

class SecureController extends Controller {
private val allowedCommands = Set("ls", "date", "whoami") // Whitelisted commands
private val commandPattern: Regex = "^[a-zA-Z]*$".r // Regex pattern to validate command

def executeCommand(command: String) = Action {
commandPattern.findFirstIn(command) match {
case Some(validCommand) if allowedCommands.contains(validCommand) =>
val result = Seq("/bin/sh", "-c", validCommand).!
Ok(result.toString)
case _ =>
BadRequest("Invalid command")
}
}
}

The updated code includes several security measures to prevent OS command injection:

  1. Command Whitelisting: A set of allowed commands (allowedCommands) is defined. Only these commands can be executed, which significantly reduces the attack surface.

  2. Input Validation: The commandPattern regex is used to validate the command input. This pattern only allows alphabetical characters, preventing the use of special characters that could be used to chain or modify commands.

  3. Parameterized Command Execution: The Seq("/bin/sh", "-c", validCommand).! line executes the command in a parameterized manner. This ensures that the command input is treated as a single argument to the shell command, rather than as part of the command itself.

  4. Error Handling: If the command is not valid or not in the whitelist, a BadRequest response is returned. This prevents the execution of potentially harmful commands.

Remember to always run your application with the least privileges necessary, regularly update and patch your dependencies, and perform security testing to identify and fix potential vulnerabilities.

References