Path Traversal
A complete guide to understanding, detecting, exploiting, and preventing Path Traversal vulnerabilities.
Introduction
Path Traversal and Local File Inclusion (LFI)
ANAS EDUCATION -- Bug Bounty & Pentesting Course (V2 Beginner-First)
A note on naming
This course covers two closely related vulnerabilities that share the same root cause and the same exploitation mechanics:
- ●Path Traversal (also called Directory Traversal) -- reading or writing files outside the intended directory.
- ●Local File Inclusion (LFI) -- the application not only reads the file but also includes or executes its contents.
Path Traversal is what happens when the application says `open(file)`. LFI is what happens when it says `include(file)`. The first gives data. The second gives remote code execution. Both are born from the same mistake. Path Traversal is CWE-22, CWE-73. LFI is CWE-98.
SECTION 1. Introduction
Imagine you open your PC and visit `anasdocs.anastech.com`.
You log in. You navigate to your invoices. Each invoice has a download button. You click the download button next to invoice 4172. The browser sends:
On the server, the PHP code that handles this request looks like this:
The server takes `invoice-4172.pdf`, appends it to `/var/www/invoices/`, opens that path, and sends the PDF bytes back. Normal. Expected. You see a PDF.
Now look at the same picture again, but with a question on top of it: what if the value sent in the `file` parameter were not just a filename, but a small instruction to the operating system?
Filesystems on Linux and Windows obey three special tokens:
- ●`.` means "the directory I am in right now".
- ●`..` means "go one directory up, toward the root".
- ●`/` (or `\` on Windows) separates one directory from the next.
So when the OS sees a path like `/var/www/invoices/../../../etc/passwd`, it follows the instructions literally: start at `/var/www/invoices/`, go up three levels (`var/www/invoices` to `var/www` to `var` to `/`), then descend into `etc/passwd`. The final resolved path is `/etc/passwd`.
Now change the URL parameter:
The server concatenates `/var/www/invoices/` + `../../../etc/passwd`. The OS resolves this to `/etc/passwd`. The server reads `/etc/passwd`. The server sends the file back. The browser shows:
Every user account on the server, leaked. No authentication bypass. No SQL injection. No buffer overflow. Just two dots, a slash, and an OS that does exactly what it is told.
This is Path Traversal. With one small change -- the same parameter pointing at a PHP source file fed into `include()` instead of `readfile()` -- the attack escalates to Local File Inclusion, which executes code. With wrappers like `php://filter`, LFI leaks source code. With log poisoning, LFI runs shell commands. With Synacktiv's filter chains, LFI becomes universal remote code execution.
This course teaches both bug classes from zero. By the end you will know:
- ●How filesystem paths work and what `..` actually does.
- ●The difference between "read a file" (Path Traversal) and "execute a file" (LFI).
- ●Twelve encoding bypasses for naive filters.
- ●Every PHP wrapper that turns LFI into RCE: `php://filter`, `php://input`, `data://`, `expect://`, `zip://`, `phar://`.
- ●Log poisoning, session poisoning, `/proc/self/environ`, PEAR/PECL command injection.
- ●The Synacktiv PHP filter chain technique that achieves RCE without uploads or special config.
- ●The CVEs that mass-exploited the internet (Apache 2.4.49, Citrix Bleed, Spring 5).
You do not need to be an expert in operating systems. You need to understand that a filename is a path, and a path is an instruction.
SECTION 2. How It Works
Step 1. The filesystem hierarchy
Every Unix-like server organizes files in a tree rooted at `/`:
When PHP calls `include("/var/www/invoices/" . $file)`, the OS looks up that path in this tree.
Step 2. The three special tokens
Each `..` is a step closer to the root. Each subsequent path component is a step into a new directory.
If the user supplies `../../../etc/passwd`, the OS reads `/etc/passwd`.
Step 3. Where the bug lives
The vulnerability is in step two: the application concatenates user input into a filesystem path without checking that the result stays inside the intended directory.
Step 4. Path Traversal vs LFI outcomes
The same trick produces different results depending on which function the developer used:
Path Traversal leaks data. LFI executes code. Same root cause; different sink.
Step 5. The critical sinks per language
- ●PHP: `include`, `require`, `include_once`, `require_once`, `file_get_contents`, `fopen`, `readfile`, `highlight_file`, `show_source`, `parse_ini_file`, `file`, `fpassthru`.
- ●Node.js: `fs.readFile`, `fs.readFileSync`, `fs.createReadStream`, `res.sendFile`, `res.download`, `path.join` joined with user input without normalization.
- ●Python: `open()`, `pathlib.Path()`, Flask `send_file()`, Django `serve()`.
- ●Java: `new File()`, `Files.read*()`, `getResourceAsStream()`, `FileInputStream()`.
- ●C#: `File.ReadAllText()`, `File.Open()`, `Path.Combine()` without canonicalization.
- ●Ruby: `File.read`, `File.open`, `Pathname`, Rails `send_file`.
If user input touches any of those without strict validation, Path Traversal can live there.
Step 6. Why include() is the dangerous escalation
`include()` is not just "read the file". It is "read the file and evaluate it as PHP code". So:
reads the log and tries to evaluate it. If the log contains `<?php system('id'); ?>` somewhere (because an attacker sent a request with that string in a logged header), PHP executes it. This is log poisoning. The combination of:
- ●A read primitive that resolves user input,
- ●A sink that executes what it reads,
- ●A logged target that the attacker can pre-poison,
turns Path Traversal into RCE without uploading anything.
SECTION 3. Attack Flow
The walkthrough below is the canonical Path Traversal to LFI to RCE chain against a single endpoint.
Step 1: Recon
Look at every URL parameter, form field, JSON body field, and cookie that could carry a filename: `file`, `path`, `page`, `template`, `include`, `doc`, `img`, `image`, `download`, `view`, `folder`, `style`, `lang`, `locale`, `css`, `theme`, `logo`, `name`, `report`.
Step 2: Baseline probe
Send a benign value first. Note the response shape, status code, and body length. Example baseline:
Step 3: Confirm traversal
Send progressive `../` ladders:
If any response contains a line starting with `root:x:0:0:`, Path Traversal is confirmed.
Step 4: Try absolute paths
If the application strips the prefix or rejects the relative path, try absolute:
Step 5: Walk the encoding bypass ladder
If `..` is filtered:
Step 6: Identify the sink type
Inspect the response to determine if the file is read or included:
- ●Read sink (file_get_contents, readfile): returns file contents as data.
- ●Include sink (include, require): may execute PHP code or fail silently if the file is not PHP.
The next escalation depends on which sink is in play.
Step 7: Escalate to source code disclosure (LFI)
If the sink is `include()`, use `php://filter` to base64-encode the file's contents so they survive the include:
The response body is the base64-encoded source of `database.php`. Decode locally to read database credentials, API keys, and source code.
Step 8: Escalate to RCE
Pick a technique that matches the environment:
- ●Log poisoning if logs are readable and predictable.
- ●`/proc/self/environ` poisoning via User-Agent on older Linux.
- ●PHP session file inclusion if you can plant code in a session value.
- ●Synacktiv PHP filter chain if nothing else fits.
- ●PEAR/PECL command injection on Debian-flavored PHP installs.
Step 9: Capture impact
Read `/etc/passwd`, then config files, then source code, then SSH keys, then cloud metadata via SSRF chain. Document every step with HTTP traces.
ASCII timing diagram
SECTION 4. Why Developers Make This Mistake
Path Traversal is a defaults bug and a model-of-the-OS bug.
Mistake 1: "The user is supplying a name, not a path"
A name and a path are the same thing once concatenated. `invoice-4172.pdf` and `../../../etc/passwd` both fit in the same string variable. The OS does not care which one the developer intended.
Mistake 2: "Only my frontend will send this request"
Anyone can construct an HTTP request. The frontend dropdown does not constrain what the backend receives.
Mistake 3: "I prefixed it with my safe directory, so it stays there"
Prefixing does nothing if the user input contains `../`. The OS happily walks back up out of the prefix.
Mistake 4: "I block `..` so it is safe"
Filters can be defeated by `....//`, URL encoding, double URL encoding, UTF-8 overlong sequences, Windows backslashes, and many other variants documented in section 11.
Mistake 5: "I check the file extension"
Extension checks die to null bytes (legacy PHP), wrapper syntax (`php://filter/.../resource=...`), and the absolute path bypass (which keeps any prefix the developer expects).
Mistake 6: "include() only includes my templates"
`include()` resolves the path the developer hands it and executes whatever lives there. If user input controls that path, the developer is no longer in control of what runs.
Mistake 7: "It's only a read, not a write"
A read of `/etc/shadow`, `id_rsa`, `.aws/credentials`, or `/run/secrets/kubernetes.io/serviceaccount/token` is functionally equivalent to compromise. A read of source code reveals further vulnerabilities to chain. A read can be enough.
SECTION 5. Beginner Summary
- ●Path Traversal lets an attacker read files outside the intended folder by adding `../` to climb the directory tree.
- ●LFI is the same bug applied to an `include()` or `require()` sink, which executes the included file as code instead of just reading it.
- ●Both work because the application trusts user input as a filename without verifying that the resolved canonical path stays inside the intended directory.
- ●Detection is one probe: `?file=../../../etc/passwd`. If the response contains lines starting with `root:x:0:0:`, the bug is confirmed.
- ●Defense is canonical path resolution plus an allowlist of expected filenames, or indirect IDs that map server-side to real files. CWE-22 for traversal, CWE-98 for LFI, OWASP A01:2021 Broken Access Control.
If you remember those five lines, you already understand the soul of these attacks.
SECTION 6. Visual Explanation
The safe pattern
The vulnerable pattern
Three families of file-path attacks
The escalation ladder
Burn these into memory. Every real engagement walks this ladder.
SECTION 7. Definition
Technical definition
Path Traversal (CWE-22 Improper Limitation of a Pathname to a Restricted Directory, also CWE-73 External Control of File Name or Path) is a vulnerability in which an application uses user-supplied input to construct a filesystem path without adequate validation, allowing the attacker to access files or directories outside the intended scope.
Local File Inclusion (CWE-98 Improper Control of Filename for Include/Require Statement) is the same vulnerability applied to a code-inclusion sink, leading to execution of the included file's contents.
Beginner-friendly definition
Path Traversal is when `../` lets the attacker read files they should not be able to read. LFI is when those files are then executed as code.
Why it matters
Real CVEs and bounty disclosures in the last few years prove this bug class is alive:
- ●CVE-2021-41773 (Apache 2.4.49, CVSS 9.8) -- mass-exploited within 24 hours of disclosure: https://nvd.nist.gov/vuln/detail/CVE-2021-41773
- ●CVE-2021-42013 (Apache 2.4.50, incomplete patch for CVE-2021-41773): https://nvd.nist.gov/vuln/detail/CVE-2021-42013
- ●CVE-2019-19781 (Citrix ADC / Gateway, unauthenticated traversal to RCE): https://nvd.nist.gov/vuln/detail/CVE-2019-19781
- ●CVE-2018-1271 (Spring MVC double-encoded backslash traversal): https://nvd.nist.gov/vuln/detail/CVE-2018-1271
- ●CVE-2024-21896 (Node.js Buffer monkey-patch traversal escape): https://nvd.nist.gov/vuln/detail/CVE-2024-21896
- ●CVE-2025-27210 (Node.js Windows UNC path traversal): https://nvd.nist.gov/vuln/detail/CVE-2025-27210
- ●CVE-2023-27534 (curl SFTP path traversal): https://nvd.nist.gov/vuln/detail/CVE-2023-27534
- ●CVE-2019-3398 (Confluence Widget Connector traversal to RCE): https://nvd.nist.gov/vuln/detail/CVE-2019-3398
- ●CVE-2019-11510 (Pulse Secure pre-auth file read): https://nvd.nist.gov/vuln/detail/CVE-2019-11510
- ●CVE-2017-5638 (Apache Struts file-related component, Equifax breach root cause): https://nvd.nist.gov/vuln/detail/CVE-2017-5638
Real HackerOne bounty examples in the corpus at https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPFILEREADING.md:
- ●Internet Bug Bounty -- Apache 2.4.49 path traversal, paid $4,000: https://hackerone.com/reports/1394916
- ●GitLab -- Nuget package traversal, paid $12,000: https://hackerone.com/reports/733072
- ●Aiven -- Grafana 8.x path traversal, paid $1,000.
- ●Slack -- Unauthenticated LFI, 122 upvotes corpus entry.
- ●WordPress -- `unzip_file` traversal, 119 upvotes corpus entry.
- ●Lichess (Lila) -- traversal disclosure, 114 upvotes corpus entry.
- ●Semmle / GitHub Security Lab -- worker container LFI, paid $2,000.
- ●TikTok -- Lynxview deeplink traversal, 103 upvotes corpus entry.
- ●Internet Bug Bounty -- Node.js Uint8Array path bypass, paid $3,495.
- ●Internet Bug Bounty -- Node.js permission model bypass, paid $2,330.
- ●Mail.ru -- esk-static traversal, paid $1,500.
- ●U.S. Dept of Defense -- multiple traversal disclosures including 497771, 2778380, 1888808.
Common affected systems
- ●File-download endpoints (invoice/report/log downloaders)
- ●Image and avatar viewers
- ●PDF and report generators loading templates by name
- ●Multi-language frameworks loading locale files dynamically
- ●Plugin and theme systems including modules by filename
- ●Backup, import, and export features
- ●Log viewers in admin panels
- ●Help-system file readers
- ●CI/CD configuration loaders
- ●Static asset routers in legacy frameworks
- ●Reverse proxies and load balancers with normalization mismatches
If a user-controllable parameter flows into `file=`, `path=`, `include=`, `view=`, or similar, traversal may live there.
SECTION 8. Examples
Five realistic AnasTech scenarios. Each one follows a real disclosed pattern.
Example 1. AnasDocs classic file download
The feature. AnasDocs users download invoices via `GET /download.php?file=invoice-4172.pdf`. The server concatenates the parameter with `/var/www/invoices/` and reads the file.
The bug. No validation that the resolved path stays inside `/var/www/invoices/`.
The attack step by step.
- ●Step 1: send `?file=../../../etc/passwd`.
- ●Step 2: response contains lines starting with `root:x:0:0:`.
- ●Step 3: pivot to `?file=../../../var/www/html/config.php` to grab DB credentials.
- ●Step 4: pivot to `?file=../../../home/ubuntu/.ssh/id_rsa` to grab SSH keys.
Example 2. AnasTech legacy null-byte extension bypass
The feature. A legacy AnasTech installation runs PHP 5.2. The downloader appends `.pdf` to the supplied filename:
The bug. In PHP versions before 5.3.4, a null byte terminates the C-level string. The appended `.pdf` is never reached.
The attack step by step.
- ●Step 1: send `?file=../../../etc/passwd%00`.
- ●Step 2: the C string ends at the null byte; `.pdf` is dropped.
- ●Step 3: `/etc/passwd` is read.
Example 3. AnasOne LFI via PHP filter (source disclosure)
The feature. AnasOne uses a `page` parameter to switch between content sections:
The bug. User input flows into `include()`. PHP's `include` understands stream wrappers.
The attack step by step.
- ●Step 1: send `?page=php://filter/convert.base64-encode/resource=../../config/database`.
- ●Step 2: the include reads the file through the filter, base64-encoded.
- ●Step 3: response body is base64 source of `database.php`.
- ●Step 4: decode locally; harvest DB credentials.
Example 4. AnasMarket log poisoning to RCE
The feature. AnasMarket allows users to browse documentation via:
The bug. The parameter is unfiltered; Apache logs every request including User-Agent.
The attack step by step.
- ●Step 1: send a request to any URL with header `User-Agent: <?php system($_GET['cmd']); ?>`.
- ●Step 2: Apache writes that User-Agent into `/var/log/apache2/access.log`.
- ●Step 3: send `?doc=/var/log/apache2/access.log&cmd=id`.
- ●Step 4: `include()` evaluates the log; PHP tag runs; `id` output appears in the response.
Example 5. AnasCorp Apache CVE-2021-41773 / CVE-2021-42013
The feature. A misconfigured Apache 2.4.49 or 2.4.50 (the patch was incomplete in 2.4.50) ships with permissive `Alias` directives and `Require all granted` on paths outside the document root.
The bug. A path normalization flaw allows requests like:
to escape the document root.
The attack step by step.
- ●Step 1: scan for Apache 2.4.49 / 2.4.50 banner.
- ●Step 2: send the `.%2e/` traversal pattern; read `/etc/passwd`.
- ●Step 3: where `mod_cgi` is enabled, POST a shell command:
- ●Step 4: response contains `id` output. Unauthenticated RCE.
This is the exact pattern that mass-compromised tens of thousands of public-facing Apache hosts in October 2021.
SECTION 9. Vulnerable Code
The flaw is structural: the server concatenates user input into a path and uses it without canonical-path verification.
PHP -- critical traversal + LFI
`$_GET['file']` is attacker-controlled. The concatenation lands inside `include()`, which both resolves wrappers (`php://filter`, `data://`, `expect://`) and executes the included file as PHP.
PHP -- extension suffix (legacy null-byte vulnerable)
The hardcoded `.php` is bypassed by null byte on legacy PHP, and by `php://filter/...?resource=...` on modern PHP.
Node.js (Express) -- traversal in `res.sendFile`
`sendFile` follows the resolved path. Without the `root` option (or with manual concatenation as shown), traversal works.
Node.js -- traversal in `fs.readFile`
Python (Flask) -- traversal in `send_file`
`send_file` does not normalize the path. `../../../etc/passwd` reaches the disk.
Python (Django) -- `serve()` misuse
Django's `serve` is explicitly documented as insecure for production. With user-controlled `path`, traversal is possible.
Java (Spring) -- file resolution without `normalize()`
Without `path.normalize()` followed by an allowlist `startsWith` check, traversal works.
C# (ASP.NET) -- `Path.Combine` misuse
`Path.Combine` does not block traversal. If `name` is `..\..\Windows\System32\drivers\etc\hosts`, ASP.NET serves the hosts file.
Ruby on Rails -- `send_file` without scoping
Go -- `filepath.Join` without `Clean` check
`filepath.Join` does normalize, but without verifying the result still starts with the intended base directory, traversal escapes.
The universal pattern across languages
- ●1. Read user input.
- ●2. Concatenate it into a file path.
- ●3. Pass the path to a read or include function.
- ●4. Never check whether the resolved canonical path stays inside the intended directory.
Step 4 is where the bug is born. Every fix in section 16 adds the missing verification.
SECTION 10. Detection
Detection is a request-replay exercise: take any parameter that looks like a file reference and walk the traversal ladder.
Manual workflow
- ●Step 1: enumerate every parameter that takes a file reference. Look for keys named `file`, `path`, `page`, `template`, `include`, `doc`, `img`, `image`, `download`, `view`, `folder`, `style`, `lang`, `locale`, `css`, `theme`, `logo`, `name`, `report`, `attachment`.
- ●Step 2: send a benign baseline value first. Capture status code and response length.
- ●Step 3: send the `../` ladder. If any response contains `root:x:0:0:`, traversal is confirmed.
- ●Step 4: if filtered, try absolute paths, encoding bypasses, null-byte (legacy), and semicolon (Java) variants.
- ●Step 5: if the sink is `include()`, escalate immediately to `php://filter` source disclosure.
- ●Step 6: try wrappers for RCE: `php://input`, `data://`, `expect://`, `zip://`, `phar://`.
- ●Step 7: if direct reads fail, try log poisoning (`/var/log/apache2/access.log`), session inclusion, `/proc/self/environ`.
Burp Suite
- ●Right-click the request, send to Intruder. Set the file parameter as the payload position. Load the SecLists LFI wordlist. Filter responses by grep-match for `root:x:0:0:`.
- ●Use Active Scan Pro -- catches basic traversal patterns.
- ●Use Param Miner to discover hidden file-related parameters.
Automated tools and URLs
- ●LFISuite -- auto-detect and exploit: https://github.com/D35m0nd142/LFISuite
- ●kadimus -- modern LFI scanner: https://github.com/P0cL4bs/Kadimus
- ●dotdotpwn -- path traversal fuzzer: https://github.com/wireghoul/dotdotpwn
- ●fimap -- legacy LFI scanner.
- ●ffuf with SecLists LFI wordlists for brute-force discovery: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
- ●Synacktiv php_filter_chain_generator: https://github.com/synacktiv/php_filter_chain_generator
- ●Synacktiv php_filter_chains_oracle_exploit (Lightyear): https://github.com/synacktiv/php_filter_chains_oracle_exploit
- ●Ambionics wrapwrap (filter chain post-processing): https://github.com/ambionics/wrapwrap
Quick command-line probes
Indicators of vulnerability
- ●User-controllable filename parameters in URLs, forms, or JSON bodies.
- ●Endpoints that read or include files (sinks in section 2).
- ●Error messages disclosing absolute server paths (`/var/www/html/...`).
- ●File extension hardcoded in the application (suggests legacy null-byte targets).
- ●Apache 2.4.49 / 2.4.50 in `Server` header or banner.
- ●Older PHP versions (< 7.x) suggesting null-byte traversal works.
- ●Legacy frameworks (Symfony 1.x, CodeIgniter early versions, Zend Framework 1.x).
- ●Multi-language sites with locale files loaded dynamically.
Train your eye. Every filename parameter is an invitation.
SECTION 11. Exploitation
Workflow
- ●1. Identify every file-handling parameter.
- ●2. Confirm traversal with `/etc/passwd` (Linux) or `C:\windows\win.ini` (Windows).
- ●3. Read sensitive files: configs, logs, SSH keys, env files.
- ●4. If the sink is include/require, escalate to LFI source disclosure via `php://filter`.
- ●5. Try wrappers for RCE: `php://input`, `data://`, `expect://`, `zip://`, `phar://`.
- ●6. If wrappers fail, try log poisoning, session poisoning, `/proc/self/environ`.
- ●7. If still stuck, use the Synacktiv filter chain (universal RCE).
- ●8. Drop a webshell, exfiltrate data, document the chain.
Techniques
1. Encoding bypass ladder
When `../` is filtered, walk through:
If single decode fails, try double. The downstream framework may decode again.
2. Non-recursive filter bypass
When the filter strips `../` exactly once:
After stripping one `../` from `....//`, the residue is still `../`.
3. Superfluous URL-decode bypass
The PortSwigger PRACTITIONER lab. The application URL-decodes its input, then runs a filter that strips `../`. Send double-encoded `../`:
First decode yields `..%2f...`. Filter sees no `../`. Then a framework decodes again somewhere downstream, yielding `../../../etc/passwd` at the sink.
4. Start-of-path validation bypass
When the application validates that the input starts with `/var/www/files/`:
The path starts correctly. The OS resolves the traversal. Game over.
5. Null-byte bypass (legacy)
Works on PHP < 5.3.4 and some other legacy languages. Always worth a try.
6. Semicolon bypass (Tomcat, Spring, some Java servers)
Some Java servers treat `;` as a parameter delimiter, but path normalization runs before parameter stripping.
7. UNC path bypass (Windows)
Windows interprets `\\` as a UNC path. Some applications fail to canonicalize and the OS reads from the SMB share -- including an attacker-controlled SMB. CVE-2025-27210 in Node.js targeted this on Windows.
8. NGINX / ALB normalization mismatch
When the reverse proxy normalizes paths but the backend does not, multiple slashes survive to the backend.
9. Spring CVE-2018-1271
Double-URL-encoded backslashes traverse out of static resource folders:
10. Apache CVE-2021-41773 / CVE-2021-42013
Chains to RCE on hosts with `mod_cgi` enabled:
11. LFI via php://filter (source disclosure)
The include reads the file, the filter base64-encodes the bytes, the result is output as text. Decode to source.
12. LFI via php://input
Some installs have `allow_url_include=On`. Send a POST body containing PHP:
Then call with `?cmd=id`.
13. LFI via data://
Requires `allow_url_include=On`.
14. LFI via expect:// (PHP expect module enabled)
Rare in production but devastating when present.
15. LFI via zip:// and phar:// (upload + include)
Upload a malicious archive:
Then include:
16. Log poisoning to RCE (Apache / Nginx)
Send a request with PHP in a logged header:
Then include the access log:
The log contains the PHP tag. `include()` evaluates it. RCE.
Common log paths:
17. /proc/self/environ poisoning
Send a request with PHP in User-Agent. Then:
The environ file contains the User-Agent value. `include()` evaluates the PHP. Works on older Linux kernels where `/proc/self/environ` is web-readable.
18. PHP session file inclusion
Plant a malicious value in your session via any feature that stores user-controlled data in the session (display name, search history, profile field). Then include the session file:
The session file is plain text containing the PHP code. The include evaluates it.
19. /proc/[PID]/fd file descriptor brute force
When the application opens a temp file but does not expose its path, brute-force PIDs and FDs:
The active web request body may be mapped to a file descriptor you can include.
20. Synacktiv PHP filter chain to RCE (modern)
Synacktiv's 2022+ technique turns ANY PHP `include()` of a user-controlled string into RCE without requiring file upload, wrappers like `data://`, or special configuration. The chain uses iconv conversions to gradually craft a base64-encoded PHP shell:
Use Synacktiv's generator:
Append `&0=id` to the URL. Watch RCE happen.
Use `php://temp` if no readable file path exists:
21. Lightyear: filter chain oracle exfiltration
Synacktiv's follow-up uses filter chains as an error-based oracle to dump files byte by byte over HTTP error codes. Useful when LFI exists but output is hidden:
- ●https://github.com/synacktiv/php_filter_chains_oracle_exploit
- ●https://github.com/ambionics/wrapwrap
22. PEAR / PECL command injection via LFI
Where PEAR is installed (default on many Debian PHP setups), include `pearcmd.php`:
PEAR writes a config file containing the PHP at `/tmp/webshell.php`. Include it. RCE.
23. Windows: read win.ini, hosts, web.config
24. Cloud metadata via LFI/SSRF chain
If the LFI sink can be redirected to an HTTP URL (`url=file:///...` or `url=http://...`), reach cloud metadata:
The combination of LFI primitives and SSRF surfaces produces cloud credentials and persistent access.
25. Kubernetes service account token theft
When the application runs in a pod with a mounted service account:
The JWT token enables direct API server calls with the pod's RBAC permissions.
26. Read application secrets
27. Read Java application files
28. Read .NET application files
29. Read cloud function source
30. WAF bypass: split keywords
Some WAFs match `../` literal but accept whitespace, mixed case, or alternate encodings:
These 30 techniques are the modern Path Traversal + LFI hunter's toolkit. Memorize them. Combine them.
SECTION 12. Proof of Concept
Burp Suite
- ●1. Capture the file-handling request, send to Repeater.
- ●2. Replace the file parameter with `../../../etc/passwd`.
- ●3. Send; observe response.
- ●4. If response contains `root:x:0:0:`, confirm traversal.
- ●5. Try absolute path, encoding bypasses, php filter, log poison.
Python detection script
Python LFI source disclosure PoC
Python log poisoning to RCE PoC
Bash PoCs
PowerShell PoC
Node.js PoC
Synacktiv PHP filter chain to RCE PoC
PortSwigger lab solutions reference
- ●Apprentice: File path traversal, simple case -- `?filename=../../../etc/passwd`
- ●Practitioner: Traversal sequences blocked, absolute path bypass -- `?filename=/etc/passwd`
- ●Practitioner: Traversal sequences stripped non-recursively -- `?filename=....//....//....//etc/passwd`
- ●Practitioner: Traversal sequences stripped with superfluous URL-decode -- `?filename=..%252f..%252f..%252fetc%252fpasswd`
- ●Practitioner: Validation of start of path -- `?filename=/var/www/images/../../../etc/passwd`
- ●Practitioner: Validation of file extension with null byte bypass -- `?filename=../../../etc/passwd%00.png`
These six payloads are the canonical Apprentice/Practitioner answer key.
SECTION 13. Payloads
Tier 1: basic traversal
Tier 2: URL-encoded variants
Tier 3: non-recursive strip bypass
Tier 4: UTF-8 overlong / Unicode
Tier 5: Windows variants
Tier 6: null byte (legacy)
Tier 7: semicolon bypass (Java / Tomcat)
Tier 8: absolute-path bypass
Tier 9: Spring CVE-2018-1271
Tier 10: Apache CVE-2021-41773 / CVE-2021-42013
Tier 11: LFI -- PHP filter wrappers
Tier 12: LFI -- input / data wrappers
Tier 13: LFI -- expect / zip / phar
Tier 14: log poisoning paths
Tier 15: /proc pseudo-files
Tier 16: PHP session files
Tier 17: PEAR / PECL RCE
Tier 18: cloud metadata via LFI/SSRF
Tier 19: high-value Linux files
Tier 20: high-value Windows files
Tier 21: app-specific files
The payload is the path. The attack is whichever file matters.
SECTION 14. Wordlists and Payload Libraries
- ●SecLists -- LFI fuzzing: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
- ●FuzzDB -- includes traversal patterns and interesting file lists for Linux and Windows: https://github.com/fuzzdb-project/fuzzdb
- ●PayloadsAllTheThings -- Directory Traversal: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Directory%20Traversal
- ●PayloadsAllTheThings -- File Inclusion: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion
- ●Synacktiv php_filter_chain_generator (LFI to RCE without uploads): https://github.com/synacktiv/php_filter_chain_generator
- ●Synacktiv php_filter_chains_oracle_exploit (Lightyear, error-based exfiltration): https://github.com/synacktiv/php_filter_chains_oracle_exploit
- ●Ambionics wrapwrap (advanced filter wrapping for output formatting): https://github.com/ambionics/wrapwrap
- ●LFISuite (automated detection and exploitation): https://github.com/D35m0nd142/LFISuite
- ●kadimus (modern LFI scanner): https://github.com/P0cL4bs/Kadimus
- ●dotdotpwn (path traversal fuzzer): https://github.com/wireghoul/dotdotpwn
- ●HackTricks LFI: https://book.hacktricks.xyz/pentesting-web/file-inclusion
- ●HackTricks LFI to RCE via PHP filters: https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters
- ●OWASP Path Traversal: https://owasp.org/www-community/attacks/Path_Traversal
- ●OWASP File Inclusion: https://owasp.org/www-community/attacks/Locally_File_Inclusion
- ●PortSwigger Web Security Academy -- Path Traversal: https://portswigger.net/web-security/file-path-traversal
- ●reddelexc Top File Reading reports corpus: https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPFILEREADING.md
- ●The Hacker Recipes -- LFI to RCE: https://www.thehacker.recipes/web/inputs/file-inclusion/lfi-to-rce
- ●Anas Magane Pentesting Notes: https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP
Practical advice
- ●Keep a personal Linux/Windows file list of 30 high-impact targets ready (`/etc/passwd`, `.env`, `id_rsa`, `wp-config.php`, `application.properties`, `web.config`, AWS creds, K8s token).
- ●Have a ready-to-paste python_filter_chain payload for the moment you find LFI.
- ●Save a `User-Agent` log-poison string ready for one-liner log RCE: `<?php system($_GET['c']); ?>`
- ●Maintain a separate folder of WAF-bypass encodings for fast iteration.
SECTION 15. Impact
Impact ladder, low to high:
Step 1: file disclosure
Read `/etc/passwd`, `/etc/hostname`, `/etc/issue`, `/proc/version`. Confirms the bug; sets the stage.
Step 2: secret extraction
Read `.env`, `wp-config.php`, `application.properties`, `web.config`, `appsettings.json`, `.aws/credentials`, `id_rsa`. Database passwords, API tokens, SSH keys leak in seconds.
Step 3: source code disclosure
Via `php://filter/convert.base64-encode/resource=`. Reveals additional bugs, hardcoded secrets, business logic.
Step 4: SSH key theft
`/home/USER/.ssh/id_rsa` -- direct lateral movement to the host as that user.
Step 5: Kubernetes service account token theft
`/run/secrets/kubernetes.io/serviceaccount/token` -- direct API server access with pod RBAC.
Step 6: cloud metadata theft (LFI/SSRF chain)
AWS / GCP / Azure metadata IPs -- temporary IAM credentials, full cloud API access.
Step 7: log poisoning to RCE
Apache/Nginx logs + `include()` evaluating PHP from User-Agent. Unauthenticated RCE.
Step 8: Synacktiv filter chain RCE
Universal LFI to RCE without uploads or special config. Works on most modern PHP.
Step 9: PEAR/PECL command injection
Writable webshell at `/tmp/webshell.php` for persistence.
Step 10: persistence via uploaded webshell
Survives application restarts; harder to detect than payload-on-each-request.
Step 11: lateral movement
Stolen SSH keys, IAM credentials, K8s tokens move into other accounts, VPCs, services.
Step 12: data destruction
After RCE, the attacker can wipe logs, modify databases, delete records.
Step 13: regulatory and contractual fallout
GDPR, HIPAA, PCI DSS, SOX violations on every data-exposure path.
Step 14: reputational damage
Public CVEs in widely-deployed software (Apache 2.4.49, Citrix CVE-2019-19781) trigger customer churn and contract renegotiation.
Step 15: long-tail cost
Forensic investigation, audits, mandatory remediation cycles, insurance premium spikes.
SECTION 16. Prevention
Path Traversal has a clean, well-known fix per language. Apply all of these together for defense in depth.
The four rules that cover almost everything
- ●1. Strip directory components from user input (`basename()` / equivalent).
- ●2. Resolve the user-supplied path against the intended base directory using a canonicalizer (`realpath()` / `Path.normalize()` / `os.path.realpath()`).
- ●3. Verify the resolved canonical path still starts with the intended base directory.
- ●4. Apply a strict allowlist of expected filenames when feasible; otherwise indirect IDs.
Vulnerable vs safe (PHP)
Vulnerable:
Safe:
Plus PHP configuration:
Vulnerable vs safe (Python)
Safe pattern with canonical-path validation:
`os.path.realpath` resolves all `..`, symlinks, and encodings to the absolute canonical path.
Vulnerable vs safe (Node.js)
Safe:
Or use Express `res.sendFile` with the `root` option:
`sendFile` with `root` rejects paths that escape the base.
Vulnerable vs safe (Java)
Vulnerable vs safe (.NET)
Vulnerable vs safe (Go)
Pattern: indirect references
Replace user-controllable filenames with opaque IDs:
Server-side: map `a7f2b9c1` to the real path. The attacker never sees or controls the actual filename, and the lookup table only contains the legitimate files.
Disable dangerous PHP options globally
This eliminates `php://input`, `data://`, `expect://`, and any remote URL inclusion.
Developer checklist
- ●Every file-system call accepts only sanitized input.
- ●`basename()` / `Path.Combine().Clean()` applied before use.
- ●Canonical path verified to start with the intended base.
- ●Allowlist of expected filenames enforced.
- ●Indirect IDs used where possible.
- ●PHP: `allow_url_include` and `allow_url_fopen` disabled when not needed.
- ●PHP: `open_basedir` set in php.ini.
- ●Web server runs as unprivileged user with no access to /etc/passwd, /etc/shadow, secrets directories.
- ●Log files are outside any web-included directory.
- ●`/etc/passwd`, `/etc/shadow`, `/proc`, `/home`, `/run/secrets` are not readable by the web user where possible.
- ●CI scans for sink patterns (Semgrep, CodeQL rules).
- ●Security review on every file-handling endpoint.
Enterprise-level mitigations
- ●Run PHP-FPM (and equivalent) as a non-privileged user with no access to sensitive directories.
- ●AppArmor or SELinux policies restricting filesystem access.
- ●Containerize the application with read-only volumes for the codebase.
- ●WAF rules for known traversal patterns (defense in depth, never primary).
- ●Bug bounty programs scoped to include traversal and LFI explicitly.
- ●Continuous monitoring of access to `/etc/passwd`, `/etc/shadow`, log files, SSH key paths.
- ●SAST rules that flag default `include`, `require`, `fs.readFile`, `send_file` with user input.
- ●Block egress to `169.254.169.254` from application user contexts (LFI/SSRF chain mitigation).
SECTION 17. Real-World Cases
CVE library (with URLs)
- ●CVE-2021-41773 (Apache HTTP Server 2.4.49 path traversal, CVSS 9.8)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2021-41773 Summary: path normalization flaw in 2.4.49 allowed `.%2e/` traversal outside the document root. Mass-exploited within 24 hours of disclosure. On hosts with `mod_cgi` enabled, chained to unauthenticated RCE.
- ●CVE-2021-42013 (Apache HTTP Server 2.4.50 incomplete patch)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2021-42013 Summary: the patch for CVE-2021-41773 was incomplete. Variant payload `.%%32%65/` still escaped.
- ●CVE-2019-19781 (Citrix ADC / Gateway pre-auth traversal to RCE)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2019-19781 Summary: unauthenticated path traversal in Citrix ADC/Gateway. Chained to RCE via VPN handler files. Affected tens of thousands of enterprise deployments. Used by APT groups within weeks.
- ●CVE-2018-1271 (Spring MVC directory traversal)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2018-1271 Summary: double-URL-encoded backslashes traversed out of static resource folders when serving from a Windows filesystem. Spring 5.0 to 5.0.4 affected.
- ●CVE-2024-21896 (Node.js Buffer monkey-patch path traversal escape)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2024-21896 Summary: Node.js permission model bypass via monkey-patching Buffer. Allowed traversal escape from the experimental permission sandbox.
- ●CVE-2025-27210 (Node.js Windows UNC path traversal)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-27210 Summary: improper handling of UNC-style paths on Windows allowed traversal escape from intended directories.
- ●CVE-2023-27534 (curl SFTP path traversal)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2023-27534 Summary: SFTP path handling allowed traversal outside expected directories.
- ●CVE-2019-3398 (Confluence Widget Connector traversal to RCE)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2019-3398 Summary: authenticated traversal in `/page/createpage-entervariables.action` allowed writing files to arbitrary locations, chaining to RCE. Mass-exploited.
- ●CVE-2019-11510 (Pulse Secure pre-auth file read)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2019-11510 Summary: arbitrary file read in Pulse Secure SSL VPN. Read session caches and credentials. Catastrophic mass-exploitation in 2019-2020.
- ●CVE-2017-5638 (Apache Struts -- Equifax root cause)
NVD: https://nvd.nist.gov/vuln/detail/CVE-2017-5638 Summary: although primarily OGNL, the exploit chain traversed and read sensitive files as part of the takeover. Cost: $700M+ in Equifax settlements.
Recent disclosed HackerOne reports
- ●Internet Bug Bounty -- Apache 2.4.49 path traversal, paid $4,000.
Report: https://hackerone.com/reports/1394916 Lesson: critical CVE-level traversal payouts on the Internet Bug Bounty program.
- ●GitLab -- Nuget package traversal, paid $12,000.
Report: https://hackerone.com/reports/733072 Lesson: package-management endpoints often have traversal in package-name handling.
- ●Aiven -- Grafana 8.x path traversal, paid $1,000.
Listed in https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPFILEREADING.md Lesson: data-visualization platforms with file-import features are recurring traversal surfaces.
- ●Slack -- Unauthenticated LFI, 122 upvotes corpus entry.
Lesson: even mature messaging platforms ship LFI on auxiliary endpoints.
- ●WordPress -- `unzip_file` traversal, 119 upvotes corpus entry.
Lesson: archive-extraction routines without zip-slip protection produce traversal at scale.
- ●Lichess (Lila) -- traversal disclosure, 114 upvotes corpus entry.
Lesson: open-source platforms catch traversal in bounty programs; review every file-name parameter.
- ●Semmle / GitHub Security Lab -- worker container LFI, paid $2,000.
Lesson: build-system workers that load configurations from user-controlled paths are LFI candidates.
- ●TikTok -- Lynxview deeplink traversal, 103 upvotes corpus entry.
Lesson: hybrid mobile webview features have traversal in URL-handling parameters.
- ●Internet Bug Bounty -- Node.js Uint8Array path bypass, paid $3,495.
Lesson: Node.js core itself ships traversal in low-level path-handling helpers.
- ●Internet Bug Bounty -- Node.js permission model bypass, paid $2,330.
Lesson: experimental sandboxes have bypasses; treat permission-model code as bypass research surface.
- ●Mail.ru -- esk-static traversal, paid $1,500.
Lesson: static-asset routers in legacy frameworks ship traversal.
- ●U.S. Dept of Defense -- multiple traversal disclosures, including HackerOne reports 497771, 2778380, 1888808.
Lesson: government VDP programs accept and triage traversal at all severity levels.
- ●Starbucks Korea -- traversal, report 780021.
- ●GSA -- traversal, report 895972.
Curated corpora
- ●reddelexc Top File Reading reports: https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPFILEREADING.md
- ●HackerOne Hacktivity (path traversal filter): https://hackerone.com/hacktivity?queryString=path%20traversal
Synacktiv research wave (2022-2026)
The Synacktiv team discovered that PHP's `php://filter` wrapper, when chained with iconv conversions, can transform arbitrary input into base64-encoded PHP code. This turns any LFI of a user-controlled string into RCE without needing file upload, wrappers like `data://`, or `allow_url_include`. The technique remains effective in 2026.
- ●https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle.html
- ●https://github.com/synacktiv/php_filter_chain_generator
Lessons learned
- ●Path Traversal and LFI ship at every scale, from network appliances (Citrix, Pulse Secure) to top SaaS to Node.js core itself.
- ●The 30-year-old `../` payload still works on modern code in 2026.
- ●The Synacktiv filter chain technique turns read-only LFI into universal RCE.
- ●Most enterprise traversal CVEs reach mass exploitation within 48 hours.
- ●Bug bounty payouts range from $1,000 (basic traversal) to $50,000+ (LFI to RCE on major platforms).
- ●The fix is universally the same: canonical path resolution plus allowlist or indirect IDs.
SECTION 18. References
Standards and authoritative docs
- ●OWASP Path Traversal: https://owasp.org/www-community/attacks/Path_Traversal
- ●OWASP File Inclusion: https://owasp.org/www-community/attacks/Locally_File_Inclusion
- ●OWASP Testing Guide -- Testing Directory Traversal / File Include: https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/05-Authorization_Testing/01-Testing_Directory_Traversal_File_Include
- ●CWE-22 Improper Limitation of a Pathname to a Restricted Directory: https://cwe.mitre.org/data/definitions/22.html
- ●CWE-73 External Control of File Name or Path: https://cwe.mitre.org/data/definitions/73.html
- ●CWE-98 Improper Control of Filename for Include/Require: https://cwe.mitre.org/data/definitions/98.html
- ●OWASP Top 10 (A01:2021 Broken Access Control covers traversal): https://owasp.org/Top10/
Learning resources
- ●PortSwigger Web Security Academy -- Path Traversal: https://portswigger.net/web-security/file-path-traversal
- ●HackTricks -- File Inclusion: https://book.hacktricks.xyz/pentesting-web/file-inclusion
- ●HackTricks -- LFI to RCE via PHP filters: https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters
- ●The Hacker Recipes -- LFI to RCE: https://www.thehacker.recipes/web/inputs/file-inclusion/lfi-to-rce
- ●Synacktiv -- PHP Filter Chains research: https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle.html
- ●PayloadsAllTheThings -- Directory Traversal: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Directory%20Traversal
- ●PayloadsAllTheThings -- File Inclusion: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion
- ●SecLists -- LFI fuzzing: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
- ●FuzzDB: https://github.com/fuzzdb-project/fuzzdb
Tools
- ●LFISuite: https://github.com/D35m0nd142/LFISuite
- ●kadimus: https://github.com/P0cL4bs/Kadimus
- ●dotdotpwn: https://github.com/wireghoul/dotdotpwn
- ●Synacktiv php_filter_chain_generator: https://github.com/synacktiv/php_filter_chain_generator
- ●Synacktiv php_filter_chains_oracle_exploit: https://github.com/synacktiv/php_filter_chains_oracle_exploit
- ●Ambionics wrapwrap: https://github.com/ambionics/wrapwrap
- ●Burp Suite: https://portswigger.net/burp
- ●OWASP ZAP: https://www.zaproxy.org/
CVE/advisory feeds
- ●NVD: https://nvd.nist.gov
- ●GitHub Advisories: https://github.com/advisories
- ●Apache Security: https://security.apache.org
- ●Anas Magane Pentesting Notes: https://github.com/Anas-Magane/Pentesting
SECTION 19. Practical Labs
Planned ANAS Path Traversal / LFI Labs (SOON)
- ●ANAS-PT-01 -- AnasDocs Simple Invoice Download Traversal, beginner
- ●ANAS-PT-02 -- AnasMarket Absolute Path Bypass, beginner
- ●ANAS-PT-03 -- AnasOne Non-Recursive Strip Bypass with `....//`, beginner-intermediate
- ●ANAS-PT-04 -- AnasCorp Superfluous URL-Decode (Double Encoding), intermediate
- ●ANAS-PT-05 -- AnasDocs Start-of-Path Validation Bypass, intermediate
- ●ANAS-PT-06 -- AnasTech Legacy Null-Byte Extension Bypass, intermediate
- ●ANAS-PT-07 -- AnasOne Tomcat/Spring Semicolon Bypass, intermediate
- ●ANAS-PT-08 -- AnasOne LFI Source Disclosure via php://filter, intermediate
- ●ANAS-PT-09 -- AnasOne LFI to RCE via data:// and php://input, advanced
- ●ANAS-PT-10 -- AnasMarket Log Poisoning (Apache + Nginx), advanced
- ●ANAS-PT-11 -- AnasOne /proc/self/environ Poisoning, advanced
- ●ANAS-PT-12 -- AnasOne PHP Session File Inclusion, advanced
- ●ANAS-PT-13 -- AnasOne Synacktiv Filter Chain Universal RCE, expert
- ●ANAS-PT-14 -- AnasOne PEAR/PECL Command Injection, expert
- ●ANAS-PT-15 -- AnasCorp Apache CVE-2021-41773 Reproduction + RCE, expert
- ●ANAS-PT-16 -- AnasMarket Windows UNC Path Traversal, advanced
- ●ANAS-PT-17 -- AnasOne K8s Service-Account Token Theft via LFI, expert
- ●ANAS-PT-18 -- AnasCorp Cloud Metadata Exfiltration via LFI/SSRF Chain, expert
PortSwigger Web Security Academy labs
- ●File path traversal, simple case (APPRENTICE): https://portswigger.net/web-security/file-path-traversal/lab-simple
- ●Traversal sequences blocked, absolute path bypass (PRACTITIONER): https://portswigger.net/web-security/file-path-traversal/lab-absolute-path-bypass
- ●Traversal sequences stripped non-recursively (PRACTITIONER): https://portswigger.net/web-security/file-path-traversal/lab-sequences-stripped-non-recursively
- ●Traversal sequences stripped with superfluous URL-decode (PRACTITIONER): https://portswigger.net/web-security/file-path-traversal/lab-superfluous-url-decode
- ●Validation of start of path (PRACTITIONER): https://portswigger.net/web-security/file-path-traversal/lab-validate-start-of-path
- ●Validation of file extension with null byte bypass (PRACTITIONER): https://portswigger.net/web-security/file-path-traversal/lab-validate-file-extension-null-byte-bypass
Self-hosted lab targets
- ●bWAPP -- LFI / Path Traversal modules: http://www.itsecgames.com
- ●DVWA -- File Inclusion modules: https://github.com/digininja/DVWA
- ●WebGoat (OWASP) -- File Inclusion lessons: https://github.com/WebGoat/WebGoat
- ●Juice Shop -- multiple path-related challenges: https://github.com/juice-shop/juice-shop
Lab progression suggestion
- ●Week 1: PortSwigger Apprentice + Practitioner labs + ANAS-PT-01/02/03 + sections 1-8.
- ●Week 2: PortSwigger remaining labs + ANAS-PT-04 to 07 + read disclosed bounty reports in section 17.
- ●Week 3: ANAS-PT-08/09/10 + reproduce log poisoning locally on a DVWA install.
- ●Week 4: ANAS-PT-11 to 14 + practice Synacktiv filter chain on a controlled target.
- ●Week 5: ANAS-PT-15 to 18 + start hunting on bounty programs that scope LFI explicitly.
SECTION 20. Cheat Sheet
SECTION 21. Exam
Thirty multiple-choice questions. Answer key at the end.
- ●1. The canonical CWE for Path Traversal is:
A) CWE-79 B) CWE-22 C) CWE-89 D) CWE-352
- ●2. The CWE for Local File Inclusion specifically is:
A) CWE-22 B) CWE-98 C) CWE-79 D) CWE-1021
- ●3. Path Traversal allows an attacker to:
A) Crash the server B) Read files outside the intended directory by using `../` C) Inject SQL queries D) Steal cookies
- ●4. The primary difference between Path Traversal and LFI:
A) They are unrelated B) LFI executes the included file as code; Path Traversal only reads C) LFI is older D) Path Traversal works only on Windows
- ●5. A response containing `root:x:0:0:` confirms:
A) SQL injection B) Path Traversal to /etc/passwd C) XSS D) CSRF
- ●6. Which payload bypasses a filter that strips `../` exactly once?
A) `../../../etc/passwd` B) `....//....//....//etc/passwd` C) `/etc/passwd` D) `%2e%2e%2f`
- ●7. Which payload bypasses a filter that URL-decodes input then strips `../`?
A) `../../../etc/passwd` B) `..%252f..%252f..%252fetc%252fpasswd` C) `../../../etc/passwd%00` D) `/etc/passwd`
- ●8. The null-byte bypass (`%00`) works against:
A) PHP 8.x B) PHP < 5.3.4 and similar legacy environments C) All Node.js versions D) Modern Go applications
- ●9. A start-of-path validation that checks input begins with `/var/www/files/` can be bypassed with:
A) `/var/www/files/../../../etc/passwd` B) `?file=evil` C) `etc/passwd` D) Random uppercase
- ●10. Which Windows file is always present and useful as a traversal test?
A) `c:\windows\system32\license.rtf` B) `c:\evil.txt` C) `c:\backdoor.exe` D) `c:\windows\virus.dll`
- ●11. The Apache 2.4.49 vulnerability (CVE-2021-41773) used which encoded sequence?
A) `..\\..\\` B) `.%2e/` C) `%252f` D) `/etc/passwd`
- ●12. Which PHP wrapper reveals source code by base64-encoding read content?
A) `data://` B) `expect://` C) `php://filter/convert.base64-encode/resource=index` D) `phar://`
- ●13. Which PHP wrapper sends a POST body to be evaluated as PHP?
A) `php://input` (with `allow_url_include=On`) B) `php://output` C) `data://` D) `phar://`
- ●14. Which technique poisons a server log file with PHP code then includes the log?
A) SQL injection B) Log poisoning C) XSS D) CSRF
- ●15. A common LFI exploitation target for `/proc`:
A) `/proc/version` B) `/proc/self/environ` (poisoned via User-Agent) C) `/proc/cpuinfo` D) `/proc/meminfo`
- ●16. The Synacktiv PHP filter chain attack:
A) Requires file upload B) Requires `allow_url_include=On` C) Turns any include() of a user-controlled string into RCE without uploads or special config D) Works only on Windows
- ●17. The Tomcat/Spring path-normalization bypass uses:
A) `..%2f` B) `..;/..;/..;/etc/passwd` C) `..\\` D) `data://`
- ●18. The Spring MVC CVE-2018-1271 traversal used:
A) Double-URL-encoded backslashes B) Null bytes C) Semicolons D) NULL parameters
- ●19. To read PHP source code without executing it via LFI you use:
A) `data://text/plain,<?php phpinfo();?>` B) `php://filter/convert.base64-encode/resource=index` C) `expect://id` D) `phar://`
- ●20. The Kubernetes file critical to exfiltrate via LFI:
A) `/run/secrets/kubernetes.io/serviceaccount/token` B) `/tmp/k8s.txt` C) `/etc/k8s.cfg` D) `/usr/k8s.conf`
- ●21. UNC-path bypass on Windows uses:
A) `c:\file` B) `\\localhost\c$\windows\win.ini` C) `~/file` D) `/file`
- ●22. The BEST defense against Path Traversal:
A) Hide the file parameter B) Strict allowlist + canonical-path validation (`realpath`/`Path.resolve` + `startsWith(base)`) C) WAF rules alone D) Disable HTTPS
- ●23. `basename()` in PHP:
A) Encodes the filename B) Strips directory components from a path C) Validates the file exists D) Adds a `.php` suffix
- ●24. `realpath()` returns:
A) The original user input B) The canonical absolute path after resolving symlinks and `..` C) The relative path D) Nothing
- ●25. `allow_url_include=Off` in PHP prevents:
A) All file reads B) Inclusion of remote URLs and certain wrappers like `data://` and `php://input` C) Loading any image D) HTTPS requests
- ●26. The highest-impact bug bounty target with Path Traversal:
A) Reading `/etc/passwd` B) Reading `/etc/shadow` and chaining to RCE via Synacktiv filter chain C) Reading `index.html` D) Reading `/proc/version`
- ●27. The payload `../../../etc/passwd%00.png` assumes:
A) The application appends `.png` and uses legacy PHP that truncates at null byte B) PHP 8 strictly handles null bytes C) The file is encrypted D) The web server is Windows-only
- ●28. When `..` is replaced by empty string non-recursively, the bypass is:
A) `....//` B) `\\` C) `data://` D) `c:\`
- ●29. The Synacktiv tool that generates filter chains for LFI to RCE is:
A) sqlmap B) php_filter_chain_generator C) nikto D) dirbuster
- ●30. The MOST important takeaway about Path Traversal and LFI:
A) They are extinct in 2026 B) Foundational bugs caused by trusting user input as filesystem paths; defense requires canonical-path validation and allowlists C) Only WAFs prevent them D) They affect only PHP
Answer key
- ●1.B 2.B 3.B 4.B 5.B 6.B 7.B 8.B 9.A 10.A
- ●11.B 12.C 13.A 14.B 15.B 16.C 17.B 18.A 19.B 20.A
- ●21.B 22.B 23.B 24.B 25.B 26.B 27.A 28.A 29.B 30.B
Scoring
- ●27 to 30: Path Traversal / LFI expert.
- ●24 to 26: Solid.
- ●19 to 23: Functional; re-read sections 11 and 16.
- ●Below 19: re-read sections 1 to 8 and retake.
SECTION 22. Certificate Requirements
- ●Read all 24 sections of this course.
- ●Score 24/30 or higher on section 21.
- ●Complete all 6 PortSwigger Web Security Academy Path Traversal labs.
- ●Complete at least 12 of the 18 planned ANAS PT Labs (once released).
- ●Build a working PoC that demonstrates LFI source disclosure via `php://filter` on a controlled target.
- ●Demonstrate one LFI-to-RCE chain (log poisoning, Synacktiv filter chain, or PEAR/PECL) in a sandbox.
- ●Write a 500-word case study on one of the CVEs in section 17.
- ●Maintain a personal payload library of 40+ traversal/LFI payloads organized by tier.
Ethical baseline
The techniques here work against real production systems. Use them only against systems you own or have explicit written permission to test. Reading files like `/etc/shadow`, `id_rsa`, or `.aws/credentials` without authorization is a criminal act in every jurisdiction this course is taught in.
SECTION 23. Important Notes
Common beginner mistakes
- ●Stopping after `../../../etc/passwd` works. Always escalate to source code, configs, and RCE.
- ●Trying only one encoding variant. Walk the full ladder.
- ●Confusing Path Traversal (read) with LFI (execute). Different sinks, different payloads.
- ●Not testing `php://filter` wrappers on every PHP target.
- ●Forgetting log poisoning when wrappers fail.
- ●Ignoring Windows targets when the server runs Windows.
- ●Reporting traversal on a static file (e.g., `index.html`) with no real impact.
Pentester tips
- ●Always benchmark with a known-good file (existing image) before traversal payloads.
- ●Map the application thoroughly; hidden parameters often have the traversal bugs the main UI does not.
- ●When the response is a binary download, hex-dump it to confirm content (sometimes traversal succeeds but content is base64 from a wrapper).
- ●Always try `php://filter/convert.base64-encode/resource=` for source disclosure on PHP targets.
- ●When you have LFI but no wrappers fit, reach for the Synacktiv filter chain generator.
- ●When you have LFI but cannot see output, use Lightyear's error-based oracle.
Bug bounty tips
- ●Basic traversal (read `/etc/passwd`) pays $1,000-$3,000.
- ●Source code disclosure pays $3,000-$10,000.
- ●LFI to RCE pays $10,000-$50,000+ depending on the target.
- ●Always demonstrate the full chain. A clean PoC with `id` output is gold.
- ●Triagers love a sanitized progression: `/etc/passwd` first, then config secrets, then RCE.
- ●Cloud metadata leakage chained from LFI is a critical multiplier on cloud-hosted targets.
Red team tips
- ●Path Traversal often leaks SSH keys, giving lateral movement without bypassing auth.
- ●LFI chained with log poisoning is one of the quietest RCE techniques (no malware, no upload).
- ●The Synacktiv filter chain leaves minimal forensic traces because the payload is URL parameters, not files.
- ●Cloud metadata via LFI gives cloud credentials without ever bypassing authentication.
- ●Persistence via LFI-installed webshells (in writable directories like `/tmp` or `uploads/`) is silent.
Defender tips
- ●Treat every file-system call with user input as suspect until proven safe.
- ●Centralize file access through a single safe helper used by every controller.
- ●SAST rules that flag default `include`, `require`, `fs.readFile`, `send_file`, `File.ReadAllText` with user input.
- ●Run the web user with no read access to `/etc/passwd` (where feasible), `/etc/shadow`, `/home`, `/root`, secrets directories.
- ●Set `open_basedir`, `allow_url_include=Off`, `allow_url_fopen=Off` in PHP.
- ●Add a CI test that asserts canonical-path validation on every file endpoint.
Real-world advice
- ●Modern frameworks normalize paths but still have edge-case bypasses (Spring, Tomcat, Apache, Nginx). Always test on hardened stacks.
- ●WAFs catch obvious `../` patterns but rarely the modern Synacktiv filter chains.
- ●Bug bounty triagers want to see the chain end-to-end, not just `/etc/passwd`.
- ●In production, never use destructive RCE payloads. Use `id`, `whoami`, `hostname` only.
- ●Always clean up artifacts (uploaded ZIPs, written webshells, modified configs, log entries).
Things to remember during exams
- ●CWE-22 = Path Traversal. CWE-98 = LFI. CWE-73 = External control of filename.
- ●`....//` defeats non-recursive `../` filters.
- ●`%252f` defeats single-decode filters.
- ●Absolute path bypasses prefix-check defenses.
- ●`%00` defeats legacy extension-suffix checks.
- ●`php://filter` is the golden ticket for LFI exploitation.
Things to remember during real assessments
- ●Get explicit written permission to read sensitive system files (`/etc/passwd`, `/etc/shadow`, SSH keys).
- ●Throttle enumeration. Mass requests for hundreds of files look like an attack.
- ●Never exfiltrate real customer data. Use the smallest possible benign read to prove the bug.
- ●Save full HTTP traces. Triagers need to reproduce.
- ●Clean up: remove uploaded shells, files written to `/tmp`, poisoned logs where possible.
Frequently confused concepts
- ●Path Traversal vs LFI -- Path Traversal reads files; LFI executes them. Same root cause, different sink.
- ●LFI vs RFI -- LFI reads local files; RFI includes remote URLs (requires `allow_url_include=On`).
- ●LFI to RCE chain -- LFI is read access; RCE comes from wrappers, log poisoning, or filter chains.
- ●Path Traversal vs SSRF -- Path Traversal targets the filesystem; SSRF targets the network. They sometimes chain.
- ●Directory Traversal vs Path Traversal -- same thing, different name.
Interview tips
- ●Explain Path Traversal with a story-free walkthrough: a download endpoint, a `../../../etc/passwd` payload, and what the OS does with it.
- ●Be ready to draw the path resolution on a whiteboard.
- ●Mention modern techniques: Synacktiv filter chains, log poisoning, PEAR/PECL.
- ●Cite CVE-2021-41773 (Apache) or CVE-2019-19781 (Citrix) for real-world impact.
- ●Always close with the defense: canonical path resolution plus allowlists.
Key takeaways
- ●Path Traversal is the oldest web bug class that still ships in modern code.
- ●`../` plus one missing check equals total system compromise.
- ●Wrappers turn read primitives into execution primitives.
- ●Modern filter chains achieve universal RCE without any special server config.
- ●The fix is one architectural rule: never trust user input as a path; always validate the canonical resolved path.
SECTION 24. Final Word from Your Instructor
You finished the long walkthrough on Path Traversal and Local File Inclusion. You now know more about these bug classes than most working developers, and enough to find them, exploit them responsibly, and fix them in any codebase.
Here is the short version.
Path Traversal works because filesystems obey three special tokens (`.`, `..`, `/`) and applications concatenate user input into paths without verifying that the resolved canonical path stays inside the intended directory. The user supplies `../../../etc/passwd`, the OS resolves it literally, the application happily reads it. With one tiny escalation -- swapping `readfile()` for `include()` -- the same trick becomes Local File Inclusion, which evaluates the file as PHP code. Combined with wrappers (`php://filter`, `php://input`, `data://`), log poisoning, session inclusion, the Synacktiv filter chain, or PEAR/PECL command injection, LFI reaches unauthenticated remote code execution on the most popular stacks on the internet in 2026.
The defense is well-known and reproducible per language. Strip directory components with `basename()`. Resolve the path canonically with `realpath()` or its equivalent. Verify the canonical path still starts with the intended base directory. Apply a strict allowlist of expected filenames when feasible, or replace user-controllable filenames with opaque server-side IDs. Disable `allow_url_include` and `allow_url_fopen` in PHP. Run the web user with no read access to sensitive directories. Block egress to cloud metadata IPs.
The CVEs prove this is current. CVE-2021-41773 / CVE-2021-42013 (Apache 2.4.49 / 2.4.50) mass-compromised tens of thousands of hosts within 48 hours of disclosure. CVE-2019-19781 (Citrix) became a primary APT entry point for years. CVE-2024-21896 and CVE-2025-27210 reach Node.js core itself. Bounty payouts in the corpus at https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPFILEREADING.md range from $1,000 for basic disclosures to $12,000 for GitLab Nuget traversal and beyond for fully-chained RCE.
When you see a `?file=`, `?path=`, `?page=`, `?template=`, or `?include=`, you have a candidate. The first probe is `../../../etc/passwd`. The next is the encoding ladder. The third is `php://filter`. The fourth is log poisoning. The fifth is the Synacktiv filter chain. Walk the ladder. Document the chain. Submit the report.
Stay curious. Stay ethical. Verify scope before you touch anything. Read more code than you write. The techniques here are real, the impact is real, and so is the responsibility that goes with the knowledge.
Go hunt.