Crumbs

Writeup for Crumbs (Web) - Angstrom CTF (2022) 💜

Video Walkthrough

Description

Follow the crumbs.

Source

const express = require("express");
const crypto = require("crypto");

const app = express();
const port = Number(process.env.PORT) || 8080;

const flag = process.env.FLAG || "actf{placeholder_flag}";

const paths = {};
let curr = crypto.randomUUID();
let first = curr;

for (let i = 0; i < 1000; ++i) {
    paths[curr] = crypto.randomUUID();
    curr = paths[curr];
}

paths[curr] = "flag";

app.use(express.urlencoded({ extended: false }));

app.get("/:slug", (req, res) => {
    if (paths[req.params.slug] === "flag") {
        res.status(200).type("text/plain").send(flag);
    } else if (paths[req.params.slug]) {
        res.status(200)
            .type("text/plain")
            .send(`Go to ${paths[req.params.slug]}`);
    } else {
        res.status(200).type("text/plain").send("Broke the trail of crumbs...");
    }
});

app.get("/", (req, res) => {
    res.status(200).type("text/plain").send(`Go to ${first}`);
});

app.listen(port, () => {
    console.log(`Server listening on port ${port}.`);
});

Solution

from pwn import *
import requests
from bs4 import BeautifulSoup

context.log_level = 'debug'
url = 'https://crumbs.web.actf.co/'

response = requests.get(url)  # Initial request

# Loop until we see the flag (1000 times)
while 'actf' not in response.text:
    # Extract the next slug from <p>
    extracted = BeautifulSoup(response.text, features="lxml").p.contents[0][6:]
    debug('extracted: %s', extracted)
    # Visit the new page
    response = requests.get(url + extracted)

# Print the response if we got the flag
extracted = BeautifulSoup(response.text, features="lxml").p.contents[0]
warn(extracted)

Last updated