From 19155da999af59a948b6d6685f0dffabe9d0a3b6 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 8 Aug 2022 21:41:17 +0000 Subject: [PATCH] vuln-fix: Partial Path Traversal Vulnerability This fixes a partial path traversal vulnerability. Replaces `dir.getCanonicalPath().startsWith(parent.getCanonicalPath())`, which is vulnerable to partial path traversal attacks, with the more secure `dir.getCanonicalFile().toPath().startsWith(parent.getCanonicalFile().toPath())`. To demonstrate this vulnerability, consider `"/usr/outnot".startsWith("/usr/out")`. The check is bypassed although `/outnot` is not under the `/out` directory. It's important to understand that the terminating slash may be removed when using various `String` representations of the `File` object. For example, on Linux, `println(new File("/var"))` will print `/var`, but `println(new File("/var", "/")` will print `/var/`; however, `println(new File("/var", "/").getCanonicalPath())` will print `/var`. Weakness: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') Severity: Medium CVSSS: 6.1 Detection: CodeQL & OpenRewrite (https://public.moderne.io/recipes/org.openrewrite.java.security.PartialPathTraversalVulnerability) Reported-by: Jonathan Leitschuh Signed-off-by: Jonathan Leitschuh Bug-tracker: https://github.com/JLLeitschuh/security-research/issues/13 Co-authored-by: Moderne --- src/main/java/org/zeroturnaround/zip/ZipUtil.java | 2 +- .../java/org/zeroturnaround/zip/commons/FileUtilsV2_2.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/zeroturnaround/zip/ZipUtil.java b/src/main/java/org/zeroturnaround/zip/ZipUtil.java index 111ac85..3fda627 100644 --- a/src/main/java/org/zeroturnaround/zip/ZipUtil.java +++ b/src/main/java/org/zeroturnaround/zip/ZipUtil.java @@ -1140,7 +1140,7 @@ private static File checkDestinationFileForTraversal(File outputDir, String name * that the outputdir + name doesn't leave the outputdir. See * DirectoryTraversalMaliciousTest for details. */ - if (name.indexOf("..") != -1 && !destFile.getCanonicalPath().startsWith(outputDir.getCanonicalPath())) { + if (name.indexOf("..") != -1 && !destFile.getCanonicalFile().toPath().startsWith(outputDir.getCanonicalFile().toPath())) { throw new MaliciousZipException(outputDir, name); } return destFile; diff --git a/src/main/java/org/zeroturnaround/zip/commons/FileUtilsV2_2.java b/src/main/java/org/zeroturnaround/zip/commons/FileUtilsV2_2.java index 8fb5292..a589817 100644 --- a/src/main/java/org/zeroturnaround/zip/commons/FileUtilsV2_2.java +++ b/src/main/java/org/zeroturnaround/zip/commons/FileUtilsV2_2.java @@ -576,7 +576,7 @@ public static void copyDirectory(File srcDir, File destDir, // Cater for destination being directory within the source directory (see IO-141) List exclusionList = null; - if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) { + if (destDir.getCanonicalFile().toPath().startsWith(srcDir.getCanonicalFile().toPath())) { File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter); if (srcFiles != null && srcFiles.length > 0) { exclusionList = new ArrayList(srcFiles.length); @@ -997,7 +997,7 @@ public static void moveDirectory(File srcDir, File destDir) throws IOException { } boolean rename = srcDir.renameTo(destDir); if (!rename) { - if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) { + if (destDir.getCanonicalFile().toPath().startsWith(srcDir.getCanonicalFile().toPath())) { throw new IOException("Cannot move directory: "+srcDir+" to a subdirectory of itself: "+destDir); } copyDirectory( srcDir, destDir );