<<< Date Index >>>     <<< Thread Index >>>

A word of caution on the use of suphp



Hi,

I've sent this "advisory" to the suphp author over 2 weeks ago and to
the suphp mailinglist more than 1 week ago.
Until now, I didn't get a reply so I'm assuming noone could care less.

This information is intended for people who plan to use suphp as a
replacement for the standard PHP module in apache.

greets,
-- Steven
A word of caution on the use of suphp
-------------------------------------

This is a lame advisory, but an advisory nonetheless.

Introduction
------------

At our site we use both mod_php and mod_suphp to make a transition from
mod_php (scripts run as user www-data) to mod_suphp (scripts run as the owner
of the script)
This temporary situation can be abused by outside attackers to gain access to
almost any user account on a webserver by abusing mod_php to gain www-data
privileges and abusing the www-data account to gain other privileges through 
suphp.

This "advisory" will show you how easy this can be accomplished...


How suphp works
---------------

Because suphp is setuid root, it is only natural that some security checks are
performed before executing a script with elevated privileges.

This is how suphp works:

 - The environment variable (env var) SCRIPT_FILENAME is checked to see if it
   exists.
 - The uid of the calling user is checked to see if it is allowed to run suphp
   (in our case, it needs to be www-data").
 - the filename of the script (SCRIPT_FILENAME) is checked to see if it
   resides in the document root (DOCUMENT_ROOT env var).
 - the filename is checked to see if the file exists.
 - the file permissions of the script are checked to make sure that it is
   readable by the owner, and not writable by either "group" or "other"
   (u+r,g-w,o-w).
 - the uid and gid to run the script as, are retrieved from env vars
   PHP_SU_USER and PHP_SU_GROUP.
 - The script is checked to make sure it is owned by user with uid =
   PHP_SU_USER and group with gid = PHP_SU_GROUP.
 - PHP_SU_USER and PHP_SU_GROUP are checked to make sure they are larger than
   some number (in our case 100, which rules out executing things as e.g.
   root).
 - If the filename is a symbolic link, it is dereferenced and checked again
   for the above conditions.
 - A message is logged.
 - uid/gid are set
 - a new environment is created
 - /usr/bin/php is run and the script is executed.

It is clear that we don't need to do the impossible to foil suphp:
 - gain www-data privileges
 - put a php script in a file owned by some user and only writable by that
   user.
 - set some environment variables
 - execute suphp
 
Step 1: gaining www-data privileges
-----------------------------------

Since most scripts are running as user www-data, it's not a big challenge to
gain www-data privileges. Even for an outside attacker. We used to find (failed)
backdoors at our site on a regular basis, proving that the sites and forums of
our users aren't safe at all.

Step 2: uploading code for suphp to execute
-------------------------------------------

Injecting php-code into a file owned by another user and not writable by
anyone but that user might look challenging... and it is.
I have spent a while pondering about this issue, thinking it would be very
tricky...
However, the answer is more simple than it thought. Usually, every user has a
mailbox which is owned by that user, and not writable by anyone else.
So... we just mail them a php-script and execute their mailbox!

(This part is totally optional however. Instead of uploading code and
executing that, you might just simply want to read sensitive files like
private ssh keys)

Step 3: creating a nice environment
-----------------------------------

This needs to be done as user www-data:

export SCRIPT_FILENAME=/some/path/to/Mailbox
export DOCUMENT_ROOT=/
export PHP_SU_USER=theuser
export PHP_SU_GROUP=hisgroup

Step 4: executing the uploaded code
-----------------------------------

Suphp doesn't take any arguments and gets everything from environment, so :

/usr/bin/suphp


Solution
--------

The most obvious solution would be to not use both mod_php and mod_suphp at the 
same time.
I'm not aware of any other solutions at this time.

greets,
-- Steven

Steven Van Acker
deepstar@xxxxxxxxxxx

[ Need a challenge ?                  ]
[    Visit http://www.pulltheplug.com ]