How to painlessly defuse the CGI exploit.

From: Date: Sat, 11 May 2002 02:00:36 +0000
Subject: How to painlessly defuse the CGI exploit.
References: 1  Groups: php.cvs 
Request: Send a blank email to php-cvs+get-11813@lists.php.net to get a copy of this message
Let's summarize. Placing an interpreter (PHP, Perl, AWK, sh, or even "cat") within the web tree is a very bad idea. The recommended configuration for PHP CGI with Apache places the PHP executable within the web tree. Apparently with Apache there is no way(?) to configure the PHP interpreter outside the web tree. To prevent the classic CGI exploit made possible by the recommended Apache configuration, an Apache specific test was added to PHP. The test to match the problem could have been: IF (server is Apache) AND (REQUEST_STATUS not set) THEN (emit warning) This is an Apache-specific hack (checking REQUEST_STATUS) to address an Apache-specific problem caused by the recommended configuration. Adding a bit of code specific to Apache is not generally a bad idea given that about half the web servers in the world are Apache :). The actual test screws up IIS (and other non-Apache servers): IF (REQUEST_STATUS not set) THEN (emit warning) Unfortunately this is causing a lot of confusion. Google lists about 250-odd references to the warning - not bad for a bit of code only out a few months :). How can we solve the problem with less grief? Simple - don't place the PHP executable in the web tree! Place a "php.bat" in the Apache cgi-bin directory containing commands: @echo off c:\php\php.exe The Apache configuration then becomes: AddType application/x-httpd-php .php .phtml Action application/x-httpd-php "/cgi-bin/php.bat" Note the absence of the ScriptAlias statement - no PHP in the web tree! To see why this works modify "php.bat" slightly: @echo off echo. set echo. echo arg1 = %1 echo arg2 = %2 echo arg3 = %3 echo. echo ... PHP output echo. c:\php\php.exe This gets you a blank line (to start body), the environment, the first three command line arguments, and finally the PHP output. Lets try the exploit: http://gerald:3000/cgi-bin/php.bat?/small.txt Yields the response: ---------------------------------------------- COMSPEC=C:\WINDOWS\COMMAND.COM DOCUMENT_ROOT=c:/program files/apache group/apache/htdocs HTTP_ACCEPT=*/* HTTP_ACCEPT_ENCODING=gzip, deflate HTTP_ACCEPT_LANGUAGE=en-us HTTP_CONNECTION=Keep-Alive HTTP_HOST=gerald:3000 HTTP_USER_AGENT=Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461) PATH=C:\PERL\BIN\;C:\WINDOWS;C:\WINDOWS\COMMAND;C:\BIN;C:\PERL\BIN;C:\CYGWIN\BIN;C:\PROGRA~1\MICROS~1\COMMON\MSDEV98\BIN;C:\PROGRA~1 \MICROS~1\VC98\BIN;C:\PROGRA~1\MICROS~1\COMMON\TOOLS\WIN95;C:\PROGRA~1\MICROS~1\COMMON\TOOLS;\SYSTEM;;\COMMAND;C:\ADABAS\BIN;C:\ADAB AS\PGM;C:\PROGRAM FILES\MTS REMOTE_ADDR=192.168.1.102 REMOTE_PORT=1144 SCRIPT_FILENAME=c:/program files/apache group/apache/cgi-bin/php.bat SERVER_ADDR=192.168.1.102 SERVER_ADMIN=admin@zotez.com SERVER_NAME=gerald.zotez.com SERVER_PORT=3000 SERVER_SIGNATURE=<ADDRESS>Apache/1.3.24 Server at gerald.zotez.com Port 3000</ADDRESS> SERVER_SOFTWARE=Apache/1.3.24 (Win32) WINDIR=C:\WINDOWS GATEWAY_INTERFACE=CGI/1.1 SERVER_PROTOCOL=HTTP/1.1 REQUEST_METHOD=GET QUERY_STRING=/small.txt REQUEST_URI=/cgi-bin/php.bat?/small.txt SCRIPT_NAME=/cgi-bin/php.bat arg1 = "/small.txt" arg2 = arg3 = ... PHP output X-Powered-By: PHP/4.2.0 Content-type: text/html No input file specified. ---------------------------------------------- For reference try an acceptable request: http://gerald:3000/php/env.php Yields the response: ---------------------------------------------- COMSPEC=C:\WINDOWS\COMMAND.COM DOCUMENT_ROOT=c:/program files/apache group/apache/htdocs HTTP_ACCEPT=*/* HTTP_ACCEPT_ENCODING=gzip, deflate HTTP_ACCEPT_LANGUAGE=en-us HTTP_CONNECTION=Keep-Alive HTTP_HOST=gerald:3000 HTTP_REFERER=http://gerald:3000/php/ HTTP_USER_AGENT=Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461) PATH=C:\PERL\BIN\;C:\WINDOWS;C:\WINDOWS\COMMAND;C:\BIN;C:\PERL\BIN;C:\CYGWIN\BIN;C:\PROGRA~1\MICROS~1\COMMON\MSDEV98\BIN;C:\PROGRA~1 \MICROS~1\VC98\BIN;C:\PROGRA~1\MICROS~1\COMMON\TOOLS\WIN95;C:\PROGRA~1\MICROS~1\COMMON\TOOLS;\SYSTEM;;\COMMAND;C:\ADABAS\BIN;C:\ADAB AS\PGM;C:\PROGRAM FILES\MTS REDIRECT_STATUS=200 REDIRECT_URL=/php/env.php REMOTE_ADDR=192.168.1.102 REMOTE_PORT=1144 SCRIPT_FILENAME=c:/program files/apache group/apache/cgi-bin/php.bat SERVER_ADDR=192.168.1.102 SERVER_ADMIN=admin@zotez.com SERVER_NAME=gerald.zotez.com SERVER_PORT=3000 SERVER_SIGNATURE=<ADDRESS>Apache/1.3.24 Server at gerald.zotez.com Port 3000</ADDRESS> SERVER_SOFTWARE=Apache/1.3.24 (Win32) WINDIR=C:\WINDOWS GATEWAY_INTERFACE=CGI/1.1 SERVER_PROTOCOL=HTTP/1.1 REQUEST_METHOD=GET QUERY_STRING= REQUEST_URI=/php/env.php SCRIPT_NAME=/cgi-bin/php.bat PATH_INFO=/php/env.php PATH_TRANSLATED=c:\inetpub\wwwroot\php\env.php arg1 = arg2 = arg3 = ... PHP output X-Powered-By: PHP/4.2.0 Content-type: text/html [snipped valid output from PHP script] ---------------------------------------------- Note two interesting differences between the two requests. The exploit passes one command line argument, and does *not* set either PATH_INFO or PATH_TRANSLATED. The valid request passes *no* command line arguments, and *does* set PATH_INFO or PATH_TRANSLATED. Since the cgi-bin/php.bat ignores the command line argument, the exploit is defeated. (BTW, I didn't invent this solution - it came from a Perl FAQ :). -- Preston L. Bannister http://members.cox.net/preston.bannister/ pbannister on Yahoo Messenger

« previous php.cvs (#11813) next »