Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public static JSONObject analysisFile(File file, EntityType entityType) {
} else if (file.getName().endsWith(FILE_SUFFIX.IPA_FILE)) {
res = analysisIpaFile(file);
} else if (file.getName().endsWith(FILE_SUFFIX.ZIP_FILE)) {
// check for zip bomb attacks
if (ZipBombChecker.isZipBomb(file)) {
throw new HydraLabRuntimeException("Zip file is too large, possible zip bomb attack.");
}
res = analysisZipFile(file);
}

Expand Down Expand Up @@ -112,11 +116,16 @@ private static JSONObject analysisIpaFile(File ipa) {
try {
String name, pkgName, version;
File zipFile = convertToZipFile(ipa, FILE_SUFFIX.IPA_FILE);
if (ZipBombChecker.isZipBomb(zipFile)) {
throw new HydraLabRuntimeException("Zip file is too large, possible zip bomb attack.");
}
Assert.notNull(zipFile, "Convert .ipa file to .zip file failed.");
File file = getPlistFromZip(zipFile, zipFile.getParent());
//Need third-party jar package dd-plist
Assert.notNull(file, "Analysis .ipa file failed.");
analysisPlist(file, res);
} catch (HydraLabRuntimeException ex) {
throw ex;
} catch (Exception e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

package com.microsoft.hydralab.common.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipBombChecker {
private static final long MAX_UNCOMPRESSED_SIZE = 1024 * 1024 * 1024; // 1024 MB
private static final int MAX_ENTRIES = 10000;
private static final int MAX_NESTING_DEPTH = 5;

public static boolean isZipBomb(File file) {
return isZipBomb(file, 0);
}

private static boolean isZipBomb(File file, int depth) {
if (depth > MAX_NESTING_DEPTH) {
return true;
}

long totalUncompressedSize = 0;
int entryCount = 0;

try (ZipInputStream zis = new ZipInputStream(new FileInputStream(file))) {
ZipEntry entry;
byte[] buffer = new byte[8192];

while ((entry = zis.getNextEntry()) != null) {
entryCount++;
if (entryCount > MAX_ENTRIES) {
return true;
}

if (!entry.isDirectory()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read;
while ((read = zis.read(buffer)) != -1) {
baos.write(buffer, 0, read);
totalUncompressedSize += read;
if (totalUncompressedSize > MAX_UNCOMPRESSED_SIZE) {
return true;
}
}
// check if the entry is a nested zip file
if (entry.getName().toLowerCase().endsWith(".zip")) {
byte[] nestedZipBytes = baos.toByteArray();
File tempZip = File.createTempFile("nested", ".zip");
try (FileOutputStream fos = new FileOutputStream(tempZip)) {
fos.write(nestedZipBytes);
}
boolean nestedBomb = isZipBomb(tempZip, depth + 1);
tempZip.delete();
if (nestedBomb) {
return true;
}
}
}
zis.closeEntry();
}
} catch (Exception e) {
return true; // If there's an error reading the zip, treat it as a potential zip bomb
}
return false;
}
}
Loading