Zip4j Doesn't Supports Reading a Zip From an Inputstream, Only From Disk
Java provides the java.util.zip
package for zip-compatible information compression. Information technology provides classes that enable you lot to read, create, and modify Cypher and GZIP file formats.
A number of security concerns must be considered when extracting file entries from a ZIP file using java.util.cypher.ZipInputStream
. File names may contain path traversal information that may cause them to be extracted outside of the intended directory, often with the purpose of overwriting existing system files. Directory traversal or path equivalence vulnerabilities tin be eliminated past canonicalizing the path name, in accordance with FIO16-J. Canonicalize path names before validating them, and and so validating the location before extraction.
A second outcome is that the extraction process can cause excessive consumption of system resource, possibly resulting in a denial-of-service set on when resource usage is disproportionately big compared to the input information. The cypher algorithm can produce very large compression ratios [Mahmoud 2002]. For instance, a file consisting of alternate lines of a characters and b characters tin achieve a compression ratio of more than than 200 to ane. Even higher compression ratios can be obtained using input data that is targeted to the pinch algorithm. This permits the existence of zip bombs in which a small ZIP or GZIP file consumes excessive resource when uncompressed. An example of a zip bomb is the file 42.null, which is a aught file consisting of 42 kilobytes of compressed data, containing five layers of nested zip files in sets of sixteen, each bottom layer archive containing a 4.iii gigabyte (4 294 967 295 bytes; ~ 3.99 GiB) file for a total of 4.5 petabytes (4 503 599 626 321 920 bytes; ~ three.99 PiB) of uncompressed data.Cypher bombs oftentimes rely on repetition of identical files to achieve their extreme compression ratios. Programs must either limit the traversal of such files or refuse to extract data beyond a certain limit. The actual limit depends on the capabilities of the platform and expected usage.
This noncompliant code fails to validate the proper name of the file that is being unzipped. It passes the name directly to the constructor of FileOutputStream
. It likewise fails to check the resource consumption of the file that is existence unzipped. It permits the operation to run to completion or until local resources are exhausted.
static final int BUFFER = 512; // ... public concluding void unzip(String filename) throws java.io.IOException{ FileInputStream fis = new FileInputStream(filename); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis)); ZipEntry entry; try { while ((entry = zis.getNextEntry()) != zippo) { Organisation.out.println("Extracting: " + entry); int count; byte data[] = new byte[BUFFER]; // Write the files to the disk FileOutputStream fos = new FileOutputStream(entry.getName()); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER); while ((count = zis.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); } dest.flush(); dest.shut(); zis.closeEntry(); } } finally { zis.close(); } }
This noncompliant code attempts to overcome the problem by calling the methodZipEntry.getSize()
to cheque the uncompressed file size earlier uncompressing it. Unfortunately, a malicious aggressor tin forge the field in the ZIP file that purports to testify the uncompressed size of the file, and so the value returned by getSize()
is unreliable, and local resources may yet be exhausted.
static final int BUFFER = 512; static last int TOOBIG = 0x6400000; // 100MB // ... public terminal void unzip(String filename) throws java.io.IOException{ FileInputStream fis = new FileInputStream(filename); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis)); ZipEntry entry; try { while ((entry = zis.getNextEntry()) != null) { System.out.println("Extracting: " + entry); int count; byte data[] = new byte[BUFFER]; // Write the files to the disk, just simply if the file is not insanely big if (entry.getSize() > TOOBIG ) { throw new IllegalStateException("File to be unzipped is huge."); } if (entry.getSize() == -ane) { throw new IllegalStateException("File to be unzipped might be huge."); } FileOutputStream fos = new FileOutputStream(entry.getName()); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER); while ((count = zis.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); } dest.flush(); dest.close(); zis.closeEntry(); } } finally { zis.shut(); } }
Acknowledgement: The vulnerability in this code was pointed out past Giancarlo Pellegrino, researcher at the Technical Academy of Darmstadt in Germany, and Davide Balzarotti, kinesthesia member of EURECOM in France.
In this compliant solution, the lawmaking validates the name of each entry before extracting the entry. If the name is invalid, the unabridged extraction is aborted. Yet, a compliant solution could also skip only that entry and proceed the extraction procedure, or it could even extract the entry to some safety location.
Furthermore, the lawmaking inside the while
loop tracks the uncompressed file size of each entry in a zilch archive while extracting the entry. It throws an exception if the entry being extracted is as well large—about 100MB in this case. We practice not utilise the ZipEntry.getSize()
method considering the value it reports is non reliable. Finally, the lawmaking also counts the number of file entries in the archive and throws an exception if there are more 1024 entries.
static final int BUFFER = 512; static final long TOOBIG = 0x6400000; // Max size of unzipped data, 100MB static final int TOOMANY = 1024; // Max number of files // ... private String validateFilename(String filename, String intendedDir) throws coffee.io.IOException { File f = new File(filename); String canonicalPath = f.getCanonicalPath(); File iD = new File(intendedDir); String canonicalID = iD.getCanonicalPath(); if (canonicalPath.startsWith(canonicalID)) { return canonicalPath; } else { throw new IllegalStateException("File is outside extraction target directory."); } } public concluding void unzip(String filename) throws java.io.IOException { FileInputStream fis = new FileInputStream(filename); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis)); ZipEntry entry; int entries = 0; long total = 0; endeavour { while ((entry = zis.getNextEntry()) != null) { System.out.println("Extracting: " + entry); int count; byte data[] = new byte[BUFFER]; // Write the files to the disk, just ensure that the filename is valid, // and that the file is not insanely big String proper noun = validateFilename(entry.getName(), "."); if (entry.isDirectory()) { Organization.out.println("Creating directory " + proper noun); new File(proper noun).mkdir(); continue; } FileOutputStream fos = new FileOutputStream(name); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER); while (total + BUFFER <= TOOBIG && (count = zis.read(information, 0, BUFFER)) != -one) { dest.write(data, 0, count); full += count; } dest.affluent(); dest.close(); zis.closeEntry(); entries++; if (entries > TOOMANY) { throw new IllegalStateException("Too many files to unzip."); } if (total + BUFFER > TOOBIG) { throw new IllegalStateException("File being unzipped is too big."); } } } finally { zis.close(); } }
Rule | Severity | Likelihood | Remediation Toll | Priority | Level |
---|---|---|---|---|---|
IDS04-J | Low | Likely | High | P2 | L3 |
Vulnerability | Description |
---|---|
Zip Slip | Aught Slip is a form of directory traversal that can be exploited by extracting files from an annal. It is acquired by a failure to validate path names of the files within an annal which can lead to files being extracted exterior of the intended directory and overwriting existing organization files. An assailant can exploit this vulnerability to overwrite executable files to accomplish remote control execution on a victim'south machine. Snyk responsibly disclosed the vulnerability earlier public disclosure on June 5th 2018. Their blog post and technical paper detailing the vulnerability tin can be found at https://snyk.io/web log/zip-slip-vulnerability/. |
Android Implementation Details
Although non directly a violation of this rule, the Android Main Cardinal vulnerability (insecure utilize of ZipEntry
) is related to this dominion. Another assail vector, institute by a researcher in Communist china, is also related to this rule.
Source: https://wiki.sei.cmu.edu/confluence/display/java/IDS04-J.+Safely+extract+files+from+ZipInputStream
0 Response to "Zip4j Doesn't Supports Reading a Zip From an Inputstream, Only From Disk"
Post a Comment