In this article I’ll explain what register_globals is; how to protect against exploits that take advantage of it; and why it should be turned off (if possible).

What is Register Globals?

register_globals is a setting/feature within PHP that was intended to ease development by making variables passed to the script (via a form, cookie, or session) automatically available as predefined variables within the global scope.

In the example below you can see how register_globals takes a variable from the page’s query string and creates the global variable $apple to represent it.

Page: index.php?apple=red

echo $apple; // 'red'

How Register Globals Can Be Exploited

At first glance one might say “That’s a great feature! Now I don’t have to go to the trouble of defining $apple and assigning it a value!

In my time as a web developer I’ve come across a few great pieces of advice.

  • Never trust the user.
  • Don’t assume.
  • If it can happen, it will happen.

Below is a excerpt from a Shopping Cart script; watch what happens when we assume

Page: cart.php?promo_code=12save

if($promo_code == '12save') {
  $discount= 0.10;
}

if(isset($discount)) {
  $price -= $price * $discount;
}

This might look secure to a new or even intermediate PHP developer…

I mean, come on… the only way to get the discount is by knowing the correct promo code, right?!

Wrong Let’s add another variable to the page’s query string and see what happens…

Page: cart.php?promo_code=doesNotMatter&discount=0.80

if($promo_code == '12save') {
  $discount= 0.10;
}

/**
 * Even though the promo code was incorrect this
 * IF statement will still evaluate TRUE and discount
 * the price.
 */
if(isset($discount)) {
  $price -= $price * $discount;
}

The reason this exploit works is because register_globals has defined $promo_code and $discount based on the page’s query string before any of the script’s code was executed.

So how can one combat this? Easy, don’t assume what the value of $discount will be, explicitly set it to 0 by default.

Page: cart.php?promo_code=12save

$discount = 0;
if($promo_code == '12save') {
  $discount = 0.10;
}

if(isset($discount) && ($discount > 0)) {
  $price -= $price * $discount;
}

Be aware that register_globals will allow keys => values to be inserted into existing array variables – this is often missed by developers of all skill levels. Array keys used later in a script must be defined with a default value to avoid exploitable code.

Below is an example of an attacker successfully forcing a “debug” mode, thus allowing him/her to see PHP errors.

Page: index.php?config[debug]=1

if(isset($config['debug']) && ($config['debug'] == true)) {
  error_reporting(E_ALL);
}

Why Register Globals Should Be Turned Off

Having register_globals enabled is like playing with fire. It’s a crutch used by new or intermediate PHP developers that don’t know any better – or in some cases are just too lazy to use proper coding practices.

Since PHP 4.2.0 register_globals has been disabled by default; and in PHP 5.3 it’s now considered deprecated. However, many shard hosting companies keep it enabled on their servers as they host older sites that were developed during a time of heavy register_globals reliance.

If you are starting a new project on a server where you have access to the php.ini file I would suggest you turn off register_globals.

If you don’t have access to the php.ini file; you’re on a shard server; or you have other sites on your server that break when you turn register_globals off you can try adding the following line of code to the root directory’s .htaccess file…

File: .htaccess

php_flag register_globals off

Summary

It’s important to realize that register_globals, by itself, is not a security flaw within PHP. If a developer is following proper coding practices there is no need to worry about register_globals being on or off.

Remember to always define your variables and array keys before you use them!

Tail Multiple Logs with Capistrano

Here’s a quick and easy way to tail log files from multiple hosts using Capistrano and the Foreman gem.Capistrano TaskFirst you’ll need to make sure the fore... Continue reading

Add Eloquent ORM Tab to PHP Debug Bar

Published on August 30, 2015

Doctrine 2 PDO Object

Published on August 17, 2015