Hi all, On Sat, Feb 28, 2015 at 11:37 AM, Yasuo Ohgaki <yohg...@ohgaki.net> wrote:
> On Fri, Feb 27, 2015 at 8:25 PM, Rowan Collins <rowan.coll...@gmail.com> > wrote: > >> Yasuo Ohgaki wrote on 27/02/2015 03:44: >> >>> Hi all, >>> >>> This is RFC for removing "allow_url_include" INI option. [1] >>> >>> During "Script only include" RFC[2] discussion, stream wrapper issue is >>> raised. >>> I was thinking this issue as a separate issue, but it seems others are >>> not. >>> >> >> I'm not convinced by the argument that because "phar://blah" looks like a >> URL, allowing it makes allow_url_include broken. Perhaps it would be better >> named allow_remote_include, but it corresponds to masking out your >> PHP_STREAM_REMOTE flag further down, which is the more important >> protection. If you want to be able to disable phar:// access, you could add >> something like allow_local_stream_include for that case without breaking BC. >> > > allow_local_stream_include is one possible solution. It has the same > problem with allow_url_include. > Since allor_url_include is global INI, it applies to child scripts. e.g. > > A.php > ----- > <?php > ini_set('allow_url_include', 'On'); > include('B.php'); > ----- > > B.php > ----- > <?php > include($_GET['var']); // Not only local script execution vulnerable, but > also remote script execution is possible because "allow_url_include=On" > here. > ----- > > We need to control these flags more precisely. That's the reason why I > proposed 2nd parameter for include. > If flags are globals, we cannot control them as it should. > > URL and URI is the same for most users, I think. (It differs, but their > usage is mostly the same) Not > many users expect to work something like > > > include('new_wrapper://some_file_with_special_content/some_how_php_script_is_accecible_suddenly'); > > Attackers can write malicious user stream wrapper as back door. Then > upload attack file and takeover > server. The wrapper will be hard to distinguish if it's legitimate or not. > Attack file can be any kind of > format. It's impossible to detect as malicious file. URL formed script > (stream wrapper) is very flexible/handy/ > hard to be detected tool for attackers. > > Remote resource is extremely danger. Local resource is very dangerous > also. Current phar:// wrapper > implementation spoils file extension and ".." (double dot) protection that > is deployed by many PHP codes > already. User wrapper seems allowed for include(), so malicious user > wrapper can help attackers to > exploit PHP servers. > > > I'm also not at all clear what you mean by "caller" and "callee" >> responsibilities; surely the difference is just between a global option >> (ini_set()) and a local one (extra argument)? And in what way does Option >> #2 require more changes than Option #1, since they both require the >> argument to be present whenever a stream wrapper is used? >> > > First question is answered in previous comment. INI cannot control flags > precisely... > > Option #1 is simple string comparison for filename is passed. It does not > care what's the filter at all nor even filter name is valid or not. 2nd > parameter is > used to make sure filename passed to include() is user's intension. e.g. > > ----- > // somewhere deep in code > $module_name = substr($_GET['module'], -4, 4) === '.php' ? > $_GET['module'] : ''; // Do not care to much, we have safe .php files. > > // somewhere far from above code > include($module_name); // phar://evil_phar/evil_script.php can be executed. > ----- > > With this RFC, if 2nd parameter is omitted > > ------ > include($module_name); // E_RROR, URL formed include(stream wrapper) is > not allowed. > ------ > > to use phar. User must be explicit. > > ----- > include($module_name, 'phar://'); > ----- > > Option #2 will be much more complex than Option #1, since it introduces > types of wrapper, force users to have class method return wrapper type and > pass flags around functions to handle wrapper types correctly. There may be > more. > > > I do think local options are better than global ini settings in many >> cases, but include/require/etc are statements, not functions, so giving >> them extra arguments is awkward - some of your examples are "wrong" in this >> regard: >> >> // Redundant brackets make this look like a function, but it's not: >> include('phar://phar_file/script.php'); >> > // I can add as many as I like, the parser is just resolving them to a >> single string expression: >> include(((('phar://phar_file/script.php')))); >> // This is the actual syntax: >> include'phar://phar_file/script.php'; >> // Implying this for arguments: >> include'phar://phar_file/script.php', 'phar://'; >> // You could explicitly allow a "function form" of the statements, so you >> could parse this: >> include(('phar://phar_file/' . $script_name), 'phar://'); >> // But then you've got a subtle BC break, because the interpretation of >> this changes: >> include ($foo) . ('.php'); >> > > I used include('phar://phar_file/script.php'), but it can be include > 'phar://phar_file/script.php'. > I'm using () since it seemed harder to distinguish parameters and other > text as we can > use () for include/require now. > > I have no intention to change current include/require syntax, except > adding 2nd parameter. > > Thank you for your feedback. I hope I explained well enough. > I'm thinking merging this RFC to "Script only include" RFC. I have to > start over, but it seems > I must do this. > > I'll use Option #1 since it's much easier/simpler/less BC/more precise. > However, > ideas are appreciated always. > In short, I'm saying we have serious security problem in our current stream wrapper implementation and it's friends including include/require. Regards, -- Yasuo Ohgaki yohg...@ohgaki.net