Severe Security Vulnerability in Bower’s Zip Archive Extraction
Earlier this month it was found that Bower, a popular web package manager, is vulnerable to archive extractions and currently, we can associate two security incidents with it, for which follow-up releases to address them are available:
- Arbitrary file writes with potential remote command injection, which was fixed in Bower 1.8.6, resulted from the Zip Slip vulnerabilities found in the decompress-zip dependency, an open source dependency used by Bower.
- Arbitrary file writes caused by .tar.gz archive symbolic link (symlink) vulnerabilities that are exploited because of how Bower extracts such archives, was fixed in Bower 1.8.8.
On January 1st 2019, a security researcher called skyn3t, reported to the Node.js security working group on HackerOne an arbitrary file write implemented through improper validation of symlinks resulting from the way Bower handles tar archive extraction.
Shortly after the bug had been triaged, Adam Stankiewicz from Bower’s core team was invited to review the report and promptly confirmed it, providing a fix in the Bower 1.8.8 release to address the security concern.
Malicious path traversal in archive extraction
If a malicious actor were to create a specially crafted zip archive for a package that was then installed with Bower, it could result in path traversal so that files would get extracted outside the root directory that is expected to unwrap the archive.
The following Proof of Concept (POC) originates from a security report that was disclosed by skyn3t to the Node.js security working group program on HackerOne, and shows how insecure handling of symlinks may result in arbitrary file writes.
The malicious package archive
The archive needs to create a symlink to a directory and then land a file in that target directory, but in order to replicate this directory layout we need to hand-craft a malicious archive.
We will start off by creating a directory for the malicious package, a default package.json file for Bower, and a symlink to /tmp:
mkdir malicious-package cd malicious-package npm init -y ln -s /tmp mySpecialDirectory
Now we can create a tarball archive for this package, and make sure not to compress it:
tar -cvf malicious-package.tar malicious-package
The tricky part is getting a file of our control into the /tmp directory and essentially into mySpecialDirectory/ inside the archive. That filename is already taken as a link, so we can’t just re-use it on our own filesystem.
To overcome this challenge, we revert back to standard core archive functionality – manipulating data within the archive. tar files allow us to update an existing archive, such as adding more files to it, enabling us to create an escape hatch.
We’ll go ahead and delete the link, create a directory in place of it and create our own file inside of it. Then we will add just that file into the archive with the tar update functionality:
rm mySpecialDirectory mkdir mySpecialDirectory echo “abc” > mySpecialDirectory/ssmaliciousFile cd .. tar -rvf malicious-package.tar malicious-package/mySpecialDirectory/ssmaliciousFile
As can be seen in the screenshot, the contents of the archive include a symlink to the /tmp directory as well as to a malicious file that we’ve created:
It’s important to note that compressed archives can’t be manipulated the same way that tar archives can. Therefore, we’ll perform the gzip compression now that the archive has been maliciously crafted:
Triggering Bower to install
Now that we have a tar.gz archive in the home folder directory ~/tmp let’s execute a Bower installation from the local file system in order to demonstrate how the package unravels:
As can be seen, Bower 1.8.7 is used and upon installing the malicious package the malicious file that was in our control was subsequently installed in the system’s /tmp directory.
Addressing the vulnerability
Bower supports these archive types: tar, tar.gz and zip. While a similar vulnerability affecting zip packages was already solved by fixing decompress-zip, tar and tar.gz remained vulnerable.
The applied fix that was ultimately offered for the tar and tar.gz vulnerabilities mitigated the issue by ignoring any symlinks in packages to be installed, and a new Bower version has since been released as 1.8.8 for users to upgrade to and mitigate the security issue.
Earlier in 2018, the Snyk security research team had coined the Zip Slip security vulnerability term after conducting widespread research for archive extraction exploitation that results in arbitrary file writes. A critical severity may further result in remote command execution and overwriting sensitive system configuration files.
The Zip Slip research resulted in the discovery of thousands of projects that were vulnerable, across many ecosystems, and affecting projects from Apache, Pivotal, Amazon, and others.
We’ve seen how to create a deliberate malicious package that can cause an arbitrary file write, but the problem doesn’t rest just with malicious packages being downloaded. If a package is fetched over an insecure medium, such as non-HTTPS traffic, then a man-in-the-middle attack can be employed.
Issues with extracting files aren’t new and might actually date all the way back to a Phrack article in 1991 that explained how to hack a BBS by employing such zip extraction attack vectors. We will most likely continue to see Zip Slip vulnerabilities being discovered in libraries and applications as more research is conducted in this field.
Remember that even though symlinks are allowed, working with user-controlled archives is dangerous and should be handled with due-diligence just like with any other user input.
- Upgrade to Bower 1.8.8 as soon as possible.
- You’re invited to consult our Zip Slip Cheat Sheet for references of vulnerable code in different language ecosystems and how to avoid similar security vulnerabilities in your code.