LA-CTF - Lucky flag


Challenge Description Link to heading

In this challenge, I was presented with a web page filled with thousands of buttons, all labeled “flag”.

Screenshot

The goal was to find the correct button that reveals the flag.


Step 1: Inspecting the Source Code Link to heading

Instead of clicking every single button, I looked into the main.js file which controls the behavior of the buttons.


Step 2: Analyzing main.js Link to heading

Key Observations Link to heading

const boxes = document.querySelectorAll('.box');
let flagbox = boxes[Math.floor(Math.random() * boxes.length)];
  • The script selects one random button (flagbox) from all the .box elements.
  • If the selected button is clicked, it reveals the flag.
for (const box of boxes) {
    if (box === flagbox) {
        box.onclick = () => {
            let enc = "\"\\u000e\\u0003\\u0001\\u0016\\u0004\\u0019\\u0015V\\u0011=\\u000bU=\\u000e\\u0017\\u0001\\t=R\\u0010=\\u0011\\t\\u000bSS\\u001f\"";

            for (let i = 0; i < enc.length; ++i) {
                try {
                    enc = JSON.parse(enc);
                } catch (e) {
                    break;
                }
            }

            let rw = [];
            for (const e of enc) {
                rw.push(e.charCodeAt(0) ^ 0x62);
            }

            const flag = rw.map(x => String.fromCharCode(x)).join('');
            alert(`Congrats ${flag}`);
        };
    } else {
        box.onclick = () => alert('no flag here');
    }
}

How is the Flag Hidden? Link to heading

  • The enc variable contains the flag encoded as Unicode escape sequences.
  • The script parses and decodes it with JSON.parse.
  • Each character is XOR-encrypted using 0x62 (decimal 98).
  • The decryption applies XOR again to restore the original characters.

Step 3: Extracting the Flag Link to heading

Instead of relying on luck, I decoded the string manually using JavaScript in the browser console.

Decryption Code Link to heading

let enc = "\"\\u000e\\u0003\\u0001\\u0016\\u0004\\u0019\\u0015V\\u0011=\\u000bU=\\u000e\\u0017\\u0001\\t=R\\u0010=\\u0011\\t\\u000bSS\\u001f\"";

for (let i = 0; i < enc.length; ++i) {
    try {
        enc = JSON.parse(enc);
    } catch (e) {
        break;
    }
}

let rw = [];
for (const e of enc) {
    rw.push(e.charCodeAt(0) ^ 0x62);
}

const flag = rw.map(x => String.fromCharCode(x)).join('');
console.log(flag);

Result Link to heading

Screenshot

lactf{w4s_i7_luck_0r_ski11}