String directoryName = fileName.substring(0, fileName.lastIndexOf(".")); | String directoryName = fileName.substring(0, fileName.lastIndexOf(".")); | ||||
Path pluginDirectory = filePath.resolveSibling(directoryName); | 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) { | if (!Files.exists(pluginDirectory) || pluginZipDate.compareTo(Files.getLastModifiedTime(pluginDirectory)) > 0) { | ||||
// expand '.zip' file | // expand '.zip' file | ||||
Unzip unzip = new Unzip(); | Unzip unzip = new Unzip(); | ||||
return pluginDirectory; | 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. | * Return true only if path is a zip file. | ||||
* | * |
import org.junit.jupiter.api.io.TempDir; | import org.junit.jupiter.api.io.TempDir; | ||||
import org.pf4j.test.PluginZip; | import org.pf4j.test.PluginZip; | ||||
import java.io.File; | |||||
import java.io.FileOutputStream; | |||||
import java.nio.file.Files; | import java.nio.file.Files; | ||||
import java.nio.file.Path; | import java.nio.file.Path; | ||||
import java.nio.file.Paths; | import java.nio.file.Paths; | ||||
import java.util.Collections; | 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.containsString; | ||||
import static org.hamcrest.CoreMatchers.equalTo; | import static org.hamcrest.CoreMatchers.equalTo; | ||||
import static org.junit.jupiter.api.Assertions.assertThrows; | import static org.junit.jupiter.api.Assertions.assertThrows; | ||||
import static org.junit.jupiter.api.Assertions.assertTrue; | import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
import static org.junit.jupiter.api.Assertions.fail; | import static org.junit.jupiter.api.Assertions.fail; | ||||
import static org.pf4j.util.FileUtils.expandIfZip; | |||||
public class LoadPluginsTest { | public class LoadPluginsTest { | ||||
import java.nio.file.Path; | import java.nio.file.Path; | ||||
import java.nio.file.Paths; | import java.nio.file.Paths; | ||||
import java.util.List; | 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.assertEquals; | ||||
import static org.junit.jupiter.api.Assertions.assertTrue; | import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
import static org.pf4j.util.FileUtils.expandIfZip; | |||||
public class FileUtilsTest { | public class FileUtilsTest { | ||||
} | } | ||||
return file; | 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!"); | |||||
} | |||||
} | |||||
} | } |