Skip to content

Commit

Permalink
Add advanced AI antihack to prevent private forceop exploits
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kangarko committed May 17, 2024
1 parent 4a1c14a commit 176a3d6
Showing 1 changed file with 56 additions and 6 deletions.
62 changes: 56 additions & 6 deletions src/main/java/org/mineacademy/fo/Common.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
Expand All @@ -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
// ------------------------------------------------------------------------------------------------------------
Expand Down

0 comments on commit 176a3d6

Please sign in to comment.