[GYCTF2020]Node Game
最近把JavaScript入了一下门,就顺便做了个js题目
源码
app.get('/', function(req, res) {
const action = req.query.action ? req.query.action : "index";
if( action.includes("/") || action.includes("\\") ){
res.send("Errrrr, You have been Blocked");
}
let file = path.join(__dirname + '/template/' + action + '.pug');
const html = pug.renderFile(file);
res.send(html);
});
app.post('/file_upload', function(req, res){
const ip = req.connection.remoteAddress;
let obj = {
msg: '',
};
if (!ip.includes('127.0.0.1')) {
obj.msg="only admin's ip can use it"
res.send(JSON.stringify(obj));
return
}
fs.readFile(req.files[0].path, function(err, data){
if(err){
obj.msg = 'upload failed';
res.send(JSON.stringify(obj));
}else{
const file_path = '/uploads/' + req.files[0].mimetype + "/";
const file_name = req.files[0].originalname;
const dir_file = __dirname + file_path + file_name;
if(!fs.existsSync(__dirname + file_path)){
try {
fs.mkdirSync(__dirname + file_path)
} catch (error) {
obj.msg = "file type error";
res.send(JSON.stringify(obj));
return
}
}
try {
fs.writeFileSync(dir_file,data)
obj = {
msg: 'upload success',
filename: file_path + file_name
}
} catch (error) {
obj.msg = 'upload failed';
}
res.send(JSON.stringify(obj));
}
})
})
app.get('/source', function(req, res) {
res.sendFile(path.join(__dirname + '/template/source.txt'));
});
app.get('/core', function(req, res) {
const q = req.query.q;
const resp = "";
if (q) {
const url = 'http://localhost:8081/source?' + q;
console.log(url)
const trigger = blacklist(url);
if (trigger === true) {
res.send("<p>error occurs!</p>");
} else {
try {
http.get(url, function(resp) {
resp.setEncoding('utf8');
resp.on('error', function(err) {
if (err.code === "ECONNRESET") {
console.log("Timeout occurs");
return;
}
});
resp.on('data', function(chunk) {
try {
resps = chunk.toString();
res.send(resps);
}catch (e) {
res.send(e.message);
}
}).on('error', (e) => {
res.send(e.message);});
});
} catch (error) {
console.log(error);
}
}
} else {
res.send("search param 'q' missing!");
}
})
function blacklist(url) {
const evilwords = ["global", "process", "mainModule", "require", "root", "child_process", "exec", "\"", "'", "!"];
const arrayLen = evilwords.length;
for (var i = 0; i < arrayLen; i++) {
const trigger = url.includes(evilwords[i]);
if (trigger === true) {
return true
}
}
}
就简单贴几个路由和过滤函数
根目录是解析一个template目录下的pug文件并返回,查了一下pug就是一个渲染模板一类的东西,可以在里面写一些代码进行渲染,命令执行估计是靠这个
file_upload路由需要remote_address是localhost,必然需要找一个ssrf点,上传一个文件到对应的mimetype文件夹下,mimetype即为文件上传部分的content-type(注意不是请求头中的content-type)
source路由展示源码,写死了无法控制
core路由是一个ssrf点,但是路由写死了source,后面的参数q可控,但需要通过blacklist的检测