Some facts about the PHPList vulnerability and the phpbb.com hack

A few days ago phpbb.com was hacked through a super-globals-overwrite vulnerability in PHPList that was used by an attacker for a local file inclusion exploit. Details about the whole attack, written down by someone who claims to be the attacker, can be read here. From the explanation it seems that the PHP installation on phpbb.com was more or less a default one that was not hardened against attacks at all, but I will get into this later.

First I want to shed some light on the super-globals-overwrite vulnerability in PHPList that was wrongly attributed a local file inclusion vulnerability in so many places (including the PHPList announcement). Responsible for the attack is the following code in admin/index.php:

if (!ini_get("register_globals")
          || ini_get("register_globals") == "off") {
   # fix register globals, for now, should be phased out gradually
   # sure, this gets around the entire reason that register globals
   # should be off, but going through three years of code takes a long time....
   foreach ($_REQUEST as $key => $val) {
      $$key = $val;
   }
}
...
if (isset($_SERVER["ConfigFile"]) && is_file($_SERVER["ConfigFile"])) {
   print '<!-- using '.$_SERVER["ConfigFile"].'-->'."\n";
   include $_SERVER["ConfigFile"];
}

This code will detect if register_globals is turned off (which is the default since PHP 4.2) and in that case emulate register_globals by globalising everything within the _REQUEST array. Code similar to this is used by many projects to emulate register_globals=on. Usually this is done as a quick hack to make software work when register_globals=off. The comment proves that this is also the case for PHPList.

The problem here is that the foreach loop above does not contain any kind of sanity check which allows attackers to overwrite all the super-global-variables (like GLOBALS, _SERVER, _ENV, …) by supplying new values for them through either the URL, the POST data or through the COOKIE. For the code above this also means an attacker can also overwrite the value of $_SERVER[‘ConfigFile’] from the outside. This gives the attacker full control over an include statement, which allows him to include arbitrary files.

Unfortunately the original exploit author, the PHPList team and many other people still believe that using is_file() or file_exists() around the file to include is enough to ensure that it is a local file. Therefore the original exploit and also the PHPList security announcement wrongly assume this is a local file inclusion problem. In reality however is_file() and file_exists() also work on PHP’s URL wrappers if the wrapper implements the stat() call. PHP’s HTTP(S)/DATA/PHP://INPUT URL wrappers do not support this. But since PHP 5.0 the FTP URL wrapper does support this and therefore _SERVER[‘ConfigFile’] allows a normal remote file inclusion through the FTP protocol.

More importantly neither the original exploit writer, nor the PHPList team or anyone else reporting about it have realised that the problem is bigger than _SERVER[‘ConfigFile’] and therefore it is not suprinsing that the fix by PHPList is just a hack that fixes a single exploit but not the problem.

if (isset($_REQUEST['_SERVER'])) { exit; }

This code does obviously protect the _SERVER variables only. All the other super-global-variables are still unprotected. Because of this it is still possible to perform LFI/RFI and SQL-Injection attacks against the latest PHPList release by just overwriting other super-globals.

Protection

This attack was only possible because the PHP installation of phpbb.com was not configured securely. Multiple applications on the same server should be isolated from each other. Activating open_basedir*, which is a simple PHP configuration option, would have been good enough to stop PHPList from including avatar files uploaded to the PHPBB installation. Additionally disabling allow_url_fopen/allow_url_include in combination with the is_file() check would have stopped a possible remote file inclusion attack. However SQL-Injection attacks would through the super-globals-overwrite would still be possible.

On the other hand there is a simple way to protect a server against super-globals-overwrite vulnerabilities: Just install the Suhosin PHP security extension. It will detect, log and stop this kind of super-globals-overwrite. If you ask me any admin installing a vanilla PHP without Suhosin patch and extension is careless anyway.

Attention

*open_basedir – don’t get me wrong – open_basedir is not secure when it comes to protect a server against a malicious users/PHP scripts, but it makes exploiting local file inclusion attacks a lot harder.