Page 2 of 4

Posted: Sun Aug 14, 2005 8:33 pm
by shiflett
onion2k wrote:In general, unless I'm going to have millions of different include files, I use a switch
This is an excellent approach and one I often recommend. It's very clear, plus it doesn't depend on any variables. Hard coded strings are very safe and obvious.

In contrast, look at how unclear the other suggestions are in comparison.
nielsene wrote:Well you aren't stripping out "../"s so its possible that a file could escape the sandbox.
One security principle to which I adhere (or try to) is to never try to correct invalid data. When you do, you create an opportunity for you to make a mistake that yields a security vulnerability. For example, here is an approach I have observed quite frequently:

Code: Select all

$string = str_replace('..', '.', $tainted_string);
Can you think of a way around this?
nielsene wrote:It is forced to be a php file so they couldn't show the passwd file.
That's not true. The way include works is the file (or resource) you reference is treated just like any other PHP file. If there are no PHP blocks, it's treated as raw output.
Roja wrote:Thats why statements like "I've never had any problems" have no place in a discussion about security.
Roja++
Roja wrote:Correct, because you are going above the root - which makes no sense.
What he said isn't correct, because going above root doesn't fail. Maybe it does on Windows or something, but the parent directory of root is root.
Todd_Z wrote:If you tried to include /home/blah/public_html/../../index.php", you would get an error for file not being found.
I have no idea what you think you've proven, but try this:

/home/blah/public_html/../../../../../../../../../../etc/passwd

If you're on Windows, that won't work either, but maybe you get the idea.
Roja wrote:They can't VIEW them, they can cause them to be included/executed.
Includes are treated just like any other PHP file. The only code that is executed is within PHP blocks. Everything else is just raw output.

So, if you're referring to his example of index.php, you're right. If this is the case, just be careful to qualify your statements. :-)

Hope that helps.

Posted: Sun Aug 14, 2005 9:05 pm
by Roja
shiflett wrote:
Roja wrote:Correct, because you are going above the root - which makes no sense.
What he said isn't correct, because going above root doesn't fail. Maybe it does on Windows or something, but the parent directory of root is root.
Actually, going above the root does fail. If you use the correct number of parents, you can explore to directories next to the directory in question.
shiflett wrote:
Todd_Z wrote:If you tried to include /home/blah/public_html/../../index.php", you would get an error for file not being found.
I have no idea what you think you've proven, but try this:

/home/blah/public_html/../../../../../../../../../../etc/passwd

If you're on Windows, that won't work either, but maybe you get the idea.
My code sample shows that you can use parent dirs (../), which previous posts claimed you couldn't do ("You can't access anything but the directory"). It allows you to go above, sideways, and below. By using the absolute value from the root, you can go all the way up, and all the way down.

From my reading, we actually agree, but your phrasing seems to indicate that you didn't quite understand what I meant. :)

Posted: Sun Aug 14, 2005 9:09 pm
by shiflett
Roja wrote:Actually, going above the root does fail.
On what platform? I'm not aware of any platform that has this behavior.

Posted: Sun Aug 14, 2005 9:57 pm
by nielsene
shiflett wrote: In contrast, look at how unclear the other suggestions are in comparison.
nielsene wrote:Well you aren't stripping out "../"s so its possible that a file could escape the sandbox.
One security principle to which I adhere (or try to) is to never try to correct invalid data. When you do, you create an opportunity for you to make a mistake that yields a security vulnerability. For example, here is an approach I have observed quite frequently:

Code: Select all

$string = str_replace('..', '.', $tainted_string);
Can you think of a way around this?
Yes I can. And yes normally I wouldn't correect the data, only detect and reject. (Ie check if filename = basename or reject) slightly strong versions can check for forward/backward slashes under a somewhat long set of encodings and reject in those as well.
nielsene wrote:It is forced to be a php file so they couldn't show the passwd file.
That's not true. The way include works is the file (or resource) you reference is treated just like any other PHP file. If there are no PHP blocks, it's treated as raw output.
Not true in this case. The OP was concatenating ".php" onto the user-provided name. That's what I mean by a PHP file, not a parsed file, but I can see the opportunity for confusion. Even if they asked for /etc/passwd it would end up being /etc/passwd.php

Posted: Sun Aug 14, 2005 9:58 pm
by nielsene
shiflett wrote:
Roja wrote:Actually, going above the root does fail.
On what platform? I'm not aware of any platform that has this behavior.
Same here... The only exception I'm aware of is if you've mada chroot/jail.

Posted: Sun Aug 14, 2005 10:07 pm
by shiflett
nielsene wrote:Not true in this case. The OP was concatenating ".php" onto the user-provided name. That's what I mean by a PHP file, not a parsed file, but I can see the opportunity for confusion.
I see now. Thanks.

An attacker can get around the .php concatenation on many platforms by using a NUL byte. For example:

http://example.org/test.php?p=../../../ ... /passwd%00

Try it - you might be surprised by the results.

Posted: Sun Aug 14, 2005 10:13 pm
by nielsene
Yup I've seen that too...

All these little exceptions is why I don't do user-provided includes. If I had to, I'd use the basename function, coupled with a regexp ([-A-Za-z0-9_]), with forced ending (.php or .inc depending on your preference, etc‚). The null-byte, full stops. and slashes wouldn't survive that.

As always, state what you'll accept, not what you'll reject. Its too easy to miss something if you only list the bad stuff.

Posted: Sun Aug 14, 2005 11:22 pm
by Todd_Z
Oh, i see the security holes now. But no - I keep my server as clean as possible.

Posted: Mon Aug 15, 2005 10:13 am
by timvw
http://www.php.net/realpath can come in quite handy ;)

Posted: Wed Aug 17, 2005 10:02 am
by juglesh
how's this when you are simply including basic pages?

Code: Select all

$_GET['page'] = ereg_replace("[^[:alnum:] ]","-",$_GET['page']);
also, I was wondering if there is any way around

Code: Select all

include 'myPrefix_'.$_GET['page'].'.php';
I have tried to ../ my way out of it, but it seems secure.

Posted: Wed Aug 17, 2005 12:42 pm
by nielsene
Well the null byte can stop the .php. I'm not sure if an attacker could get a series of ^H control code in to delete the prefix, but that might be possible via some encoding or another.

Posted: Sat Aug 20, 2005 7:02 pm
by DeprecatedDiva
I'm completely inexperienced regarding security issues and still very new to using PHP. From what I've read so far, am I in better shape for using an array of approved includes? This is the method I read about and it is the one I am using. Should I be using a different method? (I am using a testbed server at home for the time being.) :roll: :?

Posted: Sat Aug 20, 2005 7:16 pm
by nielsene
Yes, an explicit list of approved includes is a much more secure starting point. Its still possible to "mess it up" but its generally much safer.

Posted: Mon Oct 10, 2005 8:28 am
by Jenk
Bit of forum Necromancy here, I sometimes use the following:

Code: Select all

<?php
$files = array('main', 'accounts', 'page2', 'blahblah', 'etc');

@include('/path/to/includes/' . $files[intval($_GET['pid'])] '.inc') or include('/path/to/includes/default.php');

?>
on my front controller(s) :)

Posted: Mon Oct 10, 2005 8:08 pm
by Skara
and that has to be the best way I've ever seen. ;)