简体   繁体   中英

Apache Commons Compress as solution to Zip Bomb

Java Code is implemented to uncompress zip file using java.util.zip library. Sonarqube reports Security Hotspots vulnerability as prone to " Zip Bomb " security issue with message " Make sure that expanding this archive file is safe here " in the line " ZipEntry entry = zipIn.getNextEntry(); ".

As a solution, trying to use Apache Commons Compress version 1.21 library which handles Zip Bomb starting from version 1.17. For testing, downloaded a Zip Bomb Vulnerable zip file from here .

But this zip file gets uncompressed without any error/exception. What is wrong with this code mentioned under heading "Implementation using Apache Commons Compress Library"?

<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-compress</artifactId>
 <version>1.21</version>
</dependency>

Zip Bomb Vulnerable code

private void unzipNormal(String zipFilePath, String destDirectory) {
    try {
        File destDir = new File(destDirectory);
        if(!destDir.exists()) {
            destDir.mkdir();
        }

        try(ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath))) {
            ZipEntry entry = zipIn.getNextEntry();
            while(entry != null) {
                String filePath = destDirectory + File.separator + entry.getName();
                if(!entry.isDirectory()) {
                    extractFile(zipIn, filePath);
                } else {
                    File dir = new File(filePath);
                    dir.mkdir();
                }
                zipIn.closeEntry();
                entry = zipIn.getNextEntry();
            }
            zipIn.close();
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
    try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) {
        byte[] bytesIn = new byte[4096];
        int read = 0;
        while((read = zipIn.read(bytesIn)) != -1) {
            bos.write(bytesIn, 0, read);
        }
        bos.close();
    } catch (Exception ex) {
        ex.printStackTrace();
        throw ex;
    }
}

Implementation using Apache Commons Compress Library

private void unzip(String srcZipFile, String destFolder) throws IOException {

        Path filePath = Paths.get(srcZipFile);

        try(InputStream inputStream = Files.newInputStream(filePath);
            ZipArchiveInputStream i = new ZipArchiveInputStream(inputStream)
        ) {
            System.out.println("Begin..");
            ArchiveEntry entry = null;
            while((entry = i.getNextEntry()) != null) {
                if(!i.canReadEntryData(entry)) {
                    System.out.println("Continue..");
                    continue;
                }

                Path path = Paths.get(destFolder, entry.getName());
                File f = path.toFile();
                if(entry.isDirectory()) {
                    if (!f.isDirectory() && !f.mkdirs()) {
                        throw new IOException("failed to create directory " + f);
                    }
                } else {
                    File parent = f.getParentFile();
                    if(!parent.isDirectory() && !parent.mkdirs()) {
                        throw new IOException("failed to create directory " + parent);
                    }
                    try (OutputStream o = Files.newOutputStream(f.toPath())) {
                        IOUtils.copy(i, o);
                    }
                }

            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
}

Able to frame the solution with answer from here . Solution uses the Apache POI utility class and hence updated Maven pom.xml with Apache POI dependency.

Maven pom.xml

<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>4.1.2</version>
</dependency>

Solution

public static void main(String[] args) throws IOException {
    Main main = new Main();
    String srcZipFile = "/Users/user1/Documents/ZipBomb/zbsm.zip";
    String destFolder = "/Users/user1/Documents/ZipBomb/unzipApacheLARGE/";
    main.handle(srcZipFile, destFolder);
}


private void handle(String srcZipFile, String destFolder) throws IOException {
    ZipSecureFile zipSecureFile = new ZipSecureFile(srcZipFile);

    Enumeration<? extends ZipArchiveEntry> entries = zipSecureFile.getEntries();
    while (entries.hasMoreElements()) {
        ZipArchiveEntry entry = entries.nextElement();

        String name = entry.getName();
        try {
            System.out.println("current file: " + name);
            try (InputStream in = zipSecureFile.getInputStream(entry)) {
                Path path = Paths.get(destFolder, entry.getName());
                File f = path.toFile();
                if(entry.isDirectory()) {
                    if (!f.isDirectory() && !f.mkdirs()) {
                        throw new IOException("failed to create directory " + f);
                    }
                } else {
                    File parent = f.getParentFile();
                    if(!parent.isDirectory() && !parent.mkdirs()) {
                        throw new IOException("failed to create directory " + parent);
                    }
                    try (OutputStream out = Files.newOutputStream(f.toPath())) {
                        org.apache.poi.util.IOUtils.copy(in, out);
                    }
                }


            }
        } catch (Exception e) {
            throw new IOException("While handling entry " + name, e);
        }
        System.out.print("Completed Successfully!!");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM