Add checks for known malicious expansion checksums before expansion load

This commit is contained in:
PiggyPiglet
2025-11-21 18:56:49 +08:00
parent 4a085682dc
commit 38da700168
5 changed files with 104 additions and 4 deletions

View File

@@ -21,7 +21,6 @@
package me.clip.placeholderapi;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import me.clip.placeholderapi.commands.PlaceholderCommandRouter;
@@ -34,6 +33,7 @@ import me.clip.placeholderapi.listeners.ServerLoadEventListener;
import me.clip.placeholderapi.scheduler.UniversalScheduler;
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
import me.clip.placeholderapi.updatechecker.UpdateChecker;
import me.clip.placeholderapi.util.MaliciousExpansionCheck;
import me.clip.placeholderapi.util.Msg;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics;
@@ -92,6 +92,7 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
private final TaskScheduler scheduler = UniversalScheduler.getScheduler(this);
private BukkitAudiences adventure;
private boolean malwareDetected = false;
/**
@@ -150,13 +151,23 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
@Override
public void onLoad() {
instance = this;
saveDefaultConfig();
malwareDetected = new MaliciousExpansionCheck(this).runChecks();
if (malwareDetected) {
return;
}
instance = this;
}
@Override
public void onEnable() {
if (malwareDetected) {
return;
}
setupCommand();
setupMetrics();
setupExpansions();

View File

@@ -23,6 +23,7 @@ package me.clip.placeholderapi.commands.impl.local;
import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.MaliciousExpansionCheck;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;
@@ -37,7 +38,9 @@ public final class CommandReload extends PlaceholderCommand {
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) {
plugin.reloadConf(sender);
if (!new MaliciousExpansionCheck(plugin).runChecks()) {
plugin.reloadConf(sender);
}
}
}

View File

@@ -86,4 +86,8 @@ public final class PlaceholderAPIConfig {
return plugin.getConfig().getString("boolean.false", "false");
}
public boolean detectMaliciousExpansions() {
return plugin.getConfig().getBoolean("detect_malicious_expansions", true);
}
}

View File

@@ -0,0 +1,81 @@
package me.clip.placeholderapi.util;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
public final class MaliciousExpansionCheck {
private static final String MESSAGE =
"\n###############################################\n" +
"###############################################\n" +
"PlaceholderAPI performs checks at startup and /papi reload for known malicious expansions. If you're seeing this message, there are the following malicious expansions in plugins/PlaceholderAPI/expansions.\n" +
"%s" +
"To prevent further infection PlaceholderAPI has stopped the server.\n" +
"Best practice is a complete system wipe and reinstall of your server software and plugins to be safe.\n" +
"###############################################\n" +
"###############################################";
private final PlaceholderAPIPlugin main;
public MaliciousExpansionCheck(@NotNull final PlaceholderAPIPlugin main) {
this.main = main;
}
public boolean runChecks() {
if (!main.getPlaceholderAPIConfig().detectMaliciousExpansions()) {
return false;
}
final File expansionsFolder = new File(main.getDataFolder(), "expansions");
if (!expansionsFolder.exists()) {
return false;
}
final Set<String> knownMalware;
try {
final String malware = Resources.toString(new URL("https://check.placeholderapi.com"), StandardCharsets.UTF_8);
knownMalware = Arrays.stream(malware.split("\n")).collect(Collectors.toSet());
} catch (Exception e) {
main.getLogger().log(Level.SEVERE, "Failed to download anti malware hash check list from https://check.placeholderapi.com", e);
return false;
}
final Set<String> malwarePaths = new HashSet<>();
for (File file : expansionsFolder.listFiles()) {
try {
final String hash = Hashing.sha256().hashBytes(Files.asByteSource(file).read()).toString();
if (knownMalware.contains(hash)) {
malwarePaths.add(file.getAbsolutePath());
}
} catch (Exception e) {
main.getLogger().log(Level.SEVERE, "Error occurred while trying to read " + file.getAbsolutePath(), e);
}
}
if (malwarePaths.isEmpty()) {
return false;
}
main.getLogger().severe(String.format(MESSAGE, malwarePaths.stream().map(p -> "HASH OF " + p + " MATCHES KNOWN MALICIOUS EXPANSION DELETE IMMEDIATELY\n").collect(Collectors.joining())));
main.getServer().shutdown();
return true;
}
}

View File

@@ -15,4 +15,5 @@ boolean:
'true': 'yes'
'false': 'no'
date_format: MM/dd/yy HH:mm:ss
detect_malicious_expansions: true
debug: false