Webserver Security (Part II)

This second part of our two-part series on webserver security explores the problem of keeping private data in publicly accessible areas of you server and keeping data from untrustworthy sources from entering your system.

The second large class of errors we are going to address in this article deals with private data in public directories on a server. Many webspace providers offer just that: Web-Space. Their hosting solutions map the root of your ftp directory onto the root of your server. That is, the server directory “/home/www/servers/www.customer.com/” is visible for the customer via ftp as “/”. It is also readable for everyone through the URL http://www.customer.com/”. Should the customers web application have the need to keep some files private and inaccessible from the web, there is no such location. A file stored via ftp as “/password” will be available through the URL “http://www.customer.com/password”.

Many webshops write order logs or debugging output into one or multiple logfiles or have configuration files with passwords and article data. If this data is being stored below the document root, it will have an URL and is by default accessible via the web. All an attacker has to do is to guess the filenames of these files. This is quite easy if you know the defaults used by the 20 most popular shopping solutions and know how to identify the software used.

This problem does no occur with hosting solutions which were designed to provide private data storage as well as public page directories. In such solutions the ftp root directory “/” is mapped onto “/home/www/servers/www.customer.com/”, but the servers document root is located one level futher down at “/home/www/servers/www.customer.com/pages”, accessible via ftp as “/pages”. In such a setup the customer can create additional directories above and in parallel to the document root and store sensitive data there. Because these directories are available through ftp, but not through http, they cannot be accessed via the web.

On system where such a root separation scheme is not in effect it is possible to work around the problem by creating a storage directory such as “/shop” below document root and creating a .htaccess file in it which denies all http access (requires Apache webserver):

$ cat /shop/.htaccess
order deny, allow
deny from all


Files can be transferred from this directory only by ftp, because ftp will ignore .htaccess files. This approach is slightly more risky than a directory outside document root, though, because this kind of protection will fail if the server administrator does accidentally turn off the needed “AllowOverride Limit” privilege for the directory in the server master configuration.

A variant of this problem exists if multiple customers are hosted on a single machine and one customer can trick the machine into accessing pathes outside the customers directory hierarchy, that is to access any file outside of the tree “/home/www/servers/www.customer.com”. Often this is possible with symbolic links or hard links to files stored outside the virtual webserver of the customer. Targets of interest are include files and private keys of other customers, to get at their database passwords or other secret information which has to be stored in such files in clear in order to for their application to work. Other possible targets are their order logs or other useable information stored in nonpublic directories.

This problem can be partly reduced by chroot()ing as many services as possible, for example by using the sbox replacement for the Apache suexec program to have all CGI running in an isolated environment and under the user id of the customer instead of the user id of the web server. Also, many installations do run a ftp server such as wu-ftpd, which does all file transfers chrooted, again to protect well behaved customers from being spied on by others.

A rogue customer could still use CGI programs to create a symbolic link into the storage area of another customer and use the web server itself to look at foreign files, since in a hosted environment the web server cannot be easily running chrooted and under the user id of the customer for which it serves the request. Administrators should instruct their web server and all other file transfer programs not to follow symbolic links. In Apache, this can be done by disabling the “FollowSymLinks” option at the top level and not turning it on at lower levels, for example using a configuration section like the following.

<directory />
Options -FollowSymLinks
</directory>
{mospagebreak title=The server trusts data from untrustworthy sources} The third class of common problems are poorly written cgi programs or PHP scripts which put trust into parameters from untrustworthy sources and are using CGI parameters without sanity checking.

A web application generally consists of components located inside your firewall. These components can be considered trustworthy, because they are controlled by the local administrator. Such components may be local scripts, the database, the web server and local data files.

Additional components of any web application are located outside of the firewall and cannot be trusted. Mainly this is the users browser, if he uses any and is not typing his web request directly into a telnet session to better control which data he feeds our application in order to exploit any security problems we may have introduced into our code.

The firewall is the demarcation line between the trustworthy intranetwork and the Evil Internet. It is a trust boundary.

All data from outside the trust boundary must not enter a web application without checking. This includes all parameters passed to the CGI script such as all GET, POST and COOKIE variables, the HTTP_REFERER, HTTP_USER_AGENT and all other HTTP_* variables as well as all other variables generated remotely. Each and every such variable must be checked for validity before it can be used by the CGI script. That check will insure that the value of that particular variable is well within the expected domain.

For example it is a common, but wrong practice that some scripts will accept form input only if the HTTP_REFERER of the request is correct. Using such a mechanism the script tries in vain to protect itself against faked requests. Of course it is trivial for a potential attacker to learn the required HTTP_REFERER and fake it along with the rest of a request – the protection is useless. Such a script is doing the wrong thing: The HTTP_REFERER is not the value that is required to be correct in such calls – all other values are.


Faking web requests

The following simple PHP program will echo the value of the CGI parameter b. It will also show the HTTP_REFERER with which the script was called.

kris@valiant:~/www < cat test.php
<?php
print “The value of b is $bn”;
print “The value of HTTP_REFERER is $HTTP_REFERERn”;
?>


Using a simple telnet connect to port 80 we are able to feed this script with arbitrary values for parameter b as well as with any desired value for the HTTP_REFERER. We send the following lines to the server:

GET /~kris/test.php?b=this+is+a+test HTTP/1.0
Host: valiant.koehntopp.de
Referer: http://www.attacker.com/die_sucker_die.html


Here is the complete session transcript:

kris@valiant:~/www < telnet valiant 80
Trying 193.102.57.3…
Connected to valiant.koehntopp.de.
Escape character is ‘^]’.
GET /~kris/test.php?b=this+is+a+test HTTP/1.0
Host: valiant.koehntopp.de
Referer: http://www.attacker.com/die_sucker_die.html

HTTP/1.1 200 OK
Date: Sat, 08 Apr 2000 06:44:02 GMT
Server: Apache/1.3.9 (Unix) (SuSE/Linux) PHP/4.0RC2-dev mod_ssl/2.4.7 OpenSSL/0.9.4
X-Powered-By: PHP/4.0RC2-dev
Connection: close
Content-Type: text/html

The value of b is this is a test
The value of HTTP_REFERER is http://www.attacker.com/die_sucker_die.html
Connection closed by foreign host.


Note that we have to enter values for b in urlencoded form. To urlencode a string, use a simple PHP program such as

kris@valiant:~/www < cat urlencode.php
#! /home/kris/bin/php -q
<?php
print urlencode($argv[1]).”n”;
?>
kris@valiant:~/www < ./urlencode.php “this is a test”
this+is+a+test


It is only slightly more difficult to fake HTTP POST requests: The request now has to include a valid Content-Type header as well as the correct content length in bytes. Here is how it is done:

kris@valiant:~/www < telnet valiant 80
Trying 193.102.57.3…
Connected to valiant.koehntopp.de.
Escape character is ‘^]’.
POST /~kris/test.php HTTP/1.0
Host: valiant.koehntopp.de
Referer: http://www.attacker.com/die_sucker_die.html
Content-Type: application/x-www-form-urlencoded
Content-Length: 16

b=this+is+a+test
HTTP/1.1 200 OK
Date: Sat, 08 Apr 2000 06:55:11 GMT
Server: Apache/1.3.9 (Unix) (SuSE/Linux) PHP/4.0RC2-dev
mod_ssl/2.4.7 OpenSSL/0.9.4
X-Powered-By: PHP/4.0RC2-dev
Connection: close
Content-Type: text/html

The value of b is this is a test
The value of HTTP_REFERER is
http://www.attacker.com/die_sucker_die.html
Connection closed by foreign host.



Another common suicide technique is the passing of internal application state from page to page via <INPUT TYPE=”HIDDEN”> tags. Keeping internal application state outside the trust boundary is like ripping the heart out of your application and presenting it on a silver tablet to any attacker. Anyone who cares to destroy such a insanely insecure installation can easily manipulate the application state and produce any desired effect. Application state should be kept on the server using sessions and session variables. It must never cross the trust boundary. All web application development platforms such mechanisms. For example in PHP3, PHPLIB is used to keep session data, PHP4 uses the session_*() calls, ASP has the Session object and Cold Fusion offers several different flavors of session variables.

An application must not store any data from outside the trust boundary directly inside session variables: These are trusted variables and may not hold untrusted data. Usually data from the outside, such as form variables, are passed to validator functions. Only if the validator functions indicate that the content passed from the form is safe, values are copied from the form variables into session variables. Your application should do such checks in a single central location. All the rest of your application should never touch form variables, but always work with the checked and sanitized session data.

Part of the job description of a webmaster is checking all installations for errors belonging into one of these error classes and change the applications in case they show any of the symptoms discussed here. Stolen credit card data or even servers which have been broken into and have been used as an attack base are not just embarassing: Such installations are negligently insecure and you can expect to be sued for damages or even aiding a computer breakin.

For the layman on an Internet shopping afternoon all of this is not helpful: To validate the security of a server not only technical expertise is required, but also access to the server itself. Only an independent full scale audit and a technical seal of approval renewed each year or after all major technical changes will improve the current situation. If insurance and credit card companies will offer discount to installations with such a seal of approval, this will be a huge incentive for site operators to get themselves audited.

Links

http://www.koehntopp.de/kris/artikel/webtune/
“Webserver verstehen und tunen” (german language)

http://www.koehntopp.de/php/
“de.comp.lang.php – H‰ufig gestellte Fragen” (german language)

http://www.insecure.org/nmap/
“NMAP Port Scanner” (english language)

http://ethereal.zing.org/
“Ethereal Network Monitor” (english language)

http://www.marko.net/cheops
“Ceops Network Mapper” (english language)

http://freshmeat.net/appindex/1998/04/06/891857252.html
“lsof – list open files” (english language)

“TCP/IP Illustrated, Volume 1: The Protocols” (english language)
W. Richard Stevens
Addison-Wesley

“Hacking Exposed – Network Security Secrets & Solutions” (english language)
McClure, Scambray and Kurtz
Osborne

“Maximum Linux Security” (english language)
Anonymous
Sams

Google+ Comments

Google+ Comments