Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support symlinks while not allowing malicious template paths. #442

Merged
merged 4 commits into from
Jul 9, 2020

Conversation

colinmollenhour
Copy link
Member

There is too much history to go into behind this ticket but as requested at colinmollenhour/modman#125 here is a PR that includes what I think is the best fix for the "Allow Symlinks" issue. This prevents use of ".." in the template paths and the setScriptPath but does not prevent use of symlinks outright. This is far more secure than enabling "Allow Symlinks" option since it still provides protection against inclusion of malicious files outside of the Magento base "design" directory. As far as I can tell it is just as secure as disabling "Allow Symlinks" option so since it doesn't suffer the downsides I don't see any need for an "option".

Please test this with some of your deployments. It works for mine but I haven't tried it with a wider range of third party extensions. Also if anyone is privy to the vulnerability implementation details and can confirm that this circumvents them that would be great.

@LeeSaferite
Copy link
Contributor

I haven't tested this code so I apologize if this is a stupid question.

Do these changes break using something like modman to keep the external modules outside of the core code directory? Something like /modules/OpenMage_Stuff and /magento where the module is installed using symlinks under /magento. In that setup the docroot would be /magento

@colinmollenhour
Copy link
Member Author

It works with the files outside the Magento root because by default the _viewDir property is set to Mage::getBaseDir('design') to begin with (in renderView just before it is rendered) so this comparison is true. If you use setScriptPath to set a different view directory (I've never once seen a need for this and actually would be all for removing this method or making it private) then the script path has to be within the base design path. If you use '..' in your template paths then it will not work, but then neither would "Allow Symlinks = No" before even if you weren't using symlinks. The important thing is this will be prevented:

{{block type="core/template" template="../../../../some/path/to/malicious.php"}}

But you could create a symlink and reference it as usual with this patch. If an attacker has the capability of writing a symlink they would also be able to write a regular file as well. For example, the "symlink" check could be bypassed by just writing a file that has <?php include __DIR__.'/../../../../some/path/to/malicious.php'; in almost the same number of bytes. This is why it is best to only allow the webserver to write to media and var and all other files/paths should only be readable by the web server.

@Flyingmana
Copy link
Contributor

As far as I can tell it is just as secure as disabling "Allow Symlinks" option so since it doesn't suffer the downsides I don't see any need for an "option".

Iam against merging this without having at least one security expert reviewing this.

@colinmollenhour
Copy link
Member Author

@Flyingmana Please ask a security expert to review. :)

@pocallaghan
Copy link

I certainly don't consider myself an expert, but I approve @colinmollenhour's code here. We've been running essentially this code in production for clients for a long time now, mostly because up until the release of SUPEE-10570, it was still possible (through a bypass vulnerability) to re-enable the feature from the admin panel, meaning there was no protection from arbitrary includes in core Magento (given enough priveledges to update config of course).

In my mind, the logic behind this code makes more sense than the original feature ever did, because it allows for symlinks to work inside the directory, but not allow arbitrary inclusion of any file path. As Colin mentioned, if somebody can write the symlink to include a malicious external file, they could likely have written the malicious file directly anyway.

If there is a flaw in this implementation, I've been unable to see it.

@Flyingmana
Copy link
Contributor

If there is a flaw in this implementation, I've been unable to see it.

I keep repeating myself here: all of the attack vectors have not been seen by anyone here before.

We've been running essentially this code in production for clients for a long time now

this does not matter the sightliest for security vulnerabilities. There are some, which survive more then ten years.

@pocallaghan
Copy link

pocallaghan commented Mar 14, 2018

this does not matter the sightliest for security vulnerabilities. There are some, which survive more then ten years.

I'm well aware, I've reported a significant number of the ones patched by Magento. But if my opinions on the code don't matter in the slightest, I'll keep them to myself.

@colinmollenhour
Copy link
Member Author

Thanks for the review, @pocallaghan. I've seen your name on many of the vulnerability discoveries for bugs which existed for years and nobody else found so thanks for your continued contributions to Magento's security as well. I'm very happy to see you have some interest in this project, because if you're not a Magento security expert I don't know who is. :)

@Flyingmana wrote:

I keep repeating myself here: all of the attack vectors have not been seen by anyone here before.

When someone who has a proven track record of finding security vulnerabilities looks at an alternative solution for a well known vulnerability speficially in the context of examining security and says they don't see any flaws I think this means a lot more than you're giving credit for. This logic could otherwise be applied to every patch made on this project and so we should not accept any patches since every patch could introduce some new vulnerability.

So, what exactly is your definition of a security expert and how can we determine which code is safe to update and which code is not?

@Flyingmana
Copy link
Contributor

you are right @colinmollenhour , This is a proven track record of finding security vulnerabilities and totally counts.

@pocallaghan
I need to apologize and hope for forgiveness, as I usually dont check the background of participants.
Could you then also add your approval to the PullRequest?

@seansan
Copy link
Contributor

seansan commented Mar 15, 2018 via email

@pocallaghan
Copy link

@Flyingmana no apologies necessarily. As I said, I don't consider myself an expert, but I'm happy to offer my opinions.

tmotyl
tmotyl previously approved these changes Mar 17, 2018
Copy link
Contributor

@tmotyl tmotyl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

@idziakjakub
Copy link
Contributor

I found that there is no way to load non inline CSS files in transactional emails when I'm using symlinks.

$filePath = realpath($filePath);
$positionSkinDirectory = strpos($filePath, Mage::getBaseDir('skin'));
$validator = new Zend_Validate_File_Extension('css');
if ($validator->isValid($filePath) && $positionSkinDirectory !== false && is_readable($filePath)) {
return (string) file_get_contents($filePath);
}
// If file can't be found, return empty string
return '';

$positionSkinDirectory = strpos($filePath, Mage::getBaseDir('skin'));

I think "$positionSkinDirectory" should be refactored too.

@colinmollenhour
Copy link
Member Author

LGTM. Can we get a couple reviewers?

I just added an exception to be thrown for all fallback-based file paths if they contain '..' which should fix the issue observed by @idziakjakub while also reducing the chances of there being new or unknown vulnerabilities.

@ollyboy
Copy link

ollyboy commented Oct 25, 2018

Would be great to see this completed. Currently, the settings ( below ) mess up our installation as we use composer to install and manage all modules. Setting this to "0" breaks lots of templates in Amasty Nav modules and other modules

screen shot 2018-10-25 at 2 36 00 pm

The way we get around this is to use this command in our go-live scripts

n98-magerun config:set dev/template/allow_symlink 1

@colinmollenhour
Copy link
Member Author

Any objections to merging this? We're operating off of a fork right now but it would be nice to get back to the mainline. Setting allow_symlink to 0 disables the security vulnerability patch and this issue removes the flag in favor of fixing the vulnerability in a way that doesn't need to be disabled.

Flyingmana
Flyingmana previously approved these changes Sep 24, 2019
@colinmollenhour colinmollenhour requested review from edannenberg and sreichel and removed request for bastianccm October 1, 2019 07:48
@Flyingmana
Copy link
Contributor

in case someone needs a module to check symlink functionality, I found one which requires them in their install inscructions.
https://github.com/wirecard/magento-ee/wiki/Installation

Did not look in detail into it myself.

@colinmollenhour colinmollenhour changed the base branch from 1.9.3.x to 1.9.4.x April 23, 2020 22:26
@colinmollenhour colinmollenhour dismissed Flyingmana’s stale review April 23, 2020 22:26

The base branch was changed.

@colinmollenhour
Copy link
Member Author

I changed based from 1.9.3.x to 1.9.4.x so all reviews are stale.. I would like to merge this pretty soon if there are no objections so please speak now or forever hold your peace. :)

@colinmollenhour
Copy link
Member Author

Rebased on latest. Removed symlink notification since it is no longer relevant.

Proof that this fixes a security vulnerability when allow_symlink is enabled:

  • Created PHP file at var/malicious.php with contents <?php die('pwned');
  • Allowed symlinks by adding <default><dev><template><allow_symlink>1</allow_symlink></template></dev></default> to app/etc/local.xml
  • Created CMS page with block references to malicious file:
    image
  • Verified malicious file is loaded:
    image
  • Checked out support-symlinks branch
  • Verified malicious file is no longer loaded:
    image

@colinmollenhour colinmollenhour merged commit fd85473 into OpenMage:1.9.4.x Jul 9, 2020
@sreichel sreichel added this to the Release 20.0.2 / 19.4.6 milestone Aug 7, 2020
edannenberg pushed a commit to edannenberg/magento-lts that referenced this pull request Aug 20, 2020
…plate paths

* Support symlinks while not allowing malicious template paths.
* Add protection for unauthorized file access to all fallback-based paths and
  allow symlinks for inlinecss directive.
* Remove symlink notification.
edannenberg pushed a commit to edannenberg/magento-lts that referenced this pull request Aug 24, 2020
…plate paths

* Support symlinks while not allowing malicious template paths.
* Add protection for unauthorized file access to all fallback-based paths and
  allow symlinks for inlinecss directive.
* Remove symlink notification.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants