Description
Only those who use the official PicoBrowser are allowed on this site.
Setup
Access the challenge URL and observe what the server demands.
curl http://mercury.picoctf.net:38322/Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Set the User-Agent to picobrowserObservationI noticed the challenge description explicitly says 'Only those who use the official PicoBrowser are allowed on this site,' which suggested the server checks the User-Agent header and that setting it to 'picobrowser' would be the first gate to pass.The server checks User-Agent first. Set it to picobrowser. Each failed check returns the next requirement in plain text.bashcurl --user-agent "picobrowser" http://mercury.picoctf.net:38322/What didn't work first
Tried: Sending -H 'User-Agent: PicoBrowser' with capital letters
The server does a case-sensitive string match against 'picobrowser' (all lowercase). Sending 'PicoBrowser' or 'Picobrowser' returns the same 'Sorry, you can only access this server with picobrowser.' error. The --user-agent curl flag sets the header value exactly as typed, so the exact lowercase string is required.
Tried: Using a browser with a User-Agent switcher extension and navigating to the URL
Browser extensions that spoof User-Agent work for the first check but the browser cannot easily set arbitrary Referer, Date, DNT, X-Forwarded-For, or Accept-Language headers on a plain navigation request. You will pass the first gate and stall at the second. curl with explicit -H flags is the right tool because it gives full control over every header in the request.
Learn more
The User-Agent header identifies the client software. Servers cannot trust it. Check responses look something like:
# Wrong UA "Sorry, you can only access this server with picobrowser." # Right UA, wrong Referer "Sorry, you can only access this website by clicking through from our official site." # Right UA + Referer, wrong Date "Sorry, this site only worked in 2018."Each error message points at the next required header. Read it carefully and add one header per request. See web bug patterns for why header-based access controls always lose.
Step 2
Add Referer, Date, DNT, XFF, Accept-LanguageObservationI noticed the server returned a new plain-text error message after each header was accepted, describing the next missing requirement, which suggested working through the remaining five checks (Referer, Date, DNT, X-Forwarded-For, Accept-Language) one at a time until all gates passed.Six checks total. Add each header one at a time, reading the next error message between requests. The full set: Referer matches the site itself, Date in 2018, DNT 1, X-Forwarded-For from a Swedish IP, Accept-Language Swedish.bashcurl http://mercury.picoctf.net:38322/ \ --user-agent "picobrowser" \ --referer "http://mercury.picoctf.net:38322/" \ -H "Date: Mon, 23 11 2018 23:23:23 GMT" \ -H "DNT: 1" \ -H "X-Forwarded-For: 2.71.255.255" \ -H "Accept-Language: sv-SE"Expected output
picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_...}What didn't work first
Tried: Using -H 'X-Forwarded-For: 127.0.0.1' or a random private IP for the geo-check
The server resolves X-Forwarded-For against a GeoIP database and checks that the result is Sweden. Private addresses (10.x, 192.168.x, 127.x) and most public IPs do not map to SE, so the server returns 'Sorry, you're not from the right place.' Any publicly routable IP assigned to a Swedish ISP passes - 2.71.255.255 falls in TeliaSonera's allocation and resolves to SE.
Tried: Setting Date to a full RFC 7231 timestamp like 'Mon, 23 Nov 2018 23:23:23 GMT' and still getting rejected
The server only checks the year portion of the Date header, not the full timestamp. However, if the format is malformed (wrong day-of-week for the given date, wrong month abbreviation, or extra spaces) some server-side parsers will reject the entire header and fall back to failing. The value shown in the commands - 'Mon, 23 11 2018 23:23:23 GMT' - uses a numeric month which is non-standard but accepted by this challenge's lenient parser. If you use the strict RFC format and it fails, try the numeric month form.
Learn more
Why a Swedish IP. The error message names Sweden. Confirm an IP's country with a quick
whoislookup or a MaxMind GeoIP query.2.71.0.0/16through5.150.0.0contain Swedish ISP allocations;2.71.255.255works because it falls in TeliaSonera's assignment. Any IP that GeoIP resolves toSEpasses.HTTP headers, by purpose:
- Referer: the URL the client came from. Same-origin check here.
- Date: request time. Server checks the year is 2018.
- DNT: Do Not Track.
1requests no tracking. - X-Forwarded-For: original client IP through a proxy. The server uses this for geo-restriction (a Swedish IP passes).
- Accept-Language: preferred response language.
sv-SEfor Sweden.
Case sensitivity. HTTP header names are case-insensitive (
User-Agent,user-agent, andUSER-AGENTall match). Values are case-sensitive:picobrowserandPicoBrowserare different strings as far as a strict equality check is concerned. Match the exact value the server demands.
Interactive tools
- Flask Session DecoderDecode Flask / itsdangerous session cookies. Splits payload, decompresses zlib, parses JSON, and verifies the HMAC signature when given the secret.
Flag
Reveal flag
picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_...}
The server validates six HTTP headers in sequence. Each wrong header reveals the next requirement, making this a progressive enumeration challenge.