Intro to Whitebox Pentesting  

Target Function

Our next step is to test our theory of attack and confirm whether this function is vulnerable. We must plan our attack as action points to ensure each requirement is met to exploit the vulnerability successfully.

This helps us avoid certain issues that may break our attacks and know exactly where any issues may arise. If we directly jump to exploitation in certain advanced whitebox pentesting exercises, it may be difficult to diagnose why our attack is not working and waste a lot of our time.

Planning the Attack

So, what do we need to inject code into the eval function? Let's plan it:

  • [x] Hit the validateString function
  • [x] Trace how our input looks within the function
  • [ ] Obtain an admin role
  • [ ] Confirm that we reach the eval function
  • [ ] Prepare the payload
  • [ ] Confirm the payload reaches the target function as intended
  • [ ] Inject code and confirm code injection
  • [ ] Reach command execution or file writing
  • [ ] Blindly verify command execution/file writing
  • [ ] Automate the exploitation process by writing an exploit

As we can see, we split our attack into stages so that we can easily track our progress and identify where issues may arise. Our next step is to obtain the admin role, so let's see how to do that.

Admin Role

In a real-world web application, this can be achieved in multiple ways, such as:

  • Through a web privilege escalation vulnerability
  • Through an authorization flow
  • Through an XSS/CSRF attack against an admin user
  • By brute forcing an admin user account

And many other vulnerabilities that may lead to accessing an admin account. If there is no vulnerability that we are aware of to do so, then we can ask for an admin user. However, the vulnerability's impact would be lower since it would only affect a few users with an admin account.

In our case, to avoid chaining multiple vulnerabilities and stay focused on the whitebox pentesting process, we will go with the last option and assume we have an admin role. To obtain an admin authorization token, we only need to use an email with the @hackthebox.com domain, as we previously saw in the getUserToken function:

{
    email,
    role: email.includes("@hackthebox.com") ? "admin" : "user",
}

So, we will repeat the previous request we used to obtain an authorization token, but we'll change the email to the hackthebox.com domain:

[!bash!]$ curl -s -X POST -H "Content-Type: application/json" -d '{"email": "[email protected]"}' http://localhost:5000/api/auth/authenticate
{"token":"eyJhbGciOiJIUzI1N...SNIP...9R6zeoubrQTbUiThBpeQD7_DWibgo"}

We can use jwt.io to read the value of role within the JWT token, confirming that we successfully obtained admin. So, we can now cross obtain an admin role in our plan.

Exercise: Try to dynamically verify your role by adding a breakpoint to line 30 at controllers/service-controllers.js, and then right-clicking on role on line 17 and selecting Add to Watch. After that, send the previous QR code request using your new admin-role token, and when the application breaks, you can read the value of role under the WATCH menu on the left pane within the Run and Debug tab.

Reaching the Vulnerable Code

Let's go back to the validateString function to see how we can land at the vulnerable line of code:

function validateString(input, onError) {
  if (
    typeof input !== "string" ||
    input.length == 0 ||
    input.match(/['"`;]/g)
  ) {
    eval(onError);
    return false;
  }
  return true;
}

The eval function is only reached if one or more conditions are true, since an OR operator is used between the conditions. As previously discussed, these are the three conditions:

  1. if the input is not a string (e.g. a number or object)
  2. if the input length is 0
  3. if the input matches the specified regular expression pattern

However, we also need to have our input going into the onError string, so if we use an empty string (length of 0) or use something other than a string, we would not have a way to inject code into onError. So, we are left with the third option to use one of the specified bad characters to reach it. We must be careful, though, to avoid breaking the code.

So, let's try using a semi-colon ;, as this would not break out of the onError string discussed in the previous section. Our JSON payload would be the following:

{ "text": ";" }

Once we send our request, we get the following output:

[!bash!]$ curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1N...SNIP...9R6zeoubrQTbUiThBpeQD7_DWibgo" -d '{"text": ";"}' http://localhost:5000/api/service/generate
{"message":"The input ";" contains the following invalid characters: [;]"}

Excellent! This is the vulnerable verbose error message only shown to admins, meaning that we landed in the eval function and that the eval function successfully evaluated the onError string without breaking the application. Now that we can reach the vulnerable line of code, our next step is to prepare our payload to inject code into the eval function, which is what we will do in the next section.

/ 1 spawns left

Waiting to start...

Optional Exercises

Challenge your understanding of the Module content and answer the optional question(s) below. These are considered supplementary content and are not required to complete the Module. You can reveal the answer at any time to check your work.

Previous

+10 Streak pts

Next