Home

Your premium source for custom modification services for phpBB

  logo

HomeForumsBlogMOD ManagerFAQSearchRegisterLogin

Comments January 29, 2007

The dangers of PHP_SELF

Filed under: MOD Writing, phpBB — Dave Rathbun @ 7:15 am CommentsComments (5) 

I recently had a MOD denied for security reasons. I was using $HTTP_SERVER_VARS['PHP_SELF'] as a shortcut. Turns out that like many shortcuts it can lead to unintended results.

Here’s the official definition of PHP_SELF from www.php.net:

The filename of the currently executing script, relative to the document root. For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar would be /test.php/foo.bar. The __FILE__ constant contains the full path and filename of the current (i.e. included) file.

If PHP is running as a command-line processor this variable contains the script name since PHP 4.3.0. Previously it was not available.

Sounds useful enough, right? You might want to write a generic form processor, and the ACTION tag for the form should always point back to the calling routine. Using PHP_SELF would seem to be an effective way to do that. Otherwise you have to write code to pass in the calling routine’s name, and that means custom code for each and every parent page that might call this code. In my case I was using this in the Page Permissions MOD.

A brief background, if you’re not familiar with this MOD. Many folks want to have different security settings on different pages from their phpBB boards… most commonly requested is to keep guests out of the member list. In order to do this you can easily edit the memberlist code, but then what about the next page? and the next one after that? If you have to edit every single page that you want to protect, that’s painful. :-) So the Page Permissions MOD tied into the session handler. Each time you load a page from phpBB, the sesion is checked. During that process, I also check to see which page you are trying to view, and I want to do that without having to alter the source page. So, PHP_SELF was used.

Let’s continue with the memberlist.php idea, as it’s fairly popular. I want to keep guests out of the member listing, so I install the Page Permissions MOD and set the memberlist access restriction to Registered. As you can see here in this screenshot:

That’s a screenshot of an actual Page Permissions implementation. See the line for memberlist? It says “Registered” access. So that means that if someone invokes memberlist.php the code first checks PHP_SELF to obtain the page being requested, then queries the permissions settings to see what access is required, then verifies that the user has that access. It’s all good. 8)

And it’s all very flawed. :shock:

You see, PHP_SELF returns more information than you want it to. As stated above, it returns the path of the script being executed. So if I do this:

http://www.example.com/memberlist.php

I get this:

PHP_SELF is memberlist.php

That looks perfect. If the memberlist is in a subdirectory (as most phpBB installations are) it looks like this:

http://www.example.com/phpBB2/memberlist.php

PHP_SELF is /phpBB2/memberlist.php

Now this is easily handled with the pathinfo() function. If you apply the pathinfo() function to $HTTP_SERVER_VARS['PHP_SELF'] (or use $_SERVER['PHP_SELF'] if you don’t require the long array names like phpBB2 does) then it returns the following components:

dirname is /phpBB2
basename is memberlist.php
extension is php

Aha, so now we have a very easy way to get the name of the calling script, plus a way to extract out of it the actual file name (page name) being used. And this is how Page Permissions was originally written.

As written, it had a major security hole, all because of the fact that PHP_SELF returns too much data. A MOD validator caught this during the validation process. Here’s what happens.

Suppose that – as before – we have protected memberlist.php so that only registered users can read it. A guest can easily bypass the logic in the old MOD code by constructing the following URL for your board:

http://www.example.com/phpBB2/memberlist.php/index.php

What? :-? What is that? Well, it looks very strange, but it turns out that it works. You see, here’s what comes out of PHP_SELF and pathinfo() for this URL:

PHP_SELF is /phpBB2/memberlist.php/index.php
dirname is /phpBB2/memberlist.php
basename is index.php
extension is php

:shock: You see what happened? By constructing this weird URL a guest was able to fake out PHP_SELF into including “index.php” at the end of the URL. And it is very unlikely that a board owner would restrict guest access to index.php. Yes, it happens, I understand that. But the overwhelming majority of board owners want their index to be visible. And notice the directory name includes memberlist.php. Why?

It seems that the pathinfo() function is faked out by the structure of the data returened by PHP_SELF. If I were writing the core code for pathinfo() it seems that a rather easy (if brute force) method to extract parts is simply look for the / that divides the path into parts, and strip out the last part. It certainly seems that is what happens here.

But what is the impact to Page Permissions? The pathinfo() returns “index.php” as the calling script! As there are no restrictions on index.php, the access is allowed. Then the web server sees the url as memberlist.php/index.php and resolves that memberlist.php is, in fact, a file and not a directory, and displays it. :shock: Ouch.

Long story short, I did some research, and found out there is another option called SCRIPT_NAME. The SCRIPT_NAME returns exactly the name of the executing script without all of the extra baggage that PHP_SELF returns. So by simply replacing PHP_SELF with SCRIPT_NAME in the Page Permissions code I was able to close this loophole. Here are the same results using SCRIPT_NAME instead of PHP_SELF from my earlier example:

SCRIPT_NAME is /phpBB2/memberlist.php
PHP_SELF is /phpBB2/memberlist.php/index.php
dirname is /phpBB2
basename is memberlist.php
extension is php

I have updated the Page Permissions MOD and posted a download link at phpbb.com. If you are using this MOD and have not updated, please do so immediately. There is only one change required.

#
#-----[ OPEN ]-------------------------------------
#
includes/page_permissions.php

#
#-----[ FIND ]-------------------------------------
#
PHP_SELF

#
#-----[ IN-LINE FIND ]-------------------------------------
#
PHP_SELF

#
#-----[ IN-LINE REPLACE WITH ]-------------------------------------
#
SCRIPT_NAME

Oh, and the official documentation for SCRIPT_NAME includes:

Contains the current script’s path. This is useful for pages which need to point to themselves. The __FILE__ constant contains the full path and filename of the current (i.e. included) file.

I added the emphasis myself. :-)

5 Comments »

  1. Very good post, i shall link to this ;)

    Comment by eviL<3 — January 29, 2007 @ 5:53 pm

  2. Awesome! I’ve never thought about such sort of abuse of PHP_SELF. Thanks for sharing.

    // Just re-checked my code. Fine, only __FILE__ and $_SERVER['REQUEST_URI'].

    Comment by olpa — January 29, 2007 @ 10:54 pm

  3. olpa, I had never thought of such a thing either. :-) I am really quite grateful to the job done by the phpBB MOD Validation team. Every time they reject one of my MODs I learn something new, and generally important. 8)

    If it wasn’t obvious, this was the security issue that caused me to write this post a few days ago. Before revealing the specifics I wanted to give folks that were using the RC versions a chance to upgrade. I contacted some folks that I knew were using it, and had no way to know who I was missing.

    Still don’t.

    Comment by dave.rathbun — January 30, 2007 @ 9:20 am

  4. Excellent point. I just spotted use of PHP_SELF in Whobar. I think you should report it and get the credit.

    Comment by damnian — February 4, 2007 @ 2:51 pm

  5. I will defer that opportunity to you. :-) I’m not familiar with the product at all… if you are, it would probably have more weight coming from someone that knows what they’re talking about, and I clearly would not.

    Comment by dave.rathbun — February 4, 2007 @ 10:16 pm

RSS feed for comments on this post.

Leave a comment

Tags allowed in comments:
<a href="" title=""> <acronym title=""> <blockquote cite=""> <code> <strong> <em> <u> <sup> <sub> <strike>

Confirm submission by clicking only the marked checkbox:

 **             

Powered by WordPress