Final result.

image.png

image.png

Web

Giving up the game

First I inspect the front-end code of this challenge. It mocks up a loading screen that runs infinitely.

    const tips = [
        "Tip: Collect all power-ups to upgrade your ship! 💥",
        "Tip: Watch out for asteroids in Sector 7! 🪨",
        "Tip: Shields down! Restore power to your defenses! ⚡",
        "Tip: New ship parts available at the space station! 🚀",
        "Tip: Find the hidden treasure on Planet Zog! 🌌"
    ];

    let tipIndex = 0;
    const tipElement = document.querySelector('.fake-tips');

    setInterval(() => {
        tipIndex = (tipIndex + 1) % tips.length;
        tipElement.textContent = tips[tipIndex];
    }, 7000); // Change tips every 7 seconds
        fetch('/getSprites')
            .then(response => response.json())
            .then(data => {
                console.log("VGhhbmsgeW91IE1hcmlvISBCdXQgb3VyIHByaW5jZXNzIGlzIGluIGFub3RoZXIgY2FzdGxlIQ==");
            });       
    

An endpoint was mentioned - /getSprites .

The message in console log is in base64 which translates to “Thank you Mario! But our princess is in another castle!”

However, the response data from /getSprites is the flag in base64.

image.png

Flag: poctf{uwsp_1_7H1nk_7H3r3r0_1_4m}

I have a complaint

The web challenge mimic a live broadcast with live chat (I can’t chat). However, there is a “report abuse/service issue” button which leads to /complaint endpoint.

image.png

This endpoint is vulnerable to XSS. The challenge also mentione a /flag endpoint which probably deny any request not from local machine.

image.png

The objective is clear: use XSS to do SSRF and get the flag from /flag endpoint.

<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', '/flag', true);
xhr.onload = function () {
    if (xhr.status === 200) {
        console.log(xhr.responseText);
    } else {
        console.error('Error:', xhr.statusText);
    }
};
xhr.send();
</script>

! This doesn’t work, I still get code 403 - Forbidden.