From 880306e2fecdad3e34449644a7426d5d6a41d0cc Mon Sep 17 00:00:00 2001 From: Isaac Dawson <60455448+idawson-gl@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:20:18 +0900 Subject: [PATCH] Fix zipslip for jar --- .../java/decompiler/struct/ContextUnit.java | 6 +++- .../java/decompiler/CommandLineTest.java | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java index 5ddb6029ee..1806b51842 100644 --- a/src/org/jetbrains/java/decompiler/struct/ContextUnit.java +++ b/src/org/jetbrains/java/decompiler/struct/ContextUnit.java @@ -10,9 +10,11 @@ import org.jetbrains.java.decompiler.main.extern.IResultSaver; import org.jetbrains.java.decompiler.util.TextBuffer; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; @@ -131,12 +133,14 @@ public void save(final Function loader) throws IOException // directory entries for (String dirEntry : dirEntries) { + if (dirEntry.contains("..")) { continue; } sink.acceptDirectory(dirEntry); } // non-class entries for (IContextSource.Entry otherEntry : otherEntries) { - sink.acceptOther(otherEntry.path()); + String cleanedPath = FileSystems.getDefault().getPath("/"+otherEntry.path()).normalize().toString(); + sink.acceptOther(cleanedPath.substring(1)); // remove initial / needed for normalize to work } //Whooo threads! diff --git a/test/org/jetbrains/java/decompiler/CommandLineTest.java b/test/org/jetbrains/java/decompiler/CommandLineTest.java index d5aee16235..736f1da1b3 100644 --- a/test/org/jetbrains/java/decompiler/CommandLineTest.java +++ b/test/org/jetbrains/java/decompiler/CommandLineTest.java @@ -6,9 +6,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import static org.jetbrains.java.decompiler.DecompilerTestFixture.assertFilesEqual; +import static org.junit.jupiter.api.Assertions.assertFalse; public class CommandLineTest { private DecompilerTestFixture fixture; @@ -48,6 +53,30 @@ public void testJarToDir() { assertFilesEqual(fixture.getTestDataDir().resolve("bulk"), fixture.getTempDir().resolve("bulk_out")); } + @Test + public void testMaliciousJarToDir() throws IOException { + String out = fixture.getTempDir().resolve("bulk_out").toAbsolutePath().toString(); + String in = fixture.getTestDataDir().resolve("mal.jar").toAbsolutePath().toString(); + // create malicious jar if doesn't exist already + if (!new File(in).exists()) + { + String badFileName = new String("../../../../../../../../../../../tmp/test.txt"); + try (ZipOutputStream maliciousOut = new ZipOutputStream(new FileOutputStream(fixture.getTestDataDir().resolve("mal.jar").toAbsolutePath().toString()))) + { + ZipEntry entry = new ZipEntry(badFileName); + maliciousOut.putNextEntry(entry); + maliciousOut.write("womp womp".getBytes()); + maliciousOut.closeEntry(); + } + } + + ConsoleDecompiler.main(new String[]{in, out}); + + TextBuffer.checkLeaks(); + File f = new File("/tmp/test.txt"); + assertFalse(f.exists()); +} + @Test public void testZipToJar() { String out = fixture.getTempDir().resolve("bulk_out.jar").toAbsolutePath().toString();