Path traversal (directory traversal)
CWE-22OWASP A01:2021Bijgewerkt 29 augustus 20265 min leestijd
Path traversal, ook directory traversal genoemd, is een kwetsbaarheid waarbij een aanvaller een bestandspad zo manipuleert dat de applicatie bestanden buiten de bedoelde map opent. Met de reeks ../ klimt hij uit de toegestane map en leest hij gevoelige bestanden zoals configuraties, sleutels of broncode.
Path traversal, ook wel directory traversal genoemd, is een klassieke maar nog altijd veelvoorkomende webkwetsbaarheid: met een paar tekens breekt een aanvaller uit de map waarin uw applicatie hem wilde houden en leest hij bestanden elders op de server. In deze uitleg leest u wat path traversal is, hoe zo’n aanval verloopt, wat een aanvaller ermee kan bereiken en hoe u uw applicatie ertegen beschermt.
Wat is path traversal?
Path traversal (ook wel directory traversal) is een kwetsbaarheid waarbij een aanvaller een bestandsnaam of pad uit gebruikersinvoer zo manipuleert dat de applicatie bestanden buiten de bedoelde map opent. De sleutel is de reeks ../, die in vrijwel elk besturingssysteem “ga één map omhoog” betekent. Door die reeks vaak genoeg te herhalen, klimt de aanvaller helemaal naar de hoofdmap van het bestandssysteem en daalt vandaar af naar precies het bestand dat hij zoekt.
Stel u een archiefmedewerker voor die documenten ophaalt aan de hand van een routebeschrijving die de bezoeker invult. De bedoeling is dat hij alleen in de publieke kast graait. Maar het formulier vraagt letterlijk om een pad, en de bezoeker schrijft: “verlaat de publieke kast, één verdieping omhoog, naar de personeelskast, pak het salarisdossier.” De medewerker volgt de instructie gedwee, want die staat immers netjes ingevuld. De reeks ../ is precies die instructie “één verdieping omhoog”, en de applicatie voert hem klakkeloos uit.
Hoe werkt een path-traversal-aanval?
Path traversal duikt op zodra een applicatie een door de gebruiker aangeleverde naam samenvoegt met een pad op de server en het resultaat opent: bij een downloadfunctie, een template-loader, een taalbestand of een “bekijk logbestand”-scherm. Zolang die invoer niet wordt gecontroleerd, bepaalt de gebruiker welk pad er ontstaat.
Kwetsbaar:
// Downloadfunctie die de opgegeven bestandsnaam direct achter een basispad plakt
app.get('/download', (req, res) => {
const file = req.query.file;
const filePath = path.join('/var/www/files', file);
res.sendFile(filePath);
});
Bij normaal gebruik vraagt iemand /download?file=handleiding.pdf op en krijgt netjes /var/www/files/handleiding.pdf terug. Maar path.join rekent ../ gewoon uit. Vraagt een aanvaller /download?file=../../../../etc/passwd op, dan verdampt het basispad tijdens die berekening en levert de server /etc/passwd uit, de lijst met systeemgebruikers. Op Windows werkt hetzelfde met de backslash, via een verzoek als ..\..\..\windows\win.ini of een configuratiebestand vol wachtwoorden. Het aantal ../ hoeft niet precies te kloppen: verder omhoog klimmen dan de hoofdmap kan niet, want die is de bovengrens, dus een aanvaller stapelt er gerust een paar te veel om zeker in de root uit te komen.
Veilig:
import path from 'node:path';
const BASE_DIR = path.resolve('/var/www/files');
app.get('/download', (req, res) => {
const requested = req.query.file ?? '';
// Los het pad volledig op en controleer of het binnen de basismap blijft
const resolved = path.resolve(BASE_DIR, requested);
if (resolved !== BASE_DIR && !resolved.startsWith(BASE_DIR + path.sep)) {
return res.status(403).send('Toegang geweigerd');
}
res.sendFile(resolved);
});
De veilige variant vertrouwt niet op de invoer, maar op het eindresultaat. Eerst wordt het volledige pad opgelost met path.resolve, zodat alle ../-sprongen daadwerkelijk worden uitgerekend. Daarna controleert de code of dat opgeloste pad nog altijd binnen BASE_DIR valt. Wijst het buiten de basismap, hoeveel ../ de aanvaller ook stapelt, dan wordt het verzoek geweigerd. Deze controle achteraf is betrouwbaarder dan proberen ../ uit de invoer te filteren, want zulk filteren is met dubbele codering, backslashes of exotische varianten telkens weer te omzeilen.
../ uit de invoer. Aanvallers omzeilen zo’n filter met URL-codering (%2e%2e%2f), dubbele codering (%252e), backslashes of geneste varianten als ....//. Valideer het definitieve, opgeloste pad in plaats van de ruwe invoer.Wat is de impact van path traversal?
Wat een path traversal precies waard is, hangt af van wat er op de server te vinden is, vandaar de spanwijdte van medium tot hoog. In het gunstigste geval leest een aanvaller alleen bestanden die weinig prijsgeven. Maar meestal ligt er meer voor het oprapen: broncode, configuratiebestanden met database-wachtwoorden, een .env vol API-sleutels, SSH-privésleutels of sessiebestanden waarmee accounts worden overgenomen.
Technisch reikt de schade verder dan alleen lezen. Kan de aanvaller via hetzelfde lek ook bestanden schrijven of overschrijven (denk aan een upload- of uitpakfunctie die paden niet controleert, het zogeheten zip slip) dan kan hij een webshell wegschrijven of bestaande code vervangen, en zo path traversal opwaarderen tot remote code execution. Voor het bedrijf betekent dat op zijn minst een datalek, en in het ergste geval een volledig gecompromitteerde server. Omdat het lek geen speciaal gereedschap vereist en vaak met één HTTP-verzoek te misbruiken is, wordt het door geautomatiseerde aanvallers op grote schaal afgetast.
Hoe spoor je path traversal op?
Bij een handmatige test voert een pentester in elk veld dat een bestandsnaam, pad, taal of template lijkt te verwerken varianten van ../ in en let op wat er terugkomt. Levert ../../../../etc/passwd de inhoud van dat bestand op, of verraadt een foutmelding een absoluut pad, dan is het raak. Ook worden coderingstrucs beproefd (URL-codering, dubbele codering, backslashes op Windows) om zwakke filters te ontmaskeren. Parameters die verdacht veel op bestandsverwijzingen lijken, zoals file=, path=, template= of lang=, krijgen extra aandacht. Geautomatiseerde scanners vinden de voor de hand liggende gevallen, maar missen vaak de plekken waar invoer indirect in een pad belandt. AssistSec neemt path traversal standaard mee in een penetratietest en beproeft juist die minder zichtbare invoerpunten.
Hoe voorkom je path traversal?
- Los het volledige pad op en controleer dat het binnen de toegestane basismap blijft; weiger al het andere.
- Werk waar mogelijk met een allowlist of een indirecte verwijzing, bijvoorbeeld een id dat u koppelt aan een vaste bestandsnaam, in plaats van een vrij in te vullen pad.
- Strip mappaden met
path.basenameals de gebruiker alleen een losse bestandsnaam hoeft op te geven. - Decodeer invoer volledig vóór de validatie, zodat
%2e%2e%2fen dubbele codering geen filter kunnen omzeilen. - Vertrouw niet op het uitfilteren van
../; valideer altijd het definitieve, opgeloste pad. - Draai de applicatie met minimale rechten, zodat het proces bij misbruik zo min mogelijk bestanden kan lezen.
- Bewaar gevoelige bestanden zoals
.env, sleutels en back-ups buiten elke map die de webserver kan benaderen.
Bronnen
Veelgestelde vragen
Wat is het verschil tussen path traversal en local file inclusion?
Path traversal draait om het uitlezen, en soms schrijven, van willekeurige bestanden door het pad te manipuleren. Bij local file inclusion, kortweg LFI, wordt een ingesloten bestand niet alleen gelezen maar ook uitgevoerd, waardoor de gevolgen vaak zwaarder zijn. LFI is in de praktijk vaak een path traversal die in een include-functie belandt.
Werkt path traversal ook op Windows-servers?
Ja. Naast de Unix-notatie met ../ accepteert Windows ook de backslash als scheidingsteken, dus dezelfde truc werkt daar met omgekeerde schuine strepen. Aanvallers proberen doorgaans beide varianten, plus gecodeerde vormen, om filters te omzeilen.
Is path.join genoeg om path traversal te voorkomen?
Nee. path.join rekent ../ juist uit, dus een pad als ../../etc/passwd wordt gewoon opgelost naar een bestand buiten uw map. U moet het opgeloste pad daarna expliciet controleren tegen de toegestane basismap.
Kan path traversal leiden tot volledige serverovername?
Ja. Kan een aanvaller via hetzelfde lek ook bestanden schrijven of overschrijven, of een ingesloten bestand laten uitvoeren, dan plaatst hij een webshell en bereikt zo remote code execution. Alleen kunnen lezen is al ernstig, maar schrijven tilt de impact naar serverovername.
Verwante artikelen
- CVE'sCWE-22A01:2021FortiOS SSL VPN (CVE-2018-13379)CVE-2018-13379 uitgelegd: hoe een path traversal in FortiOS SSL VPN wachtwoorden in platte tekst prijsgaf en jaren later nog werd misbruikt.
- KwetsbaarhedenCWE-639A01:2021Insecure direct object reference (IDOR)IDOR uitgelegd: hoe aanvallers via aanpasbare ID's in URL's of API's andermans gegevens inzien of wijzigen, en hoe u dit opspoort en voorkomt.
- KwetsbaarhedenCWE-94A03:2021Remote code execution (RCE)Remote code execution (RCE) uitgelegd: hoe aanvallers via ongefilterde invoer eigen commando's of code op uw server draaien, en hoe u het voorkomt.
- KwetsbaarhedenCWE-16A05:2021Security misconfigurationSecurity misconfiguration uitgelegd: hoe standaardwachtwoorden, debug-modi en open cloud-buckets aanvallers binnenlaten, en hoe u dit voorkomt.