From 176a3d6e7dada68d7d09640ffeb2645ff2660148 Mon Sep 17 00:00:00 2001 From: Matej Pacan Date: Fri, 17 May 2024 13:35:11 +0200 Subject: [PATCH] Add advanced AI antihack to prevent private forceop exploits Just kidding. Simply catch the most popular commands and log them for manual review. Reasoning is simple, for example in Boss plugin you can create commands run after a Boss is spawned. If malicious actor gets access to the GUI (which happened with Vulcan anticheat) they can set the rule to run console-level commandsi ncluding OP. This is far from a full-standing protection but at least catches the first few attempts so staff is notified and can diagnose. Foundation's GUI are secure as they are not opened based on their title, but rather player-specific metadata tag. Contributions welcome. --- src/main/java/org/mineacademy/fo/Common.java | 62 ++++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mineacademy/fo/Common.java b/src/main/java/org/mineacademy/fo/Common.java index 2e75e6666..86760198e 100644 --- a/src/main/java/org/mineacademy/fo/Common.java +++ b/src/main/java/org/mineacademy/fo/Common.java @@ -1148,23 +1148,41 @@ public static void dispatchCommand(@Nullable CommandSender playerReplacement, @N if (command.isEmpty() || command.equalsIgnoreCase("none")) return; - if (command.startsWith("@announce ")) + if (command.startsWith("@announce ")) { + Valid.checkNotNull(playerReplacement, "Cannot use @announce without a player in: " + command); + Messenger.announce(playerReplacement, command.replace("@announce ", "")); + } + + else if (command.startsWith("@warn ")) { + Valid.checkNotNull(playerReplacement, "Cannot use @warn without a player in: " + command); - else if (command.startsWith("@warn ")) Messenger.warn(playerReplacement, command.replace("@warn ", "")); + } + + else if (command.startsWith("@error ")) { + Valid.checkNotNull(playerReplacement, "Cannot use @error without a player in: " + command); - else if (command.startsWith("@error ")) Messenger.error(playerReplacement, command.replace("@error ", "")); + } + + else if (command.startsWith("@info ")) { + Valid.checkNotNull(playerReplacement, "Cannot use @info without a player in: " + command); - else if (command.startsWith("@info ")) Messenger.info(playerReplacement, command.replace("@info ", "")); + } + + else if (command.startsWith("@question ")) { + Valid.checkNotNull(playerReplacement, "Cannot use @question without a player in: " + command); - else if (command.startsWith("@question ")) Messenger.question(playerReplacement, command.replace("@question ", "")); + } + + else if (command.startsWith("@success ")) { + Valid.checkNotNull(playerReplacement, "Cannot use @success without a player in: " + command); - else if (command.startsWith("@success ")) Messenger.success(playerReplacement, command.replace("@success ", "")); + } else { command = command.startsWith("/") && !command.startsWith("//") ? command.substring(1) : command; @@ -1174,6 +1192,8 @@ else if (command.startsWith("@success ")) if (!command.startsWith("tellraw")) command = colorize(command); + checkBlockedCommands(playerReplacement, command); + final String finalCommand = command; runLater(() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), finalCommand)); @@ -1194,11 +1214,41 @@ public static void dispatchCommandAsPlayer(@NonNull final Player playerSender, @ if (command.startsWith("/") && !command.startsWith("//")) command = command.substring(1); + checkBlockedCommands(playerSender, command); + final String finalCommand = command; runLater(() -> playerSender.performCommand(colorize(finalCommand.replace("{player}", resolveSenderName(playerSender))))); } + /* + * A pitiful attempt at blocking a few known commands which might have been used for malicious intent. + * We log the attempt to a file for manual review. + */ + private static boolean checkBlockedCommands(@Nullable CommandSender sender, String command) { + if (command.startsWith("gm ") || + command.startsWith("gmc ") || + command.startsWith("gms ") || + command.startsWith("gamemode ") || + command.startsWith("essentials:gamemode ") || + command.startsWith("essentials:gm ") || + command.startsWith("minecraft:gamemode ") || + command.startsWith("op ") || + command.startsWith("minecraft:op ") || + command.startsWith("lp ") || + command.startsWith("lp:") || + command.startsWith("luckperms ") || + command.startsWith("luckperms:")) { + + final String errorMessage = (sender != null ? sender.getName() : "Console") + " tried to run blocked command: " + command; + FileUtil.writeFormatted("blocked-commands.log", errorMessage); + + throw new FoException(errorMessage); + } + + return false; + } + // ------------------------------------------------------------------------------------------------------------ // Logging and error handling // ------------------------------------------------------------------------------------------------------------