hacktricks/pentesting-web/deserialization/nodejs-deserialization-__proto__-abuse.md

66 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NodeJS deserialization \_\_proto\_\_ abuse
This information was copied from this research: [https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)
While I was researching packages, I stumbled upon the idea to look at other approaches of attacks on deserialization, which are used in other languages. To achieve code execution we leverage functions with attackers controlled data which are called automatically during the deserialization process or after when an application interacts with a newly created object. Something similar to “magic methods” in other languages.
Actually, there are a lot of packages which work completely differently, still after some experiments I came to an interesting semi-universal attack. It is based on two facts.
Firstly, many packages use the next approach in the deserialization process. They create an empty object and then set its properties using square brackets notations:
```text
obj[key]=value
```
where **key** and **value** are taken from JSON
Therefore we as attackers are able to control practically any property of a new object. If we look through the list of properties, our attention comes to the [cool \_\_proto\_\_ property ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto). The property is used to access and change a prototype of an object. This means that we can change the objects behavior and add/change its methods.
Secondly, a call of some function leads to the invoking of the function arguments methods. For example, when an object is converted to a string, then methods valueOf, toString of the object are called automatically \(more details [here](http://2ality.com/2012/03/converting-to-string.html)\). So, `console.log(obj)` leads to invocation of `obj.toString()`. Another example, `JSON.stringify(obj)` internally invokes obj.toJSON\(\).
Using both of these features, we can get remote code execution in process of interaction between an application `(node.js)` and an object.
Ive found a nice example [package Cryo](https://www.npmjs.com/package/cryo), which supports both function serialization and square bracket notation for object reconstruction, but which isnt vulnerable to IIFE, because it properly manages object \(without using `eval&co`\).
Here a code for serialization and deserialization of an object:
```text
cvar Cryo = require('cryo');
var obj = {
testFunc : function() {return 1111;}
};
var frozen = Cryo.stringify(obj);
console.log(frozen)
var hydrated = Cryo.parse(frozen);
console.log(hydrated);
```
Serialized JSON looks like that. Pretty tangled:
```text
{"root":"_CRYO_REF_1","references":[{"contents":{},"value":"_CRYO_FUNCTION_function () {return 1111;}"},{"contents":{"testFunc":"_CRYO_REF_0"},"value":"_CRYO_OBJECT_"}]}
```
For our attack we can create a serialized JSON object with a `custom __proto__`. We can create our object with our own methods for the objects prototype, but as a small trick, we can set an incorrect name for `__proto__` \(because we dont want to rewrite a prototype of the object in our application\) and serialize it.
```text
var obj = {
__proto: {
toString: function() {console.log("defconrussia"); return 1111;},
valueOf: function() {console.log("defconrussia"); return 2222;}
}
};
```
So we get serialized object and rename from `__proto` to `__proto__` in it:
```text
{"root":"CRYO_REF_3","references":[{"contents":{},"value":"_CRYO_FUNCTION_function () {console.log(\"defconrussia\"); return 1111;}"},{"contents":{},"value":"_CRYO_FUNCTION_function () {return 2222;}"},{"contents":{"toString":"_CRYO_REF_0","valueOf":"_CRYO_REF_1"},"value":"_CRYO_OBJECT"},{"contents":{"proto":"CRYO_REF_2"},"value":"_CRYO_OBJECT"}]}
```
When we send that JSON payload to an application, the package Cryo deserializes the payload in an object, but also changes the objects prototype to our value. Therefore, if the application interacts with the object somehow, converts it to a sting, for example, then the prototypes method will be called and our code will be executed. So, its RCE.
I tried to find packages with similar issues, but most of them didnt support serialization of function. I didnt find any other way to reconstruct `functions in __proto__`. Nevertheless, as many packages use square bracket notation, we can rewrite `__proto__` for them too and spoil prototypes of newly created objects. What happens when an application calls any prototype method of such objects? It may crash due to an unhandled TypeError exception.
In addition, I should mention that the whole idea potentially works for deserialization from any format \(not only JSON\). Once both features are in place, a package is potentially vulnerable. Another thing is that `JSON.parse` is not “vulnerable” to `__proto__ rewriting`.