constexpress=require("express");constcrypto=require("crypto");constapp=express();constport=Number(process.env.PORT) ||8080;constflag=process.env.FLAG||"actf{placeholder_flag}";constpaths= {};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); } elseif (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 requestsfrom bs4 import BeautifulSoupcontext.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'notin 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 flagextracted =BeautifulSoup(response.text, features="lxml").p.contents[0]warn(extracted)