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

fix: prevent extracting archived files outside of target path #59

Merged
merged 1 commit into from
Apr 16, 2018

Conversation

aviadatsnyk
Copy link

@aviadatsnyk aviadatsnyk commented Apr 16, 2018

Why this PR?

This PR is meant to fix an arbitrary file write vulnerability, that can be achieved using a specially crafted zip archive, that holds path traversal filenames. When the filename gets concatenated to the target extraction directory, the final path ends up outside of the target folder.

A sample malicious zip file named zip-slip.zip. (see this gist) was used, and when running the code below, resulted in creation of evil.txt file in /tmp folder.

fs.createReadStream('zip-slip.zip').pipe(unzipper.Extract({ path: '/tmp/safe' }));

There are various possible ways to avoid this issue, some include checking for .. (dot dot) characters in the filename, but the best solution in our opinion is to check if the final target filename, starts with the target folder (after both are resolved to their absolute path).

Stay secure,
Snyk Team

@aviadatsnyk aviadatsnyk force-pushed the fix/zip-slip branch 5 times, most recently from aee680d to 5ff422a Compare April 16, 2018 12:43
@aviadatsnyk
Copy link
Author

Finally got a version that passes for all the node versions, so no more planned changes here.

// destination, or not extract it otherwise.
var extractPath = path.join(opts.path, entry.path);
if (extractPath.indexOf(opts.path) != 0) {
return;
Copy link
Owner

Choose a reason for hiding this comment

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

This should either throw an error or at the very least show a warning.
Also the entry is left hanging here as nothing drains it (possibly use .autodrain)

@ZJONSSON ZJONSSON merged commit 2220ddd into ZJONSSON:master Apr 16, 2018
@ZJONSSON
Copy link
Owner

published as unzipper@0.8.13. Awesome catch, thank you!!

@glen-nicol
Copy link

Hi there, I ended up using the code snippet above to add zip-slip protection to some of my manual unzipping methods that use this library. And I noticed that on my linux docker image it failed to detect the windows zip-slip archive.

I am using the following and it catches both of the examples from synk on windows and linux docker images (did not try mac)

const DUMMY_PATH = path.join('/sandbox');
const extractPath = path.join(DUMMY_PATH, zipEntry.path.replace(/\\/g, '/'));
if (extractPath.indexOf(DUMMY_PATH) !== 0) {
  return true;
}

@ZJONSSON
Copy link
Owner

Good catch, can you do a PR with a test that fails without the fix above?

@glen-nicol
Copy link

Sure, I'll try to do that in the next couple days.

@ZJONSSON
Copy link
Owner

Awesome, thank you @glen-nicol

@glen-nicol
Copy link

I was looking at it some more, I don't think UNIX machines are actually vulnerable to the windows zip. But I think it will end up creating a rather strange filename "................\tempevil.txt". Should we still go ahead and make the change to ignore something that is obviously attempting to do something bad?

@ZJONSSON
Copy link
Owner

ZJONSSON commented Feb 11, 2020

Thanks @glen-nicol I ran tests against the windows zip-slip archive on a windows machine and the file was safely ignored there. Ideally we should want same behavior independent of platform so the preference here would be to ignore. But I'm happy that this is not actual vulnerability

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants