Description
The site blocks absolute paths but still reads files relative to the web root. Use directory traversal (../../../../flag.txt) to bypass the filter.
Setup
Submit filenames through the form.
Absolute paths like /flag.txt are rejected, so supply a relative traversal path: ../../../../flag.txt.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Understand the constraint
ObservationThe description says the site blocks absolute paths while still reading files relative to the web root. That is a naive leading-slash check, and a relative traversal walks past it once you count how many levels deep the webroot sits.The prompt reveals the webroot (/usr/share/nginx/html) and that the actual flag is/flag.txt. Count the slashes in the webroot to know how many../you need - here four levels (usr,share,nginx,html) drop you at/. If the webroot isn't disclosed, start with one../and add another each request until you read a known file like/etc/passwd.What didn't work first
Tried: Trying just one or two
../sequences like../../flag.txt.This does not climb high enough. The webroot is four levels below the root, so fewer than four ../ segments leave you inside the nginx html tree, where no flag.txt exists. Use exactly as many segments as the webroot path has.
Tried: Trying the absolute path
/flag.txtdirectly in the form.The filter blocks any input starting with a slash, which is the first thing anyone tries and exactly what the prompt warns about. A relative traversal starts with a dot instead, so it passes the check while still resolving to the root-level file.
Learn more
Path traversal (also called directory traversal) is a vulnerability where an application uses user-supplied input to construct a file path without properly sanitizing
../sequences. Each../moves one directory level up in the filesystem hierarchy, so enough of them can escape the intended directory entirely.The web root
/usr/share/nginx/htmlis four levels deep from the filesystem root (/). Prepending../../../../to any filename therefore resolves to the filesystem root, allowing you to read any file the web server process has permission to access - including/flag.txt,/etc/passwd, or application configuration files containing database credentials.This attack is catalogued as CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) and appears regularly on the OWASP Top 10. The correct fix is to canonicalize the resolved path with something like
os.path.realpath()in Python orrealpath()in C, then verify it starts with the intended base directory - blocking any traversal that escapes the sandbox.Beyond web servers, path traversal vulnerabilities appear in desktop applications, archive extraction code, and file upload handlers. A classic variant is the Zip Slip attack: a specially crafted zip file contains entries with filenames like
../../etc/cron.d/evil. If the extraction library naively joins the output directory with the entry filename without checking the result, it writes files outside the intended directory - potentially overwriting system files. Many languages and frameworks patched this class of bug after coordinated disclosure in 2018.When testing for path traversal during a security assessment, try both forward slashes (
../) and backslashes (..\), which Windows systems also interpret as directory separators. Additionally, null-byte injection (../../../etc/passwd%00.jpg) used to fool older PHP versions into ignoring a required file extension. While modern runtimes have fixed null-byte handling, these techniques illustrate why input sanitization must handle all possible encodings and not just the happy path.Step 2Traverse upward
ObservationThe webroot is exactly four directories below the root: usr, share, nginx, html. Four ../ segments climb precisely back to the filesystem root and reach flag.txt without ever starting with a slash.Entering../../../../flag.txtclimbs out of the webroot and reads the real flag file. If a follow-up filter blocks literal../, percent-encoding tricks (%2e%2e%2f, double-encoded%252e%252e%252f, mixed..%2f) sometimes round-trip through naive sanitizers - try those only after the canonical traversal fails.What didn't work first
Tried: Immediately jumping to percent-encoded variants like
%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fflag.txtbefore trying the plain form.This filter blocks leading slashes and nothing else, so encoding tricks buy nothing. Trying encoded forms first wastes time and invites confusing errors when the server decodes and re-encodes the path unexpectedly. Try the plain traversal first and escalate only if it is blocked.
Tried: Appending the traversal to a relative filename like
images/../../../../flag.txtassuming a subdirectory prefix is required.The form accepts a bare traversal path with no leading directory component. Adding a prefix like images/ only pushes the starting point deeper, so you need more ../ steps and the arithmetic gets harder. Start the traversal from the webroot itself.
Learn more
Simple blocklist-based filters that reject strings starting with
/are easily bypassed because relative traversal paths don't begin with a slash. More sophisticated filters might also block../directly, but those can often be defeated with URL encoding (%2e%2e%2f), double encoding (%252e%252e%252f), or mixed representations (..%2f) - demonstrating why blocklists are inherently fragile compared to allowlist-based validation.In real penetration testing, path traversal findings are high-severity because they can expose configuration files, source code, private keys, and database files. Automated scanners like Burp Suite and nikto include path traversal checks, and manual testers look for any parameter that appears to reference a filename, especially those with extensions like
.txt,.php, or.log.A useful recon file to target is
/proc/self/environ, which on Linux exposes the environment variables of the running web server process. This can leak database connection strings, API keys, and other secrets injected via environment variables - a common deployment pattern in containerized applications. Another classic target is/proc/self/cmdline, which reveals the exact command used to start the process and can hint at configuration file locations.Always pair path traversal testing with a check of
/etc/passwdto confirm the vulnerability is exploitable before reaching for more sensitive targets. A successful read of/etc/passwd(which is world-readable by design) proves traversal works and lets you enumerate system users without risking detection from reading genuinely sensitive files like private SSH keys.See Web challenges: real-world bug patterns for the larger family of input-trust failures (open redirects, SSRF, prototype pollution) that share this root cause.
Interactive tools
- URL Encoder / DecoderEncode and decode URL-encoded (percent-encoded) strings. Useful for web exploitation challenges involving query parameters, form data, and HTTP headers.
Flag
Reveal flag
picoCTF{...}
Classic path traversal-relative paths often slip past simple filtering.