Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Java provides the java.util.zip package for zip-compatible data compression.   It provides classes that allow enable you to read, create, and modify ZIP and GZIP file formats. 

There are a A number of security concerns must be considered when extracting file entries from a ZIP file using java.util.zip.ZipInputStream.   File names may contain path traversal information that may cause them to be extracted outside of the intended directory, frequently with the purpose of overwriting existing system files.  Directory traversal or path equivalence vulnerabilities can be eliminated by canonicalizing the path name per , in accordance with FIO16-J. Canonicalize path names before validating them and , and then validating the location before extraction.

A second issue is that the extraction process can cause excessive consumption of system resources. This may result , possibly resulting in a denial-of-service attack when resource usage is disproportionately large in comparison compared to the input data. The zip algorithm can produce very large compression ratios [Mahmoud 2002]. For example, a file consisting of alternating lines of a characters and b characters can achieve a compression ratio of more than 200 to 1. Even higher compression ratios can be obtained using input data that is targeted to the compression algorithm. This permits the existence of zip bombs in which a small ZIP or GZIP file consumes excessive resources when uncompressed.   An example of a zip bomb is the file 42.zip, which is a zip file consisting of 42 kilobytes of compressed data, containing five layers of nested zip files in sets of 16, each bottom layer archive containing a 4.3 gigabyte (4 294 967 295 bytes; ~ 3.99 GiB) file for a total of 4.5 petabytes (4 503 599 626 321 920 bytes; ~ 3.99 PiB) of uncompressed data. Zip bombs often 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 attempts to overcome the problem by calling the method ZipEntry.getSize() to check the uncompressed file size before uncompressing it.   Unfortunately, a malicious attacker can forge the field in the ZIP file that purports to show the uncompressed size of the file. So,  the so the value returned by getSize() is unreliable, and local resources may still be exhausted.

Code Block
bgColor#FFcccc
static final int BUFFER = 512;
static final int TOOBIG = 0x6400000; // 100MB
// ...

public final 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, but only if the file is not insanely big
      if (entry.getSize() > TOOBIG ) {
         throw new IllegalStateException("File to be unzipped is huge.");
      }
      if (entry.getSize() == -1) {
         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.close();
  }
}

Acknowledgement: The vulnerability in this code was pointed out by Giancarlo Pellegrino, researcher at the Technical University of Darmstadt in Germany, and Davide Balzarotti, faculty member of EURECOM in France.

...

Furthermore, the code inside the while loop tracks the uncompressed file size of each entry in a zip archive while extracting the entry. It throws an exception if the entry being extracted is too large—about 100MB in this case. We do not use the ZipEntry.getSize() method because the value it reports is not reliable. Finally, the code also counts the number of file entries in the archive , and throws an exception if there are more than 1024 entries.

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

IDS04-J

lowLow

probableProbable

highHigh

P2

L3

Related Guidelines

MITRE CWE

CWE-409, Improper handling of highly compressed data (data amplification)

Secure Coding Guidelines for the Java Programming Language, Version 3.0

Guideline 2-5, Check that inputs do not cause excessive resource consumption

...

Although not directly a violation of this rule, the Android Master Key vulnerability (insecure use of ZipEntry) is related to this rule. Another attack vector, found by a Chinese researcher in China, is also related to this rule.

...

 

...