The eval function in JavaScript is a powerful but potentially dangerous feature. Its primary purpose is to execute arbitrary JavaScript code represented as a string.

There are four standard ways to evaluate strings in JavaScript:

  • eval("code")
  • new Function("code")
  • setTimeout("code", timeout)
  • setInterval("code", interval)

Example

1. This is a calculator application that prints the mathematical results on screen

2. Since, I had access to the source code I found this piece of code that demonstrated how the eval() function is in use

// Exporting an object with a method named 'calculate'
module.exports = {
    calculate(formula) { // Try block to handle potential errors during execution
        try {
// Using eval to execute a dynamically created function
// The function is created using a template literal, incorporating the 'formula' parameter
// The closing parentheses () immediately follows the function body, invoking the function. This pattern is known as an Immediately Invoked Function Expression (IIFE).
            return eval(`(function() { return ${ formula } ;}())`);
        
// Catch block to handle potential errors, specifically SyntaxError
        } catch (e) {
// Checking if the caught error is an instance of SyntaxError
            if (e instanceof SyntaxError) {
// Returning an error message if a SyntaxError occurs
                return 'Something went wrong!';
            }
        }
    }
}

Exploitation

1. First we need to understand how the application works

2. We try to make it crash

3. We can try to use some JavaScript functions and see if they get executed since this script doesn’t have sanitization we don’t need to worry about

  • process.platform
  • process.cwd()

4. Now we know we can execute commands we can try a more sophisticated command

  • require('child_process').execSync('ls -l').toString()

require('child_process'):

  • This part of the code imports the child_process module in Node.js. The child_process module provides functionality to spawn child processes, allowing you to execute external commands.

.execSync('ls -l'):

  • The execSync function is a synchronous method in the child_process module. It is used to execute shell commands synchronously, meaning the code will block until the command completes. In this case, it runs the ls -l command, which lists the contents of the current directory in long format.

.toString():

  • The result of execSync is a Buffer object containing the output of the command. The .toString() method is then used to convert the Buffer object into a string. This is necessary if you want to work with the command output as a string in your Node.js code.

Recommendations

Avoid eval Completely:

  • The safest approach is to avoid using eval altogether unless absolutely necessary. Most use cases for eval can be replaced with safer alternatives.

Use JSON.parse or Other Specific Functions:

  • If you need to parse JSON data, use JSON.parse instead of eval. JSON.parse is safer and only evaluates valid JSON data, reducing the risk of code injection.

Function Constructors:

  • If dynamic code execution is required, consider using the Function constructor. This is generally safer than eval because it creates a new function scope.

Validate and Sanitize User Inputs:

  • If you must use dynamically generated code, thoroughly validate and sanitize user inputs before incorporating them into the code. Ensure that the input adheres to expected patterns and does not contain malicious content.

Code Review and Static Analysis:

  • Regularly review code for potential security vulnerabilities, including the use of eval. Utilize static analysis tools to identify insecure patterns in your codebase.