Intro to Whitebox Pentesting  

Eval Injection

In any whitebox pentesting exercise, we would use the skills and knowledge we obtained about various vulnerabilities learned from other modules in HackTheBox Academy and our experience. Each shortlisted function may be vulnerable to a different vulnerability, so the more knowledge we acquire, the more vulnerabilities we can identify.

As our findings are mainly linked to an eval function that may suffer from code injection, we will take a quick refresher on Code Injections. You should already have completed relevant modules on this topic, but if you still need to, complete the Command Injections module first. It is also recommended to complete other injection fundamentals modules, like Cross-Site Scripting (XSS) and SQL Injection Fundamentals.


Code Injection

All injection vulnerabilities include an attacker using user input to modify the way an application is executed. This is often done by injecting a string that escapes the bounds of the user input and affects the function that is using it. For example, in an SQL injection attack, the user input would affect the SQL query, and in a command injection, it would affect the command being executed.

What about code injection? A code injection vulnerability means that our input directly affects the application's code by injecting more code into it. Obviously, code injection vulnerabilities only affect interpreted/scripted languages, such as JavaScript or Python, which dynamically execute their source code during run-time.

For example, XSS vulnerabilities are considered code injection vulnerabilities, as we would inject HTML/JavaScript code into the page, which would then be run on the victim's machine.

If we can inject code on an application that runs on the backend, like NodeJS, then we may be able to cause more harm than a simple XSS. We could add more JavaScript code to the NodeJS server, which would run when the vulnerability is exploited.

Depending on the language and framework vulnerable to this attack, we may be unable to add arbitrary code, like importing additional libraries or running any functions. If we can run code that executes system commands or writes files to the system, we can reach remote command execution (RCE) on that system.


Code/Command Injection Functions

To identify a command/code injection vulnerability during a Whitebox Pentesting exercise, we can look for functions executing system commands or evaluating language code, especially if user input is entering them. The following are some of the functions that would do so "highlighted ones are for Code Injection, while others are for Command Injection":

JavaScript 'NodeJS' Python PHP C/C++ C# Java
eval eval eval execlp
Function exec exec execvp
setInterval subprocess.open proc_open ShellExecute
setTimeout subprocess.run popen
constructor.constructor os.system shell_exec
child_process.exec os.popen passthru system System.Diagnostics.Process.Start Runtime.getRuntime().exec
child_process.spawn system popen

User input going into such functions should always lead to further testing to ensure it is safely validated and sanitized. User input may also indirectly affect these and should be tested as a form of Second-order attacks as shown in the Modern Web Exploitation Techniques module.


Eval Injection

The eval function we have identified evaluates any text passed into it as code, meaning it runs it as JavaScript code. It is not the only JavaScript function that evaluates a string as JavaScript code, as other functions also do the same and may suffer from code injection. The following are some examples of the usage of such functions:

eval("console.log('test')");
new Function("console.log('test')")();
setTimeout("console.log('test')", 1000);
setInterval("console.log('test')", 1000);

As for code injection, if you are familiar with other forms of injection, then an eval injection should be easy to understand. All we need to do is escape the bounds of the user input and add more code to the eval function. For example, let's take the following basic example of an eval function:

eval("var i = '" + input + "'");

We can immediately tell this code is vulnerable, as our input is directly placed within the eval function without sanitization or validation. To inject code, all we need to do is close the first single quote ', then add our code. So, we can use the following input as our payload:

'; console.log("pwned"); ';

So, the final line would be the following:

eval("var i = ''; console.log('injection'); ''");

Exercise: Try to run the above line of code in any JavaScript interpreter "e.g. write it to a file, then run it with the node command. Was the word injection logged to the console?

This would execute the following JavaScript code:

var i = "";
console.log("injection");
("");

The console.log("injection"); part is our injected code, which the application would execute and run. This is a fundamental example to understand eval injections, but in the next section, we will dive deeper into eval injections and learn how to prepare payloads and confirm that we reach code injection properly.


validateString

Now that we understand eval injections, we can return to the validateString to see if it is vulnerable. As previously discussed, the function is only used once within the generateQR function, as follows:

!validateString(
  text,
  // provide verbose error message 'for admins only'
  role === "admin"
    ? `throw({message: 'The input "${text}" contains the following invalid characters: [${text.match(
        /['"`;]/g
      )}]', statusCode: 403})`
    : "throw({message: 'Invalid input', statusCode: 403})"
);

We know that the second parameter (onError) is what goes into eval, as we previously saw:

function validateString(input, onError) {
  if (...SNIP...) {
    eval(onError);
    return false;
  }
  return true;
}

When the validateString is used, the following is used for the onError parameter:

role === "admin"
  ? `throw({message: 'The input "${text}" contains the following invalid characters: [${text.match(
      /['"`;]/g
    )}]', statusCode: 403})`
  : "throw({message: 'Invalid input', statusCode: 403})";

Let's try to understand this code. The input depends on the role and changes whether it equals admin. If not, it would simply pass throw({message: 'Invalid input', statusCode: 403}) to the eval function. This code contains no user input, so we have no control over it. However, if the role is admin, then the following is the code passed to eval:

`throw({message: 'The input "${text}" contains the following invalid characters: [${text.match(
  /['"`;]/g
)}]', statusCode: 403})`;

We can ask AI to explain this code, but we do not need to in this case, as we can see that our input (${text}) is directly passed to this string. So, we must have an "admin" role to reach code injection, which we will attempt in the next section.

Note: If you are not familiar with JavaScript, the $ mark in ${text} when used with backticks in strings leads to String Interpolation. This places the content of the text variable into the string at that location, which may lead to code injection.

/ 1 spawns left

Waiting to start...

Questions

Answer the question(s) below to complete this Section and earn cubes!

+10 Streak pts

Previous

+10 Streak pts

Next