How Does an Evil Script Execute?
From what you've seen so far, it's probably hard to see how anyone could get an evil script to execute, but it turns out that if you use a common programming trick, you're wide open to attack. That programming trick is "parameterized" or "variable" includes. The include
keyword might make you think of the #include
directive within C or C++, which is a compiler directive that always appears at the top of the program, but the PHP include
command isn't like that at all. It's actually very flexible, and can be used in conjunction with variables.
For example, you can write perfectly valid code such as:
People use such code to include or exclude scripts depending on other program conditions. Now, if your program has many scripts that can be included, but you only want to include one at a time, you might use an HTTP GET
parameter to specify which script you want to use. For example, if you have 10 scripts named inc1.php
, all of which contain an addOne
function, but do different things, you could write something like:
Then, in your page code you would have something like the following code.
echo("The result is " . $out);
The preceding code sets the value of the $inc
variable to the value of the GET
parameter, causing the script to include (and execute) the inc1.php
file. Because PHP will load scripts from an external URL, someone could very easily inject an evil script to run on the server simply by typing the following URL into their browser.
How Can I Protect My Code
First, if your Web site uses any applications that are written in PHP, such as phpBB
, you need to make sure that you are using a version that is "fixed" to disallow this type of injection. In the case of phpBB
, the vulnerable versions are those prior to version 2.0.11. For other applications, check with the developers or vendors of the application.
To protect your own codebase, you should consider the following coding tips.
- If you don't want to include or require files from an external URL, turn off the URL_fopen_wrappers option.
- Always give your include files the .php extension. Some programmers like to give them an .inc extension instead, but most Web servers will not execute .inc files, they return the contents instead. Therefore, any malicious users who knew the URL of your include file and typed it into their browser's address bar would get the full source code of the include file. As people commonly store such things as database login passwords in include files, you could have a bit of a problem!
- Never directly include a parameterized page. Check it against a list of known pages first. For example, you could change the previous code fragment to something safer, such as:
$pages = array('inc1.php','inc2.php','inc3.php');
if( in_array($inc, $pages) )
- Be very careful using the eval() function. Eval evaluates a string as if it were code, and outputs the results to the browser. If you send the value of a parameter passed to a page directly to eval(), a script injection could occur. Don't ever do that! Check parameter values first.
- Make sure to set the REGISTER_GLOBALS setting in your php.ini file to OFF. When this is set to ON you have a risk of someone passing the value of a variable into your page by naming that variable in the browser's address bar. For example, suppose you have code in your pages such as:
If you have carelessly forgotten to define $incfile¸ and REGISTER_GLOBALS is set to ON, then someone could call your page like this:
- Never pass parameters directly from a URL to a SQL query if you are using data. Always sanitize the parameters first, or use the parameters to build a query. For example, don't write code like this:
Instead, define the SQL code on the server. You can still control it from the URL by passing a defined parameter, such as:
When your code receives this URL, you can do something like the following:
$sql="Select * from accounts";
$sql="Select * from whatever";
Overall, this exploit provides a clear example of how subtle a security hole can be. When a good feature of a language such as PHP is misused, and exposed to further misuse through poor input parameter sanitation, security problems can arise. In this case, the root cause isn't a bug in the language or any problem with the language per se; instead, it's related to the way people use the language. The recent Santy/PHPInclude worms are able to exploit mistakes such as those described in this article to propagate themselves and destroy Web sites. They find vulnerable pages using simple Google (and other search engine) searches and propagate similarly. By cleaning up your pages to use the techniques and background discussed in this article, you can now go forth and be sure that your Web site will not suffer the same fate, and will be protected from this hole. However, you need to be vigilant, to understand your code and anticipate how the features of the platform that you are using could be used differently so you can protect yourself, your Web site, and your data from attacks.