Browse Source

Add security checks to prevent directory traversal when decompressing files

pull/537/head
afeng2016-s 9 months ago
parent
commit
c1b03c92c0

+ 13
- 0
pf4j/src/main/java/org/pf4j/util/FileUtils.java View File

@@ -185,6 +185,11 @@ public final class FileUtils {
String directoryName = fileName.substring(0, fileName.lastIndexOf("."));
Path pluginDirectory = filePath.resolveSibling(directoryName);

// Check whether directory traversal risks exist in the path
if (!isInvalidPath(pluginDirectory)) {
throw new SecurityException("Invalid destination directory");
}

if (!Files.exists(pluginDirectory) || pluginZipDate.compareTo(Files.getLastModifiedTime(pluginDirectory)) > 0) {
// expand '.zip' file
Unzip unzip = new Unzip();
@@ -197,6 +202,14 @@ public final class FileUtils {
return pluginDirectory;
}

/**
* Use regular expressions to check whether the path contains a path traversal attempt
*/
private static boolean isInvalidPath(Path path) {
String pathStr = path.toString();
return pathStr.matches(".*\\.\\.(\\\\|/).*");
}

/**
* Return true only if path is a zip file.
*

+ 5
- 0
pf4j/src/test/java/org/pf4j/LoadPluginsTest.java View File

@@ -20,10 +20,14 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.pf4j.test.PluginZip;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
@@ -36,6 +40,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.pf4j.util.FileUtils.expandIfZip;

public class LoadPluginsTest {


+ 47
- 0
pf4j/src/test/java/org/pf4j/util/FileUtilsTest.java View File

@@ -24,9 +24,12 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.pf4j.util.FileUtils.expandIfZip;

public class FileUtilsTest {

@@ -95,4 +98,48 @@ public class FileUtilsTest {
}
return file;
}

/**
* Using the zipslip vulnerability, create a zip file.
*
* Save the created zip file in the D:/code/pf4j directory, if you do not have this path on your computer D drive, create it
* @throws Exception
*/
@Test
public void creatFile() throws Exception {

String maliciousFileName = "../../../../../../../malicious.sh";

// Build a malicious ZIP file
try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream("malicious.zip"))) {
ZipEntry entry = new ZipEntry(maliciousFileName);
zipOutputStream.putNextEntry(entry);
zipOutputStream.write("Malicious content".getBytes());
zipOutputStream.closeEntry();
}
}

/**
* Try to extract malicious.zip to the root directory of drive D on your computer.
* @throws Exception
*/
@Test
public void loadFile() throws Exception {
// Save the created zip file in the D:/code/pf4j directory, if you do not have this path on your computer D drive, create it
String maliciousZipPath = "D:\\code\\pf4j\\malicious.zip";

// Unzip file
expandIfZip(Paths.get(maliciousZipPath));
//loadPluginFromPath(Paths.get(maliciousZipPath));

// Check whether the specified file exists in the directory
File file = new File("D:\\malicious.sh");
if (file.exists()) {
System.out.println("file exists: Directory traversal successful!");
} else {
System.out.println("file does not exist!");
}
}


}

Loading…
Cancel
Save