lfi

LFI – Introduzione

Analizzando pagine web dinamiche di vari siti o ad esempio dei CMS (WordPress, Drupal, Joomla) è possibile notare come gli sviluppatori ottimizzino il codice distribuendolo su più pagine.

In questo modo i programmatori evitano di creare file (ad esempio php) troppo grandi e di conseguenza meno chiari/flessibili.

Per incorporare il contenuto di una pagina php dentro l’altra, vengono utilizzate le funzioni:

include(‘pagina2.php’);

include_once(‘pagina2.php’);

require(‘pagina2.php’);

require_once(‘pagina2.php’);

Cosa può accadere se il nome della pagine inclusa viene richiamata col metodo GET o POST  senza l’inserimento di adeguati filtri?

La risposta è semplice: è possibile leggere file di sistema o scaricare il codice sorgente degli applicativi, questa vulnerabilità viene chiamata LFI  Local File Inclusion.

E’ importante precisare due punti per il corretto rilevamento della vulnerabilità:

  1. I files a cui avrà accesso la pagina affetta dal bug, devono avere almeno i permessi in lettura per l’utente Apache (o  l’utente di riferimento del demone http)
  2. Il sistemista del web server non ha circoscritto l’area di lavoro dell’applicativo

Esempio vulnerabilità LFI

Url server web: 10.0.0.70

Pagina Vuln: index.php

Questo è un esempio di codice php (index.php) che include il nome di un’altra pagina tramite metodo GET (variabile ID):

<?php
   if ( isset( $_GET['ID'] ) ) {
      include( $_GET['ID']);
   }
?>

Qui di seguito invece il codice della pagina che verrà inclusa (pagina2.php):

<?php

echo "Pagina inclusa correttamente!\n";

?>

Per testare la pagina basta aprire il browser ed inserire l’url “http://10.0.0.70/index.php?ID=pagina2” :

lfi

Il problema della pagina index.php è che non esiste alcun controllo sul valore che le viene passato tramite GET, infatti è possibile scalare a ritroso le directory fino ad includere file di sistema.

La tecnica si chiama “Path Traversal” e vengono utilizzati principalmente  i caratteri “..” .

I caratteri “..” vengono utilizzati sia nei sistemi *nix che windows per tornare indietro di una directory, quindi è possibile concatenarli fino ad arrivare al file interessato:

http://10.0.0.70/index.php?ID=../../../etc/passwd

lfi

Il file /etc/passwd avendo accesso in lettura da parte di tutti gli utenti viene letto anche da apache, in questo caso sfruttando la vulnerabilità lfi  ha è possibile avere la lista di tutti gli utenti di sistema.

In questo caso un possibile malintenzionato potrebbe già eseguire un brute-force mirato, scegliendo quale utente con relativa shell prendere di mira.

Naturalmente i files sensibili dove può accedere in lettura soltanto l’utente root, ad esempio /etc/shadow, non possono essere letti da apache.

Per risolvere questo problema spesso gli sviluppatori implementano soltanto l’estensione “.php” dentro il codice della pagina, precisamente nell’istruzione include:

<?php
   if ( isset( $_GET['ID'] ) ) {
      include( $_GET['ID'] . ".php");
   }
?>

Così facendo viene aggiunta automaticamente la stringa “.php” a qualsiasi valore passato tramite GET.

Fino a poco tempo fa questo filtro veniva aggirato inserendo il carattere null “%00” in fondo all’url dell’indirizzo, in questo modo l’estensione del file richiamato veniva spezzata e quindi ignorata:

http://10.0.0.70/index.php?ID=../../../etc/passwd%00

Questa tecnica è possibile attuarla fino alla versione 5.3.3 di php, infatti nella 5.3.4 è stata rilasciata una patch che permette di ignorare e non interpretare il carattere null.

RedHat Enterprise e CentOS hanno reso disponibile la versione di php non affetta dal bug a Novembre 2013:

https://rhn.redhat.com/errata/RHSA-2013-1615.html

Esempi di Path Traversal per LFI

Per contrastare le vulnerabilità lfi, molti applicativi web si limitano a normalizzare le query controllando che non siano presenti i caratteri “..” “../” o “..\” .

Quella che riporto di seguito è una lista di caratteri URL e UTF-8 encode che vengono utilizzati per aggirare i filtri:

URL:

  • %2e%2e%2f viene interpretato come ../
  • %2e%2e/ viene interpretato come ../
  • ..%2f viene interpretato come ../
  • %2e%2e%5c viene interpretato come ..\

UTF-8:

  • ..%c0%af viene interpretato come ../
  • ..%c1%9c viene interpretato come ..\

La funzione php  str_replace sembra essere efficace anche con gli url encode, per fare un test basta modificare la pagina index.php che è stata creata precedentemente.

Per comodità eseguirò un test col browser testuale curl inserendo l’url econde %2e%2e%2f a discapito dei caratteri “../

[root@localhost lfi]# curl http://10.0.0.70/index.php?ID=%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/redhat-release 
CentOS release 5.10 (Final) 
[root@localhost lfi]#

Adesso modificherò la pagina php utilizzando la funzione str_replace per sostituire qualsiasi stringa “../” col carattere “_”

<?php
   if ( isset( $_GET['ID'] ) ) {
        $ID = $_GET['ID'];
        $ID = str_replace('..', '_', $ID);
        echo "$ID\n";
      include( $ID );
   }
?>

Inserisco l’indirizzo nel browser:

[root@localhost lfi]# curl http://10.0.0.70/index.php?ID=%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/redhat-release
etc/redhat-release <-- risultato echo 
[root@localhost lfi]#

Come si può notare tutti i caratteri sono stati decodificati e sostituiti, infatti il file /etc/redhat.release non viene aperto.

Questo test LFI è stato effettuato su una CentOS 5.10 e php53-5.3.3-22.el5_10.

Scaricare file tramite LFI

Come avevo specificato nell’introduzione, tramite lfi è possibile scaricare file dal server remoto come ad esempio i sorgenti delle pagine dinamiche.

Esistono vari applicativi web che permettono di integrare o scaricare file di testo, foto, documenti pdf ecc.., e se non hanno un solido controllo nelle query possono essere sfruttate per scaricare file non autorizzati.

Un famosissimo script noto per aver avuto grossi problemi di lfi si chiama “eLouai’s Force Downlaod” e nonostante sia vecchissimo è ancora diffuso in rete.

E chiaro che se un malintenzionato riesce a scaricare la pagina index del sito, oltre agli accessi al database, può risalire a tutto il resto delle pagine

lfi

Il plugin wordpress Download Shortcode è una piccola utility che permette di inserire link a file multimediali all’interno di shortcodes, basandosi sullo script eLouai’s Force Downlaod ma con una piccola modifica anti lfi:

$filename = $_GET['file'];

// Check for empty value or shenanigans
if (
     // From validate_file() in WP core
        false !== strpos( $filename, '..' )
        || false !== strpos( $filename, './' )
        || ':' == substr( $filename, 1, 1 )
    // Empty path
        || $filename == ""
    // Doesn't exist
        || ! file_exists( $filename )
    // Is a PHP file
        || strpos( $filename, '.php' ) )
    exit();

strpos è una funzione di php che permette di estrarre  porzioni da una stringa partendo dal primo carattere (valore 0).

Nello script soprastante il flusso viene interrotto se nella variabile $file (il nome del file passato tramite GET) esiste una stringa con i caratteri “..“, “./“, “.php”.

Interessante la parte di codice “‘:’ == substr( $filename, 1, 1 )“, in questo caso viene controllato se il secondo carattere della stringa è il simbolo “:” che potrebbe essere utilizzato per includere file all’interno di unità di windows (C:\windows, D:\, F:\, ecc…).

Questi sono alcuni esempi da cui partire per rendere i propri codici più sicuri contro LFI, nal prossimo articolo tratterò alcune soluzioni a livello sistemistico.