From 45a637f33b73b02a6612adf4bbe7bb5b7a700655 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 9 Sep 2023 16:09:46 +0100 Subject: [PATCH] feat: allow to disable zip security checks (#1579, #980) --- .../jadx/api/plugins/utils/ZipSecurity.java | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/jadx-core/src/main/java/jadx/api/plugins/utils/ZipSecurity.java b/jadx-core/src/main/java/jadx/api/plugins/utils/ZipSecurity.java index adb7a0ad2..22df2c1d6 100644 --- a/jadx-core/src/main/java/jadx/api/plugins/utils/ZipSecurity.java +++ b/jadx-core/src/main/java/jadx/api/plugins/utils/ZipSecurity.java @@ -5,6 +5,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; +import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.zip.ZipEntry; @@ -17,6 +18,8 @@ import org.slf4j.LoggerFactory; public class ZipSecurity { private static final Logger LOG = LoggerFactory.getLogger(ZipSecurity.class); + private static final boolean DISABLE_CHECKS = Objects.equals(System.getenv("JADX_DISABLE_ZIP_SECURITY"), "true"); + /** * size of uncompressed zip entry shouldn't be bigger of compressed in * {@link #ZIP_BOMB_DETECTION_FACTOR} times @@ -33,44 +36,55 @@ public class ZipSecurity { private ZipSecurity() { } - private static boolean isInSubDirectoryInternal(File baseDir, File canonFile) { - if (canonFile == null) { - return false; + private static boolean isInSubDirectoryInternal(File baseDir, File file) { + File current = file; + while (true) { + if (current == null) { + return false; + } + if (current.equals(baseDir)) { + return true; + } + current = current.getParentFile(); } - if (canonFile.equals(baseDir)) { - return true; - } - return isInSubDirectoryInternal(baseDir, canonFile.getParentFile()); } public static boolean isInSubDirectory(File baseDir, File file) { + if (DISABLE_CHECKS) { + return true; + } try { - file = file.getCanonicalFile(); - baseDir = baseDir.getCanonicalFile(); + return isInSubDirectoryInternal(baseDir.getCanonicalFile(), file.getCanonicalFile()); } catch (IOException e) { return false; } - return isInSubDirectoryInternal(baseDir, file); } - // checks that entry name contains no any traversals - // and prevents cases like "../classes.dex", to limit output only to the specified directory + /** + * Checks that entry name contains no any traversals and prevents cases like "../classes.dex", + * to limit output only to the specified directory + */ public static boolean isValidZipEntryName(String entryName) { + if (DISABLE_CHECKS) { + return true; + } try { File currentPath = CommonFileUtils.CWD; File canonical = new File(currentPath, entryName).getCanonicalFile(); if (isInSubDirectoryInternal(currentPath, canonical)) { return true; } - LOG.error("Invalid file name or path traversal attack detected: {}", entryName); - return false; } catch (Exception e) { - LOG.error("Invalid file name or path traversal attack detected: {}", entryName); - return false; + // check failed } + LOG.error("Invalid file name or path traversal attack detected: {}", entryName); + return false; } public static boolean isZipBomb(ZipEntry entry) { + if (DISABLE_CHECKS) { + return false; + } long compressedSize = entry.getCompressedSize(); long uncompressedSize = entry.getSize(); boolean invalidSize = (compressedSize < 0) || (uncompressedSize < 0); @@ -90,6 +104,9 @@ public class ZipSecurity { } public static InputStream getInputStreamForEntry(ZipFile zipFile, ZipEntry entry) throws IOException { + if (DISABLE_CHECKS) { + return new BufferedInputStream(zipFile.getInputStream(entry)); + } InputStream in = zipFile.getInputStream(entry); LimitedInputStream limited = new LimitedInputStream(in, entry.getSize()); return new BufferedInputStream(limited); @@ -112,7 +129,7 @@ public class ZipSecurity { return result; } entriesProcessed++; - if (entriesProcessed > MAX_ENTRIES_COUNT) { + if (!DISABLE_CHECKS && entriesProcessed > MAX_ENTRIES_COUNT) { throw new IllegalStateException("Zip entries count limit exceeded: " + MAX_ENTRIES_COUNT + ", last entry: " + entry.getName()); }