azkaban-aplcache

Fix compression vulnerability. (#1779) * Fix compression

6/1/2018 8:38:04 PM
3.47.1

Details

diff --git a/az-core/src/main/java/azkaban/utils/Utils.java b/az-core/src/main/java/azkaban/utils/Utils.java
index 3f84e25..0a6fffa 100644
--- a/az-core/src/main/java/azkaban/utils/Utils.java
+++ b/az-core/src/main/java/azkaban/utils/Utils.java
@@ -199,6 +199,12 @@ public class Utils {
     while (entries.hasMoreElements()) {
       final ZipEntry entry = (ZipEntry) entries.nextElement();
       final File newFile = new File(dest, entry.getName());
+      if (!newFile.getCanonicalPath().startsWith(dest.getCanonicalPath())) {
+        throw new IOException(
+            "Extracting zip entry would have resulted in a file outside the specified destination"
+                + " directory.");
+      }
+
       if (entry.isDirectory()) {
         newFile.mkdirs();
       } else {
diff --git a/az-core/src/test/java/azkaban/utils/UtilsTest.java b/az-core/src/test/java/azkaban/utils/UtilsTest.java
new file mode 100644
index 0000000..7889b7c
--- /dev/null
+++ b/az-core/src/test/java/azkaban/utils/UtilsTest.java
@@ -0,0 +1,54 @@
+/*
+* Copyright 2018 LinkedIn Corp.
+*
+* Licensed under the Apache License, Version 2.0 (the “License”); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an “AS IS” BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*/
+package azkaban.utils;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import org.junit.Test;
+
+/**
+ * Test class for azkaban.utils.Utils
+ */
+public class UtilsTest {
+
+  /**
+   * An insecure zip file may hold path traversal filenames. During unzipping, the filename gets
+   * concatenated to the target directory. The final path may end up outside the target directory,
+   * causing security issues.
+   *
+   * @throws IOException the io exception
+   */
+  @Test
+  public void testUnzipInsecureFile() throws IOException {
+    final File zipFile = new File("myTest.zip");
+    try (final ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
+      final ZipEntry entry = new ZipEntry("../../../../../evil.txt");
+      out.putNextEntry(entry);
+    }
+
+    final ZipFile source = new ZipFile(zipFile);
+    final File dest = Utils.createTempDir();
+    assertThatThrownBy(() -> Utils.unzip(source, dest)).isInstanceOf(IOException.class)
+        .hasMessageContaining("Extracting zip entry would have resulted in a file outside the "
+            + "specified destination directory.");
+  }
+}