From 451faf8d6c190e9dc22e74efa3f7bf416426dcf0 Mon Sep 17 00:00:00 2001 From: SoKnight Date: Fri, 10 Dec 2021 22:50:27 +0500 Subject: [PATCH] Project source code upload --- .gitignore | 40 ++++++ pom.xml | 128 ++++++++++++++++++ .../exploitfix/ExploitFixPlugin.java | 27 ++++ .../listener/ProtocolChatPacketListener.java | 72 ++++++++++ .../exploitfix/patcher/LoggerFilter.java | 23 ++++ .../exploitfix/patcher/LoggerPatcher.java | 47 +++++++ src/main/resources/plugin.yml | 8 ++ 7 files changed, 345 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/ru/easydonate/exploitfix/ExploitFixPlugin.java create mode 100644 src/main/java/ru/easydonate/exploitfix/listener/ProtocolChatPacketListener.java create mode 100644 src/main/java/ru/easydonate/exploitfix/patcher/LoggerFilter.java create mode 100644 src/main/java/ru/easydonate/exploitfix/patcher/LoggerPatcher.java create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3fa1adf --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Intellij IDEA +.idea/ +*.iml +out/ + +# Compiled class files +*.class + +# Logs +*.log + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# Maven +target/ +.mvn/ + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..39d28e8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,128 @@ + + + 4.0.0 + + ru.easydonate + exploitfix + 1.0.0 + jar + + EasyExploitFix + Easy way to fix the Log4j2 exploit for unsupported server software + + + + UTF-8 + 1.8 + + + 1.13-R0.1-SNAPSHOT + 4.8.0-SNAPSHOT + 2.14.1 + 1.18.22 + + + 3.8.1 + 3.2.4 + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + dmulloy2-repo + https://repo.dmulloy2.net/repository/public/ + + + + + + + org.spigotmc + spigot-api + ${spigot.api.version} + provided + + + + + com.comphenix.protocol + ProtocolLib + ${protocollib.version} + provided + + + + + org.apache.logging.log4j + log4j-core + ${log4j.core.version} + provided + + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + ${project.name} + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${java.version} + ${java.version} + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven.shade.plugin.version} + + false + + + *:* + + META-INF/maven/ + META-INF/*.MF + + + + + + + package + + shade + + + + + + + diff --git a/src/main/java/ru/easydonate/exploitfix/ExploitFixPlugin.java b/src/main/java/ru/easydonate/exploitfix/ExploitFixPlugin.java new file mode 100644 index 0000000..8e2c99c --- /dev/null +++ b/src/main/java/ru/easydonate/exploitfix/ExploitFixPlugin.java @@ -0,0 +1,27 @@ +package ru.easydonate.exploitfix; + +import org.bukkit.plugin.java.JavaPlugin; +import ru.easydonate.exploitfix.listener.ProtocolChatPacketListener; +import ru.easydonate.exploitfix.patcher.LoggerPatcher; + +import java.util.regex.Pattern; + +public final class ExploitFixPlugin extends JavaPlugin { + + private static final Pattern DETECTOR_PATTERN = Pattern.compile("\\{*jndi:.*}"); + + @Override + public void onLoad() { + boolean hasPatched = new LoggerPatcher(this, DETECTOR_PATTERN).patch(); + if(!hasPatched) + getServer().getPluginManager().disablePlugin(this); + } + + @Override + public void onEnable() { + new ProtocolChatPacketListener(this, DETECTOR_PATTERN); + + getLogger().info("Exploit protection has been enabled!"); + } + +} diff --git a/src/main/java/ru/easydonate/exploitfix/listener/ProtocolChatPacketListener.java b/src/main/java/ru/easydonate/exploitfix/listener/ProtocolChatPacketListener.java new file mode 100644 index 0000000..8fd1dbd --- /dev/null +++ b/src/main/java/ru/easydonate/exploitfix/listener/ProtocolChatPacketListener.java @@ -0,0 +1,72 @@ +package ru.easydonate.exploitfix.listener; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.chat.ComponentSerializer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class ProtocolChatPacketListener extends PacketAdapter { + + private final Pattern detectorPattern; + + public ProtocolChatPacketListener(Plugin plugin, Pattern detectorPattern) { + super(plugin, ListenerPriority.LOWEST, + PacketType.Play.Client.CHAT, + PacketType.Play.Server.CHAT + ); + this.detectorPattern = detectorPattern; + + ProtocolLibrary.getProtocolManager().addPacketListener(this); + } + + @Override + public void onPacketSending(PacketEvent event) { + if(event.getPacketType() != PacketType.Play.Server.CHAT) + return; + + PacketContainer packet = event.getPacket(); + WrappedChatComponent chatComponent = packet.getChatComponents().readSafely(0); + if(chatComponent == null) + return; + + String componentJson = chatComponent.getJson(); + BaseComponent[] componentsArray = ComponentSerializer.parse(componentJson); + String message = TextComponent.toPlainText(componentsArray); + + Matcher matcher = detectorPattern.matcher(message.toLowerCase()); + if(matcher.find()) { + event.setCancelled(true); + packet.getChatComponents().write(0, WrappedChatComponent.fromText("")); + } + } + + @Override + public void onPacketReceiving(PacketEvent event) { + if(event.getPacketType() != PacketType.Play.Client.CHAT) + return; + + PacketContainer packet = event.getPacket(); + String message = packet.getStrings().read(0); + + Matcher matcher = detectorPattern.matcher(message.toLowerCase()); + if(matcher.find()) { + Player player = event.getPlayer(); + getPlugin().getLogger().warning(player.getName() + " tried to use the Log4j2 exploit!"); + + event.setCancelled(true); + packet.getStrings().write(0, ""); + } + } + +} diff --git a/src/main/java/ru/easydonate/exploitfix/patcher/LoggerFilter.java b/src/main/java/ru/easydonate/exploitfix/patcher/LoggerFilter.java new file mode 100644 index 0000000..6190da8 --- /dev/null +++ b/src/main/java/ru/easydonate/exploitfix/patcher/LoggerFilter.java @@ -0,0 +1,23 @@ +package ru.easydonate.exploitfix.patcher; + +import lombok.AllArgsConstructor; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.filter.AbstractFilter; + +import java.util.regex.Pattern; + +@AllArgsConstructor +public final class LoggerFilter extends AbstractFilter { + + private final Pattern detectorPattern; + + @Override + public Result filter(LogEvent event) { + String message = event.getMessage().getFormattedMessage(); + if(message.contains("$") && detectorPattern.matcher(message.toLowerCase()).find()) + return Result.DENY; + + return super.filter(event); + } + +} diff --git a/src/main/java/ru/easydonate/exploitfix/patcher/LoggerPatcher.java b/src/main/java/ru/easydonate/exploitfix/patcher/LoggerPatcher.java new file mode 100644 index 0000000..4454359 --- /dev/null +++ b/src/main/java/ru/easydonate/exploitfix/patcher/LoggerPatcher.java @@ -0,0 +1,47 @@ +package ru.easydonate.exploitfix.patcher; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.filter.AbstractFilterable; +import org.bukkit.plugin.Plugin; + +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public final class LoggerPatcher { + + private final Plugin plugin; + private final LoggerFilter loggerFilter; + + public LoggerPatcher(Plugin plugin, Pattern detectorPattern) { + this.plugin = plugin; + this.loggerFilter = new LoggerFilter(detectorPattern); + } + + public boolean patch() { + try { + List processedAppenders = patchAvailableLoggers(); + plugin.getLogger().info("Logger filter has been applied for appenders: " + String.join(", ", processedAppenders)); + return true; + } catch (Throwable throwable) { + plugin.getLogger().severe("Couldn't add filters to some logger(s)."); + plugin.getLogger().severe("Logger version is probably incompatible!"); + plugin.getLogger().severe("Details: " + throwable.getMessage()); + return false; + } + } + + private List patchAvailableLoggers() { + Map appenders = ((Logger) LogManager.getRootLogger()).getAppenders(); + + return appenders.values().stream() + .filter((appender -> appender instanceof AbstractFilterable)) + .peek(appender -> ((AbstractFilterable) appender).addFilter(loggerFilter)) + .map(Appender::getName) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..923f280 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,8 @@ +name: ${project.name} +main: ru.easydonate.exploitfix.ExploitFixPlugin +version: ${project.version} +author: SoKnight +load: STARTUP +depend: [ProtocolLib] +description: ${project.description} +api-version: 1.13 \ No newline at end of file