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

[Security] Amend earlier download fix #2876

Merged
merged 4 commits into from
Jun 21, 2017
Merged

[Security] Amend earlier download fix #2876

merged 4 commits into from
Jun 21, 2017

Conversation

johnsaigle
Copy link
Contributor

This pull request restores the broken functionality merged in #2868. This fixes the access control issue while allowing valid files to download.

See also: Redmine 12586.

@johnsaigle johnsaigle added Category: Bug PR or issue that aims to report or fix a bug Release: Breaking changes PR that contains changes that might impact the code or accepted practices of active projects labels Jun 14, 2017
@johnsaigle johnsaigle added this to the 17.0 milestone Jun 14, 2017
@johnsaigle
Copy link
Contributor Author

johnsaigle commented Jun 14, 2017

@driusan Please take a look at this fix when you can. Also, I strongly recommend that we include this function in the Utility class as we'll likely need this workaround in the future.

realpath() doesn't work for us as it requires that the web-user have write access in each directory in the hierarchy.

@xlecours xlecours self-assigned this Jun 14, 2017
@MounaSafiHarab
Copy link
Contributor

@johnsaigle

I tested this, and I now can see the images again in Imaging browser, and can download (I tested MINC downloads as this is the type of files I usually download).

@johnsaigle
Copy link
Contributor Author

@MounaSafiHarab thanks for testing!

@johnsaigle johnsaigle added the Passed manual tests PR has been successfully tested by at least one peer label Jun 14, 2017
}
// resolve path parts (single dot, double dot and double delimiters)
$path = str_replace(array( '/', '\\' ), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a pretty hard to read way to strip out the empty parts.

Can you just use a function defined inline which returns true if strlen > 0 to make it a little more obvious what the array_filter is trying to filter for, instead of basing it on an implicit assumption that 0 and false are equivalent?

continue;
}
if ('..' == $part ) {
array_pop($absolutes);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might be a good idea to check the return value here and throw an exception if you're trying to pop off of an empty stack.

$path = implode(DIRECTORY_SEPARATOR, $absolutes);
// resolve any symlinks
if (file_exists($path) && linkinfo($path) > 0 ) {
$path = readlink($path);
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this necessary? What's wrong with resolving the path to a symbolic link?

@@ -19,6 +19,46 @@
* @link https://github.com/aces/Loris-Trunk
*/

/**
* This function is to replace PHP's extremely buggy realpath().
* Taken from https://gist.github.com/umidjons/6154548
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the copyright on it? I don't see any copyright notice, which means it defaults to all rights reserved and we don't have the right to use it unless the author gives explicit written approval.

(Which makes most of my below comments a moot point..)

Copy link
Contributor Author

@johnsaigle johnsaigle Jun 14, 2017

Choose a reason for hiding this comment

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

Gotcha... I've messaged the author and if he's feeling generous he'll hopefully license it properly. I'll look into another solution in the meantime.

// Check if the resolved 'true' path starts with the prefix.
// If not, user supplied a relative path which is forbidden
if (substr($TruePath, 0, strlen($PathPrefix)) !== $PathPrefix) {
error_log("ERROR: User supplied relative path. Potentially malicious.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

You might want to include the IP address or username if you're going to provide a message like this, so it can be followed up with.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool, can do.

switch($FileExt) {
case 'mnc':
$FullPath = $mincPath . '/' . $File;
$PathPrefix = $mincPath;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are these all changed instead of just switching realpath to truepath and verifying that it fixes the security issues (and works..)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well I did verify it works and fixes the security issue (which has been confirmed by @MounaSafiHarab). You're right this is more of a cosmetic change but it also makes the file a little smaller and I think clearer.

@driusan driusan added the State: Blocked PR or issue awaiting an external event such as the merge or another PR to proceed label Jun 14, 2017
@driusan
Copy link
Collaborator

driusan commented Jun 14, 2017

Adding the blocked tag because of the copyright issue.

@johnsaigle
Copy link
Contributor Author

@driusan I removed the offending code as well as the cleanup changes. This PR now only contains the minimum changes needed for security.

I've tested this on my VM and it allows files to download while also preventing the exploit.

@johnsaigle johnsaigle removed the State: Blocked PR or issue awaiting an external event such as the merge or another PR to proceed label Jun 15, 2017
@driusan driusan dismissed their stale review June 15, 2017 19:20

Changes donne

@johnsaigle
Copy link
Contributor Author

johnsaigle commented Jun 16, 2017

@driusan do you think you could give me an approving review now that the changes are done? 😂 Also, what are your thoughts on moving this to Utility?

@johnsaigle
Copy link
Contributor Author

@MounaSafiHarab Would you mind re-testing this with the new changes?

@johnsaigle johnsaigle removed the Passed manual tests PR has been successfully tested by at least one peer label Jun 16, 2017
@MounaSafiHarab MounaSafiHarab added the Passed manual tests PR has been successfully tested by at least one peer label Jun 16, 2017
@MounaSafiHarab
Copy link
Contributor

MounaSafiHarab commented Jun 16, 2017

@johnsaigle

works for me (tested minc images download in imaging browser)!
do I move it to the last column, or is it up to @driusan to approve it as a reviewer first?

@driusan driusan merged commit f460ad7 into aces:17.0-dev Jun 21, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Bug PR or issue that aims to report or fix a bug Category: Security PR or issue that aims to improve security Passed manual tests PR has been successfully tested by at least one peer Release: Breaking changes PR that contains changes that might impact the code or accepted practices of active projects
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants