Hi Rowan, 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. Regards, > -- Yasuo Ohgaki yohg...@ohgaki.net