PHP filesystem attack vectors - Take Two



PHP filesystem attack vectors - Take Two

Name PHP filesystem attack vectors - Take Two
Systems Affected PHP and PHP+Suhosin
Vendor http://www.php.net/
Advisory http://www.ush.it/team/ush/hack-phpfs/phpfs_mad_2.txt
Authors Giovanni "evilaliv3" Pellerano (evilaliv3 AT ush DOT it)
Antonio "s4tan" Parata (s4tan AT ush DOT it)
Francesco "ascii" Ongaro (ascii AT ush DOT it)
Alessandro "jekil" Tanasi (alessandro AT tanasi DOT it)
Date 20090725

I) Introduction
II) PHP arbitrary Local File Inclusion testing
III) PHP arbitrary Local File Inclusion results
IV) PHP arbitrary File Open testing
V) PHP arbitrary File Open results
VI) PHP arbitrary Remote File Upload testing
VII) PHP arbitrary Remote File Upload results
VIII) Conclusions
IX) References

I) Introduction

This is the second part and continuation of our previous "PHP filesystem
attack vectors" [1] research.

Working with s4tan and ascii on the "SugarCRM 5.2.0e Remote Code
Execution" advisory [2] we noticed a strange behaviour on Windows OS:
trying to upload a file named "a.php." results in just "a.php".

Analyzing this we noticed that every time an application, or manually,
was trying to open or save a file with one ore more dots at the end,
Windows was not denying the operation, but it was removing the dots in a
transparent way.

Mindful readers probably have already spotted the issue.

We wanted to take our time for a deeper investigation about what
normalization issues were available and how to take advantage of them
in order to exploit arbitrary local file inclusion/handling and uploads
functionalities (not only on Windows OS but also on GNU/Linux and *BSD).

Below you can find the sources of two simple "academic" fuzzers, later
results are discussed and finally POCs and conclusions are proposed.

II) PHP arbitrary Local File Inclusion testing

This tests include(), include_once(), require(), require_once() and
similiar functions.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

alfi_fuzzer.php:

<?php

error_reporting(0);

$InterestingFile = "test_alfi.php";
$fh = @fopen($InterestingFile, 'w+');
fwrite($fh, "<?php ?>");
fclose($fh);

for ($i = 1; $i < 256; $i++) {
$chri = chr($i);
for ($j = 0; $j < 256; $j++) {
$chrj = chr($j);
for ($k = 0; $k < 256; $k++) {
$chrk = chr($k);
if($chri.$chrj.$chrk == '://') continue;
if ($j == 0) $FuzzyFile = $InterestingFile.$chri;
else if ($k == 0) $FuzzyFile = $InterestingFile.$chri.$chrj;
else $FuzzyFile = $InterestingFile.$chri.$chrj.$chrk;
if(include($FuzzyFile)) {
print($i." ".$j." ".$k." [".$FuzzyFile."]\n");
fclose($fh);
}
if($j == 0) break;
}
}
}

unlink($InterestingFile);

?>

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

Note: This code and the one that will be presented in section IV only
makes use of chars from the ASCII extended table (256 chars) to limit the
combinations because our intent was to test not only a malicious ending
char but a whole ending "extension" of 3 bytes.

A better fuzzer would include UTF-8. In the test we also do not
consider \x00, because this vector is already known [3, 4].

III) PHP arbitrary Local File Inclusion results

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-pl0-Gentoo

PHPFS_MAD2 $ php alfi_fuzzer.php
47 46 46 [test_alfi.php/.]
47 47 47 [test_alfi.php//.]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-pl0-Gentoo + Suhosin-Patch 0.9.27

PHPFS_MAD2 $ php alfi_fuzzer.php

[ NO RESULTS ]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-FreeBSD 7.3 + Suhosin-Patch 0.9.7

PHPFS_MAD2 $ php alfi_fuzzer.php

[ NO RESULTS ]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-

PHP 5.3.0 Windows XP (WampServer 2.0i install)

C:\PHPFS_MAD2> php alfi_fuzzer.php
! Valid chars are: \x20 ( ), \x22 ("), \x2E (.), \x3C (<), \x3E (>)
! Valid strings are all combinations of the above chars.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.3.0 Windows Server 2008 (WampServer 2.0i install)

C:\PHPFS_MAD2> php alfi_fuzzer.php
! Valid chars are: \x20 ( ), \x22 ("), \x2E (.), \x3C (<), \x3E (>)
! Valid strings are all combinations of the above chars.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

IV) PHP arbitrary File Open testing

This tests fopen() and similiar functions.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

afo_fuzzer.php:

<?php

error_reporting(0);

$MaliciousFile = "test_afo.php";

for ($i = 1; $i < 256; $i++) {
$chri = chr($i);
for ($j = 0; $j < 256; $j++) {
$chrj = chr($j);
for ($k = 0; $k < 256; $k++) {
if ($j == 0) $FuzzyFile = $MaliciousFile.$chri;
else if ($k == 0) $FuzzyFile = $MaliciousFile.$chri.$chrj;
else $FuzzyFile = $MaliciousFile.$chri.$chrj.chr($k);
$fh = @fopen($FuzzyFile, 'w+');
if ($fh != FALSE) {
fwrite($fh, $FuzzyFile);
fclose($fh);
if (file_exists($MaliciousFile)) {
if ($j == 0) print($i." ");
else if ($k == 0) print($i." ".$j." ");
else $FuzzyFile = print($i." ".$j." ".$k." ");
print("[".file_get_contents($MaliciousFile)."]\n");
unlink($MaliciousFile);
} else
unlink($FuzzyFile);
}
if($j == 0)
break;
}
}
}

?>

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

V) PHP arbitrary File Open Fuzzer results

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-pl0-Gentoo

PHPFS_MAD2 $ php afo_fuzzer.php
47 46 [test_afo.php/.]
47 47 46 [test_afo.php//.]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-pl0-Gentoo + Suhosin-Patch 0.9.27

PHPFS_MAD2 $ php afo_fuzzer.php

[ NO RESULTS ]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-

PHP 5.2.10-FreeBSD 7.3 + Suhosin-Patch 0.9.7

PHPFS_MAD2 $ php afo_fuzzer.php

47 46 [test_afo.php/.]
47 47 46 [test_afo.php//.]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-

PHP 5.3.0 Windows XP (WampServer 2.0i install)

C:\PHPFS_MAD2> php afo_fuzzer.php

! Valid chars are: \x2E (.), \x2F (/), \x5C (\)
! Valid strings are all combinations of the above chars.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.3.0 Windows Server 2008 (WampServer 2.0i install)

C:\PHPFS_MAD2> php afo_fuzzer.php

! Valid chars are: \x2E (.), \x2F (/), \x5C (\)
! Valid strings are all combinations of the above chars.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

VI) PHP arbitrary Remote File Upload testing

This tests move_uploaded_file() and similiar functions.

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

upload.php:

<?php

error_reporting(0);

$MaliciousFile = "evil.php";

if (isset($_GET['fuzzy'])) {
$FuzzyDestination = $MaliciousFile.$_GET['fuzzy'];
move_uploaded_file($_FILES['userfile']['tmp_name'], $FuzzyDestination);
printf($FuzzyDestination);
if (file_exists($MaliciousFile)) {
echo "SUCCESS";
unlink($MaliciousFile);
exit();
} else {
unlink($FuzzyDestination);
}
}

echo "FAIL";

?>

arfu_fuzzer.sh:

#!/bin/bash

touch "uploadtest.txt"
url="http://127.0.0.1/uploads/upload.php?fuzzy=";

for i in {1..255}; do
xi="%`printf %02x $i`"
for j in {0..255}; do
xj="%`printf %02x $j`"
for k in {0..255}; do
xk="%`printf %02x $k`"

ext="$xi$xj$xk"
[ $k -eq 0 ] && ext="$xi$xj"
[ $k -eq 0 ] && [ $j -eq 0 ] && ext="$xi"

response=`curl -kis -F "userfile=@xxxxxxxxxxxxxx;" $url$ext | grep
SUCCESS | wc -l`

if [ "$response" == "1" ]; then
echo "Found: $i $j $k -> ($ext)";
fi

[ $j -eq 0 ] && break

done
done
done


--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

VII) PHP arbitrary Remote File Upload results

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-pl0-Gentoo

PHPFS_MAD2 $ sh test_arfu.sh

FOUND: 47 0 0 -> (/)
FOUND: 47 46 0 -> (/.)

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.2.10-pl0-Gentoo + Suhosin-Patch 0.9.27

PHPFS_MAD2 $ sh test_arfu.sh

FOUND: 47 0 0 -> (/)
FOUND: 47 46 0 -> (/.)

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-

PHP 5.2.10-FreeBSD 7.3 + Suhosin-Patch 0.9.7

PHPFS_MAD2 $ sh test_arfu.sh

FOUND: 47 46 0 -> (/.)

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<-

PHP 5.3.0 Windows XP (WampServer 2.0i install)

PHPFS_MAD2 $ sh test_arfu.sh

[ All the combinations of (space), ., /, \ are valid ones. ]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

PHP 5.3.0 Windows Server 2008 (WampServer 2.0i install)

PHPFS_MAD2 $ sh test_arfu.sh

[ All the combinations of (space), ., /, \ are valid ones. ]

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

VIII) Conclusions

We found that it's possible to take advantage of filename normalization
routines in order to bypass common web application security routines,
detailed below:

- On GNU/Linux both (include|require)(_once)? functions will convert
"foo.php" followed by one or more sequences of \x2F (/) and \x2E (.)
back to "foo.php".
This does not work if Suhosin patch is applied.

- On GNU/Linux the fopen function will convert "foo.php" followed by one
or more sequences of \x2F (/) and \x2E (.) back to "foo.php".
This does not work if Suhosin patch is applied.

- On GNU/Linux move_uploaded_file function will convert "foo.php"
followed by one or more sequences of \x2F (/) and \x2E (.) back to
"foo.php".
This does work anyway *also* if Suhosin patch is applied.

- On FreeBSD the fopen function will convert "foo.php" followed by one
or more sequences of \x2F (/) and \x2E (.) back to "foo.php".
This does work anyway *also* if Suhosin patch is applied.
Suhosin is shipped in the the default install.

- On FreeBSD the move_uploaded_file function will convert "foo.php"
followed by one or more sequences of \x2F (/) and \x2E (.) back to
"foo.php".
This does work anyway *also* if Suhosin patch is applied.
Suhosin is shipped in the the default install.

- On Windows OS both (include|require)(_once)? functions will convert
"foo.php" followed by one or more of the chars \x20 ( ), \x22 ("),
\x2E (.), \x3C (<), \x3E (>) back to "foo.php".

- On Windows OS the fopen function will convert "foo.php" followed by
one or more of the chars \x2E (.), \x2F (/), \x5C (\) back to
"foo.php".

- On Windows OS move_uploaded_file function will convert "foo.php"
followed by one or more of the chars \x2E (.), \x2F (/), \x5C (\)
back to "foo.php".

We have observed that some particular strings like "foo.php./" or
"foo.php.\" force Windows to create a file called "foo.php.". It
seems that Windows' functions do not contemplate the existence of
a file with dots at the end (perhaps Windows hackers can better
comment on this).

All functions on that file will fail their attempt, so that it's not
possible to easily delete or rename that file (one has to do del *
or similiar).

IX) References

[1] http://www.ush.it/2009/02/08/php-filesystem-attack-vectors/
http://www.ush.it/team/ush/hack-phpfs/phpfs_mad.txt
[2] http://www.ush.it/team/ush/hack-sugarcrm_520e/adv.txt
[3] http://www.securiteam.com/securitynews/5FP0C0KJPQ.html
[4] http://ha.ckers.org/blog/20060914/php-vulnerable-to-null-byte-injection/

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

Credits (Out of band)

This article has been bought to you by the ush.it team. Giovanni
"evilaliv3" Pellerano, Antonio "s4tan" Parata and Francesco "ascii"
Ongaro are the ones who spent most hours on it with the precious help
of Alessandro "Jekil" Tanasi, Florin "Slippery" Iamandi and many other
friends.

Giovanni "evilaliv3" Pellerano
web site: http://www.ush.it/, http://www.evilaliv3.org/
mail: evilaliv3 AT ush DOT it

Antonio "s4tan" Parata
web site: http://www.ush.it/
mail: s4tan AT ush DOT it

Francesco "ascii" Ongaro
web site: http://www.ush.it/
mail: ascii AT ush DOT it

Alessandro "jekil" Tanasi
web site: http://www.tanasi.it/
mail: alessandro AT tanasi DOT it

--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--

Legal Notices

Copyright (c) 2009 Francesco "ascii" Ongaro

Permission is granted for the redistribution of this alert
electronically. It may not be edited in any way without mine express
written consent. If you wish to reprint the whole or any
part of this alert in any other medium other than electronically,
please email me for permission.

Disclaimer: The information in the article is believed to be accurate
at the time of publishing based on currently available information. Use
of the information constitutes acceptance for use in an AS IS condition.
There are no warranties with regard to this information. Neither the
author nor the publisher accepts any liability for any direct, indirect,
or consequential loss or damage arising from use of, or reliance on,
this information.



Relevant Pages

  • How exactly does mcrypt implement rijndael-256 and how to make compatible
    ... I try to program a Rijndael encryption in Windows which has to be ... In php I use the code below to encrypt with a 256 Bit Key and a 256 Bit ... My windows code has the same specs, ... I read somewhere on the internet that mcrypt added not ascii 0 but the ascii value of the number of the padded bytes - still with this modification of my code the result is different. ...
    (comp.lang.php)
  • Re: Parsing mbox files with Windows Php
    ... Php IMAP functions are well documented and easy to use. ... it appears that the Windows Php binary is unable to ... connect to an mbox file, so to make my job easy, I would have to ... (This second error is the one coming from the underlying c-client ...
    (comp.lang.php)
  • Re: PHP running exec() Windows program very slow in comparison to UNIX equivalent program
    ... So, by converting a VB6 DLL into a COM and calling the COM from PHP I am able to work around the speed limitations of swetest.exe, PHP, and Windows. ... I wrote a little program in VB5 that essentially does what this other compiled C Windows program does in just one of the loops that gets executed about 140 times. ... the other thing is how long it takes to to execute the program with those statements from a command prompt. ...
    (alt.php)
  • RE: phpBB Worm
    ... the getpwent function is not supported on Windows. ... it probably depends on the web server ... I looked at the decoded Perl script, ... was invoked by PHP, which should have the Web server's permissions, ...
    (Bugtraq)
  • Re: PHP / Sendmail / SMTP
    ... The problem is PHP! ... Then I am curious why anyone would need to use one on NIX? ... Windows is really only a single user system. ... at best its a one function server administered ...
    (comp.lang.php)