Path traversal esineb kõikjal, kus Teie kood koostab välisest sisendist failitee ega takista selle lahendumist kataloogist väljapoole, mida te silmas pidasite. Selle kohta käib kirje CWE-22. Leidke kõik sellised kohad, lõpetage failinimede vastuvõtmine kasutajatelt ja kontrollige ülejäänud sisendi puhul lahendatud teed.
Mida ründaja saab
Lugemine on vaid algus. Sõltuvalt sellest, mida kood teega teeb, võib ründaja lugeda ootamatuid faile ja paljastada tundlikke andmeid, luua või üle kirjutada programme ja teeke ning seeläbi koodi käivitada või rikkuda faile nii, et toode lakkab töötamast või lukustab kasutajad välja. OWASP nimetab kättesaadavate failide hulgas rakenduse lähtekoodi ja konfiguratsiooni.
Kõige hullemad sihtmärgid on turvamehhanismi taga olevad failid. Paroolifaili lugemine võimaldab kontode vastu brute force'i, ja uue konto lisamine sellisesse faili võib autentimise mööda minna.
Ulatus sõltub platvormist. Windowsis saab ründaja liikuda ainult sellel partitsioonil, kus asub veebijuur, Linuxis aga kogu kettal. Operatsioonisüsteemi pääsukontroll kehtib endiselt lisaks.
Failiteid koostavate kohtade leidmine
Alustage sink'ist, mitte URL-ist. Koostage loend kõigist kutsetest, mis avavad, loevad, serveerivad, include'ivad või kirjutavad faili, ning jälgige iga tee argumenti tagasi selle päritoluni. Loendisse kuulub kõik, mis puutub kokku päringuga, sealhulgas Teie enda wrapper-funktsioonide ja raamistiku helperite taha peidetud kutsed, seega kontrollige ka nende kutsujaid.
Sisend ei piirdu query stringiga. OWASP-i näidete hulgas on get-files.jsp?file=report.pdf, get-page.php?home=aaa.html ja some-page.asp?page=index.html, aga ka cookie. Järgnev lõik on kohandatud OWASP-i (algselt Wikipedia) näitest:
$template = 'blue.php';
if ( isset( $_COOKIE['TEMPLATE'] ) )
$template = $_COOKIE['TEMPLATE'];
include ( "/home/users/phpguru/templates/" . $template );
Cookie TEMPLATE=../../../../../../../../../etc/passwd paneb include() ronima juurkataloogi ja tagastama paroolifaili. Parameetrid nimega file, page, template või f on tavalised kahtlusalused, kuid nimed ei ole töökindel juhis. Jälgige andmeid.
Kontrollige kolme vormi:
- Relatiivne traversal:
../jadad, mis tõusevad ettenähtud kataloogist välja. - Absoluutsed teed:
?f=/etc/passwdvõi?f=/var/www/html/get.php, mis toimivad siis, kui sisendit kasutatakse tervikliku teena. - Remote include'id:
?page=http://other-site/..., kui include-mehhanism aktsepteerib URL-e.
Üksikasjalikud veateated aitavad ründajat, sest need paljastavad päris teed, mille vastu pakkumisi teha. Kontrollige, mida Teie rakendus tagastab, kui faili ei leita.
Miks blocklistid ei tööta
../ eemaldamine ei toimi, sest sama traversalil on palju kirjapilte:
%2e%2e%2f,..%2fja%2e%2e/tähendavad kõik../...%5cja%2e%2e%5ctähendavad..\, mis on oluline Windowsis, kus töötavad mõlemad eraldajad.%252e%252e%255con..\topeltkodeeritud vorm. Veebikonteinerid dekodeerivad ühe taseme, seega jõuab see kohale endiselt kodeerituna. Kui Teie kood või mõni teek dekodeerib selle uuesti, muutub see traversaliks pärast seda, kui kontroll on juba tehtud...%c0%afja..%c1%9con../ja..\täiendavad kodeeringud.- Nullbaiti, näiteks
?file=secret.doc%00.pdf, kasutades võib Java rakendus näha.pdf, samal ajal kui operatsioonisüsteem näeb.doc. Ründajad kasutavad seda valideerimisest möödumiseks.
Filtreerimine kukub läbi ka omaenda reeglite järgi. Kui eemaldada .../...// seest järjest ../, moodustavad järelejäänud märgid taas ../. Ainult / filtreerimine on kasutu, kui failisüsteem aktsepteerib \.
Esimene parandus: lõpetage teede vastuvõtmine
Parim kontroll on kasutaja sisend teelt eemaldada. Kasutage indekseid, mitte failinimede osi. OWASP-i näide on keelefail: kasutaja saadab 5 ja server seob selle keelega, selle asemel et usaldada tagasi saadetud nime.
Allalaadimiste puhul hoidke faile ID all ja serveerige ID järgi, nii et kasutaja ei esita kunagi nime ega laiendit. Mallide näide muutub selliseks:
$templates = [1 => 'blue.php', 2 => 'red.php'];
$id = (int) ($_COOKIE['TEMPLATE'] ?? 1);
$template = $templates[$id] ?? 'blue.php';
include '/home/users/phpguru/templates/' . $template;
Kui peate nime siiski vastu võtma, valideerige see teadaolevalt heade väärtuste vastu ja lükake ülejäänud tagasi. Kasutage ranget märkide allowlisti, failinimes kuni ühte ., ilma kataloogieraldajateta ja lubatud laiendite loendiga. Lükake halb sisend tagasi, selle asemel et seda sanitiseerida.
Teine parandus: kanoniseerige, siis kontrollige
Kui sisend peab jõudma faili-API-ni, dekodeerige see üks kord ja lahendage seejärel sisseehitatud kanoniseerimisfunktsiooniga enne valideerimist:
| Keel | Funktsioon |
|---|---|
| C | realpath() |
| Java | getCanonicalPath() |
| ASP.NET | GetFullPath() |
| Perl | realpath() või abs_path() |
| PHP | realpath() |
Need eemaldavad .. jadad ja sümboolsed lingid. Pärast lahendamist veenduge, et tulemus asub endiselt Teie baaskataloogis, ja keelduge päringust, kui see seal ei asu. PHP skitsis on $name allowlistist juba läbi läinud:
$base = realpath('/home/users/phpguru/templates');
$full = realpath($base . '/' . $name);
if ($full === false || strpos($full, $base . DIRECTORY_SEPARATOR) !== 0) {
http_response_code(404);
exit;
}
Hoidke iga kontroll serveris. Kliendipoolsest valideerimisest pääseb triviaalselt mööda.
Piirake kahju
Hoidke tundlikud konfiguratsioonifailid veebijuurest väljas. Windows IIS-is hoidke veebijuur süsteemiketta väliselt, et traversal ei ulatuks süsteemikataloogideni. Chrooted jailid ja code access policy'd piiravad, kuhu faile saab lugeda või kirjutada, ning vähendavad kahju, kui mõni kontroll jääb tegemata.
Testimiseks esitage ülaltoodud kodeeringud uuesti igale leitud parameetrile, lisaks absoluutne tee ja remote URL. Penetratsioonitest teeb seda süstemaatiliselt.
Kust alustada
- Koostage loend kõigist Teie koodi failikäsitluse kutsetest, lisage nende ümber olevad wrapperid ja raamistiku helperid ning jälgige iga tee argumenti tagasi selle allikani, sealhulgas cookie'd ja päised.
- Asendage kasutaja antud failinimed serveris failidega seotud ID-dega, alustades allalaadimistest ning malli- ja keelevalikust.
- Iga allesjääva juhu puhul dekodeerige üks kord, kanoniseerige platvormi funktsiooniga ja lükake tagasi kõik, mis lahendub baaskataloogist väljapoole.
- Kustutage blocklisti kood, mis eemaldab
../või/, ja asendage see märkide, laiendite ning võimaluse korral väärtuste allowlistiga. - Viige tundlik konfiguratsioon veebijuurest välja ning lõpetage veateadete tagastamine, mis paljastavad failiteid.
- Testige iga parameetrit kodeeritud, topeltkodeeritud, absoluutsete ja remote variantidega ning hoidke need juhud regressioonitestidena.
