Ïðèãëàøàåì ïîñåòèòü
ßçûêîâ (yazykov.lit-info.ru)

Section 6.1.  Traversing the Filesystem

Previous
Table of Contents
Next

6.1. Traversing the Filesystem

Whenever you use a file in any way, you must indicate the filename at some point. In many cases, the filename is given as an argument to fopen( ), and other functions use the handle that it returns:

    <?php

    $handle = fopen('/path/to/myfile.txt', 'r');

    ?>

A vulnerability exists when you use tainted data as part of the filename:

    <?php

    $handle = fopen("/path/to/{$_GET['filename']}.txt", 'r');

    ?>

Because the leading and trailing parts of the full path and filename cannot be manipulated by an attacker in this example, the exploit possibilities are somewhat limited. However, keep in mind that some attacks use a NULL (%00 when passed in the query string) to terminate a string, avoiding any filename extension limitations. In this case, the most dangerous exploit is one in which the attacker traverses the filesystem by using multiple instances of the string ../ to move up the directory tree. For example, imagine a value of filename being passed as follows:

    http://example.org/file.php?filename=../../../../../another/path/to/file

Section 6.1.  Traversing the Filesystem

As is the case with many attacks, using tainted data in the construction of a string provides an attacker with an opportunity to change the string, and this can cause your application to behave unexpectedly. If you begin a habit of using only filtered data to create any dynamic string, you can begin to protect yourself from many types of vulnerabilities, including those with which you might not be familiar.


Because the leading static portion of the filename used in the original fopen( ) call is /path/to/, this attack traverses up more than is necessary. The attacker does not have the benefit of observing the source code before launching the attack, so the strategy is typically to repeat the string ../ more times than is expected to be necessary. Using too many does not disrupt the attack, so it is not necessary that the attacker guess the correct depth.

This particular attack alters the intended behavior of the fopen( ) call, reducing it to the following:

    <?php

    $handle = fopen('/another/path/to/file.txt', 'r');

    ?>

Upon noticing this problem, or after being the victim of an attack, many developers make the mistake of trying to correct potentially malicious data, sometimes without even inspecting it first. As described in Chapter 1, the best approach is to treat filtering as an inspection process and to force the user to abide by your rules. For example, if every valid filename consists of only alphabetic characters, the following code can enforce this restriction:

    <?php

    $clean = array();

    if (ctype_alpha($_GET['filename']))
    {
      $clean['filename'] = $_GET['filename'];
    }
    else
    {
      /* ... */
    }

    $handle = fopen("/path/to/{$clean['filename']}.txt", 'r');

    ?>

Section 6.1.  Traversing the Filesystem

It is not necessary to escape the filename in any way because this data is being used only in a PHP functionit is not being sent to a remote system.


The basename( ) function can be useful for inspecting a string to check for unwanted path information:

    <?php

    $clean = array();

    if (basename($_GET['filename']) == $_GET['filename'])
    {
      $clean['filename'] = $_GET['filename'];
    }
    else
    {
      /* ... */
    }

    $handle = fopen("/path/to/{$clean['filename']}.txt", 'r');

    ?>

This approach is slightly less secure than enforcing that the filename consists of only alphabetic characters, but you may not be able to be quite as strict. A good Defense in Depth approach is to combine both methods, especially if you use a regular expression to inspect the data for valid characters (instead of a function like ctype_alpha( )).

A more dangerous vulnerability exists when the entire trailing part of the filename is tainted:

    <?php

    $handle = fopen("/path/to/{$_GET['filename']}", 'r');

    ?>

The increased flexibility given to an attacker increases the magnitude of the vulnerability. In this particular case, an attacker can manipulate the filename to refer to any file on the filesystem regardless of the path or file extension, because the file extension is provided as part of $_GET['filename']. As long as the web server has read access to the file, the handle will be to a file chosen by the attacker.

This type of vulnerability becomes even more substantial if the leading part of the path is tainted, and this is the topic of the next section.


Previous
Table of Contents
Next