Skip to main content

OS Command Injection

Need

Prevention of OS Command Injection attacks

Context

  • Usage of Python 3 for writing and executing Python code
  • Usage of OS for accessing and interacting with operating system functionalities
  • Usage of Django for building web applications in Python

Description

Non compliant code

import os
from django.http import HttpResponse

def run_command(request):
command = request.GET.get('command')
result = os.system(command)
return HttpResponse(result)

The above code is a simple Django view that takes a command from the HTTP GET parameters and executes it on the server using os.system(). This is a clear example of an OS command injection vulnerability, as it allows any user to run arbitrary commands on the server.

In this case, the command parameter is directly taken from the user input (HTTP GET parameter) without any sanitization or validation. This means that an attacker could inject any command they want. For example, they could use the ; character to add additional commands, or use command substitution with $(command) to execute the output of another command.

Moreover, the os.system() function is used to execute the command, which is a high-risk function as it executes the command in a subshell, allowing the command to interact with the environment, change directories, read and write files, and even spawn new processes.

This can lead to a variety of attacks, including but not limited to: data theft, data modification, denial of service, or even full system compromise if the application is running with high privileges.

Steps

  • Validate and sanitize the input: Ensure that the 'command' parameter is strictly validated against a whitelist of allowed commands. Any input that does not strictly match the whitelist should be rejected.
  • Use safer functions: Instead of using 'os.system', which executes the command in a subshell, use safer functions like 'subprocess.run' or 'os.execv'. These functions do not invoke a shell and hence are not susceptible to shell injection attacks.
  • Limit privileges: Run the application with the least privileges necessary. This can limit the potential damage if an attacker does manage to execute arbitrary commands.
  • Implement error handling: Implement proper error handling so that detailed system information is not leaked to the user, which could aid an attacker.
  • Use a Web Application Firewall (WAF): A WAF can help to filter out malicious input, providing an additional layer of security.

Compliant code

import os
import subprocess
from django.http import HttpResponse
from django.core.exceptions import ValidationError

ALLOWED_COMMANDS = ['ls', 'date', 'uptime'] # Define your own list of allowed commands

def validate_command(command):
if command not in ALLOWED_COMMANDS:
raise ValidationError(f'Invalid command: {command}')

def run_command(request):
command = request.GET.get('command')
validate_command(command)
result = subprocess.run([command], capture_output=True, text=True)
return HttpResponse(result.stdout)

The updated code includes several changes to mitigate the risk of OS Command Injection:

  1. Input Validation and Sanitization: The validate_command function is introduced to validate the 'command' parameter against a whitelist of allowed commands (ALLOWED_COMMANDS). If the command is not in the whitelist, a ValidationError is raised. This ensures that only predefined, safe commands can be executed.

  2. Safer Function Usage: The os.system function is replaced with subprocess.run. Unlike os.system, subprocess.run does not invoke a shell by default, making it less susceptible to shell injection attacks. The capture_output=True argument is used to capture the command's output, and text=True is used to return the output as a string.

  3. Error Handling: Django's built-in ValidationError is used for error handling. If an invalid command is provided, a clear, user-friendly error message is returned without revealing any sensitive system information.

  4. Privilege Limitation and Web Application Firewall (WAF): These are not reflected in the code but are important considerations. The application should be run with the least privileges necessary to limit potential damage from an attack. Additionally, using a WAF can provide an extra layer of security by filtering out malicious input.

References