Question

I have inherited a web server filled with code that requires register_globals to be on. Most of it is custom code written by random people who have come and gone over the years. I have fixed the majority of it in scripts that I know about, but my problem is with finding the ones I don't know about.

I am considering writing an application to scan through every directory on the web server to identify PHP scripts that require register_globals. Is there a good strategy for doing this?

One method I have considered involves somehow forcing PHP to report all errors, executing scripts, and checking for undefined variable notices. I could build an application that reads the STDERR stream for this.

Are there any better methods you can think of?

Was it helpful?

Solution

Most IDEs will show you undefined variables, PHPStorm does for example. You can let it scan all your source files and you will be notified about undefined variables in all your code, whiteout actually executing it.

This is probably the most simply and painless variant. Alternatively you could obviously write your own script utilizing the Tokenizer and identify all T_VARIABLEs, which are not previously initialized using a T_VARIABLE '=' expr construct. But this will be more error prone. Using the IDE will probably give you better results with less effort.

OTHER TIPS

Assuming single files are always using register_globals being on or off, you could create a list of all form element names which are submitted to a script and then check this script if it's using $fieldname without containing $_REQUEST['fieldname'] (or the $_POST, $_GET arrays).

Your "check for notices" method would be ok if you can guarantee a very high code coverage while doing those checks (to ensure you didn't miss anything - the uncovered parts then have to be checked manually).

While examining your logs for symptoms of scripts written expecting global vars can be helpful, reading through the code is the only way to really do this. If you wanted to automate this, you would need to build or rely on a PHP interpreter; otherwise you're destined to miss stuff nested inside of conditions, potential evals, etc.

There is a way to locate usages of register globals that are strings in running code. You can create the following script and use the PHP auto_prepend_file ini options to prepend it to your existing code.

<?php

class revealGlobalsUsage {

    public $globalName;
    public $globalVal;

    public function __construct($name, $val)
    {
        $this->globalName = $name;
        $this->globalVal = $val;
    }

    public function __toString()
    {
        $backtrace = debug_backtrace();

        // log backtrace here...

        return $this->globalVal;
    }
}

// overwrite globals that have been set from GET and POST requests
foreach ($_REQUEST as $name => $val) {
    // Strings that are cast to integers will fail as there 
    // is no __toString equivalent for integers/bool/float etc.
    if (is_string($val) && !is_numeric($val)) {
        $GLOBALS[$name] = new revealGlobalsUsage($name, $val);
    }

    // You can log all GET/POST requests here...
}

For integers etc. you would need to patch your PHP: https://gist.github.com/ircmaxell/1966809

I ran into this problem myself in an enormous codebase with thousands of files. Inspired by the solution posted by @sschueller I have tested this auto_prepend_file code which logs occurrences for investigation. This method should also be used in conjunction with parsing/tokenizing to catch all occurrences.

<?php

$vars = get_defined_vars();

foreach ($vars as $var => $value) {
    if (in_array($var, array('$_SERVER', '$_REQUEST', '$_GET', '$_POST', '$_COOKIE', '$_SESSION', '$_FILES', '$_ENV'))) {
        // only examine the local symbols, not superglobals
        continue;
    }

    if (array_key_exists($var, $_REQUEST) && $value == $_REQUEST[$var]) {
        error_log(sprintf("register_globals reliance detected in %s for variable %s=%s", $_SERVER['SCRIPT_FILENAME'], $var, $value), 3, "/var/tmp/register_globals.log");
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top