app.get('/', function (req, res) { res.sendFile(__dirname + '/public/home.html'); });
functionwaf(code) { let pattern = /(process|\[.*?\]|exec|spawn|Buffer|\\|\+|concat|eval|Function)/g; if (code.match(pattern)) { thrownewError("what can I say? hacker out!!"); } }
app.post('/', function (req, res) { let code = req.body.code; let sandbox = Object.create(null); let context = vm.createContext(sandbox); try { waf(code); let result = vm.runInContext(code, context); console.log(result); } catch (e) { console.log(e.message); require('./hack'); } });
app.get('/secret', function (req, res) { if (process.__filename == null) { let content = fs.readFileSync(__filename, "utf-8"); return res.send(content); } else { let content = fs.readFileSync(process.__filename, "utf-8"); return res.send(content); } });
app.listen(3000, () => { console.log("listen on 3000"); });
1、可以看到三种解法中都有共同点,就是使用了throw new Proxy()和cc,使用throw new Proxy()是因为下面代码在输出沙盒的结果时使用try catch的结构(详细原理可见参考链接1),cc=arguments.callee.caller这个是取代了this的作用,作为global和sandbox之间的桥梁
示例:
1 2 3 4 5 6 7
throw new Proxy({}, { get: function(){ const cc = arguments.callee.caller; return cc } }) 运行这段代码之后,返回值为[Function (anonymous)],如果将return cc改为return cc()之后,返回值为const vm = require("vm");TypeError: require is not a function,可见cc其实是指向global中的require的