Skip to main content

Scavenger Hunt picoCTF 2021 Solution

Hunt through a website's various files and hidden paths to collect all the pieces of the flag.

Published: April 2, 2026Updated: September 20, 2026

Description

There is some interesting information hidden around this site. Find all the pieces of the flag.

Remote
Navigate to the challenge URL.
bash
# Open the challenge URL in your browser

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
Each file's contents hint at the next, so the chain is sequential: HTML comment → CSS comment → JS comment → robots.txt → .htaccess → .DS_Store. Skip a step and you miss the breadcrumb pointing to the next location.
  1. Step 1Part 1: HTML source
    Observation
    The description says information is hidden around the site. The first place to look is the most obvious one: the raw HTML source, where developer comments sit invisible in the rendered page.
    View the page source (Ctrl+U or right-click > View Page Source). Find a comment containing the first part of the flag: picoCTF{t.
  2. Step 2Part 2: CSS file
    Observation
    The HTML links an external stylesheet at /mycss.css, and the first comment hints at more parts to find. Comments survive in the raw CSS file even when the browser view hides them, so check it directly.
    The HTML links to a CSS file at /mycss.css. Open it and look for a comment. It contains the second part: h4ts_4_l0
    bash
    curl -s http://<server>/mycss.css
    What didn't work first

    Tried: Viewing the CSS inside the browser DevTools Sources panel instead of opening the raw file URL

    DevTools minifies or reformats the file in some browsers, stripping comments before displaying them. Opening the raw URL directly (or curling it) shows the unmodified source including the comment that holds the flag part.

    Tried: Searching only the HTML source for all flag parts at once

    The HTML only embeds Part 1 in a comment; Parts 2 and beyond are split across separate linked files. Stopping at the HTML source gives an incomplete fragment and no indication of where the chain continues.

  3. Step 3Part 3: JavaScript file and robots.txt
    Observation
    The HTML also references /myjs.js, and every linked resource is a candidate hiding spot. That file carries a comment pointing at robots.txt, a standard recon file that routinely exposes the paths an owner wanted kept from crawlers.
    The HTML also links to /myjs.js. A comment there hints to check robots.txt. Open /robots.txt and find the third part: t_0f_pl4c
    bash
    curl -s http://<server>/myjs.js
    bash
    curl -s http://<server>/robots.txt
    What didn't work first

    Tried: Curling /myjs.js and stopping there without also fetching robots.txt

    The JS comment does not contain a flag part itself - it is a breadcrumb that explicitly says to check robots.txt. Stopping at /myjs.js yields only a hint string, not the third flag fragment, which lives in robots.txt.

    Tried: Assuming robots.txt only lists Disallow paths and grepping for 'Disallow' to find the flag part

    The flag part is embedded in a comment line (prefixed with #), not in a Disallow directive. Grepping only for 'Disallow' misses comment lines entirely; grepping for 'picoCTF' or reading the full file is needed.

    Learn more

    robots.txt is a file at the root of a web server that instructs search engine crawlers which URLs to index or avoid. It is publicly accessible by anyone and is frequently checked during web CTF recon since it often reveals hidden paths or admin areas the site owner does not want indexed - but has not actually protected.

    Sample contents. A real robots.txt entry that exposes the next breadcrumb often looks like:

    User-agent: *
    Disallow: /.htaccess
    # Part 3: t_0f_pl4c

    The Disallow path is a hint, not a defense - search engines respect it, attackers do not.

  4. Step 4Part 4: .htaccess
    Observation
    robots.txt has a Disallow entry for /.htaccess alongside another breadcrumb comment. So the server is Apache, and its per-directory config file is reachable over HTTP rather than protected by the usual deny rule.
    robots.txt hints at an Apache server configuration file. Check /.htaccess. It contains the fourth part: 3s_2_lO0k
    bash
    curl -s http://<server>/.htaccess
    What didn't work first

    Tried: Requesting /.htaccess and getting a 403 Forbidden, then giving up

    Many Apache defaults block direct reads of .htaccess with a 403. In this CTF instance the deny rule is intentionally absent so the file is accessible. A 403 on a real server is expected behavior; here it signals the challenge is misconfigured on purpose, so the request is worth making.

    Tried: Trying /apache.conf or /httpd.conf instead of /.htaccess

    The robots.txt breadcrumb references Apache configuration but the per-directory override file is .htaccess, not the global server config files. httpd.conf and apache.conf live outside the web root and are never accessible over HTTP; .htaccess is the only Apache config file that sits inside the document root.

    Learn more

    .htaccess is an Apache per-directory configuration file. It can define URL rewrite rules, authentication requirements, custom headers, and password protection (AuthType Basic). Apache reads it on every request to the directory it lives in, which is why misconfiguring it (forgetting the <Files> deny block) is so common. Out of the box Apache denies direct fetches with a 403, but plenty of distributions and tutorials drop that protection, exposing the server's internal rewrite/auth logic.

  5. Step 5Part 5: .DS_Store
    Observation
    .htaccess carries a comment hinting at a Mac-specific hidden file, and .DS_Store is the macOS Finder metadata file developers commit and deploy by accident all the time. Fetch /.DS_Store next; it is binary, so strings pulls the readable content out.
    .htaccess hints at a Mac-specific file. Request /.DS_Store - this macOS metadata file is sometimes accidentally uploaded to web servers. The file is binary, so do not just cat it; pull plain text out with strings.
    bash
    curl -s http://<server>/.DS_Store -o ds_store.bin
    bash
    strings ds_store.bin
    bash
    # if that shows nothing readable, try the wide-character modes:
    bash
    strings -e b ds_store.bin

    The .DS_Store holds the last fragment. Concatenate the five pieces in the order they were found (HTML, CSS, JS/robots.txt, .htaccess, .DS_Store) to get the complete flag.

    What didn't work first

    Tried: Running curl on /.DS_Store and piping it straight into grep without extracting strings first

    grep detects that its input is binary and only reports that the binary input matched (GNU grep 3.5 and newer word it as 'grep: (standard input): binary file matches', older releases as 'Binary file (standard input) matches') instead of printing the matching line, so the fragment never appears. Saving the response with -o and running strings on it turns the binary into printable runs that grep (or your eyes) can read. Also note that only part of the flag lives here, so grepping for 'picoCTF' matches nothing: the fragment carries no prefix.

    Tried: Using cat on ds_store.bin instead of strings to read the flag

    cat outputs raw binary bytes to the terminal, which produces garbage characters and can corrupt the terminal session. The strings utility extracts only sequences of printable ASCII characters from binary files, isolating the embedded filename strings (including the flag) from the surrounding binary metadata.

    Learn more

    .DS_Store files are created by macOS Finder to store folder view settings (icon positions, column widths, etc.) in a proprietary binary format. When developers deploy websites from a Mac without a .gitignore entry for .DS_Store, these files get uploaded to the server alongside the actual web content. They can leak directory structure and file listings - tools like ds_store_exp parse them to reconstruct entire directory trees. Filenames inside the structure are stored as UTF-16BE, which plain strings skips because the bytes are interleaved with NULs, so reach for strings -e b when the default run comes up empty. Any ASCII text the challenge author pasted in shows up under plain strings as normal.

Interactive tools
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.

Flag

Reveal flag

picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_...}

Hidden server files like .htaccess and .DS_Store are often accidentally accessible on misconfigured servers - each file in this challenge hints at the next.

Key takeaway

Web servers often serve configuration and metadata files that were never intended to be public. Files like robots.txt, .htaccess, and .DS_Store exist for legitimate purposes but leak path structures, server configuration, and sometimes credentials when left world-readable. Security-conscious deployments use .gitignore and server-level deny rules to prevent these files from ever reaching production, because security through obscurity (just not linking to them) is not a defense.

Related reading

Useful tools for Web Exploitation

Where to go next