Skip to main content

Inappropriate coding practices - Eval function

Need

Secure input validation and sanitization

Context

  • Usage of C# for building robust and scalable applications
  • Usage of Microsoft.CSharp for dynamic compilation and execution of C# code
  • Usage of System.CodeDom.Compiler for dynamic code compilation

Description

Non compliant code

public IActionResult UnsafeEval(string command)
{
var result = Eval(command);
return Ok(result);
}

private object Eval(string command)
{
return Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp")
.CompileAssemblyFromSource(new System.CodeDom.Compiler.CompilerParameters(), "public static class Foo{ public static object Bar() { return " + command + "; } }")
.CompiledAssembly
.GetType("Foo")
.GetMethod("Bar")
.Invoke(null, null);
}

The above code is an example of a vulnerable C# backend application that uses the ASP.NET Core framework. The UnsafeEval method takes a string parameter command, which is then passed to the Eval method. The Eval method uses the Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp") method to compile and execute the command.

The vulnerability lies in the Eval method, specifically in the way it handles the command parameter. The command parameter is directly concatenated into the C# code string that is compiled and executed. This code is not validated or sanitized before it is executed.

This means that an attacker could inject malicious code into the command parameter. For example, if an attacker sends a request with a command parameter value of System.IO.File.Delete("importantFile.txt"), the server would execute this command and delete the "importantFile.txt" file.

This is an example of an injection vulnerability, where untrusted input is allowed to be part of a command or query that is then executed by the server. In this case, the injection happens in the C# code that is compiled and executed by the Eval method. This vulnerability could lead to serious security issues, such as data loss, data corruption, or even full system compromise.

Steps

  • Avoid using the eval function altogether.
  • Validate and sanitize all user input before using it in any code execution.
  • Use parameterized queries or prepared statements to prevent SQL injection.
  • Implement a strict input validation mechanism to ensure that only expected input is accepted.
  • Implement a whitelist approach for input validation, allowing only specific characters or patterns.
  • Implement output encoding to prevent cross-site scripting (XSS) attacks.
  • Implement proper exception handling to prevent sensitive information leakage.
  • Regularly update and patch the application and its dependencies to fix any known vulnerabilities.

Compliant code

public IActionResult SafeEval(string command)
{
if (IsValid(command))
{
var result = Eval(command);
return Ok(result);
}
else
{
return BadRequest("Invalid command");
}
}

private bool IsValid(string command)
{
// Implement your validation logic here
// For example, you can check if the command contains only allowed characters
// or matches a certain pattern
// This is a very basic example and might not cover all possible cases
return Regex.IsMatch(command, @"^[a-zA-Z0-9]*$");
}

private object Eval(string command)
{
return Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp")
.CompileAssemblyFromSource(new System.CodeDom.Compiler.CompilerParameters(), "public static class Foo{ public static object Bar() { return " + command + "; } }")
.CompiledAssembly
.GetType("Foo")
.GetMethod("Bar")
.Invoke(null, null);
}

The original code was vulnerable because it used the Eval function with unvalidated user input, which could lead to code injection attacks. The Eval function is dangerous because it executes the string it is passed as code. If an attacker can control the string that is passed to Eval, they can execute arbitrary code.

The fixed code adds an IsValid function that validates the command before it is passed to Eval. The validation function checks if the command contains only alphanumeric characters. This is a very basic validation and might not cover all possible cases. Depending on the context of your application, you might need to implement a more complex validation logic.

Please note that using Eval is generally discouraged because of its potential security risks. If possible, consider refactoring your code to avoid using Eval. If you must use Eval, make sure to validate and sanitize all user input thoroughly.

References