Skip to content

Commit 451faf8

Browse files
committed
Project source code upload
1 parent 64efc0c commit 451faf8

7 files changed

Lines changed: 345 additions & 0 deletions

File tree

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Intellij IDEA
2+
.idea/
3+
*.iml
4+
out/
5+
6+
# Compiled class files
7+
*.class
8+
9+
# Logs
10+
*.log
11+
12+
# Package Files #
13+
*.jar
14+
*.war
15+
*.nar
16+
*.ear
17+
*.zip
18+
*.tar.gz
19+
*.rar
20+
21+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
22+
hs_err_pid*
23+
24+
*~
25+
26+
# temporary files which can be created if a process still has a handle open of a deleted file
27+
.fuse_hidden*
28+
29+
# KDE directory preferences
30+
.directory
31+
32+
# Linux trash folder which might appear on any partition or disk
33+
.Trash-*
34+
35+
# Maven
36+
target/
37+
.mvn/
38+
39+
# Common working directory
40+
run/

pom.xml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>ru.easydonate</groupId>
8+
<artifactId>exploitfix</artifactId>
9+
<version>1.0.0</version>
10+
<packaging>jar</packaging>
11+
12+
<name>EasyExploitFix</name>
13+
<description>Easy way to fix the Log4j2 exploit for unsupported server software</description>
14+
15+
<properties>
16+
<!-- Building -->
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
<java.version>1.8</java.version>
19+
20+
<!-- Dependencies -->
21+
<spigot.api.version>1.13-R0.1-SNAPSHOT</spigot.api.version>
22+
<protocollib.version>4.8.0-SNAPSHOT</protocollib.version>
23+
<log4j.core.version>2.14.1</log4j.core.version>
24+
<lombok.version>1.18.22</lombok.version>
25+
26+
<!-- Maven plugins -->
27+
<maven.compiler.plugin.version>3.8.1</maven.compiler.plugin.version>
28+
<maven.shade.plugin.version>3.2.4</maven.shade.plugin.version>
29+
</properties>
30+
31+
<repositories>
32+
<repository>
33+
<id>spigotmc-repo</id>
34+
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
35+
</repository>
36+
<repository>
37+
<id>sonatype</id>
38+
<url>https://oss.sonatype.org/content/groups/public/</url>
39+
</repository>
40+
<repository>
41+
<id>dmulloy2-repo</id>
42+
<url>https://repo.dmulloy2.net/repository/public/</url>
43+
</repository>
44+
</repositories>
45+
46+
<dependencies>
47+
<!-- Spigot API -->
48+
<dependency>
49+
<groupId>org.spigotmc</groupId>
50+
<artifactId>spigot-api</artifactId>
51+
<version>${spigot.api.version}</version>
52+
<scope>provided</scope>
53+
</dependency>
54+
55+
<!-- ProtocolLib -->
56+
<dependency>
57+
<groupId>com.comphenix.protocol</groupId>
58+
<artifactId>ProtocolLib</artifactId>
59+
<version>${protocollib.version}</version>
60+
<scope>provided</scope>
61+
</dependency>
62+
63+
<!-- Log4j Core -->
64+
<dependency>
65+
<groupId>org.apache.logging.log4j</groupId>
66+
<artifactId>log4j-core</artifactId>
67+
<version>${log4j.core.version}</version>
68+
<scope>provided</scope>
69+
</dependency>
70+
71+
<!-- Lombok -->
72+
<dependency>
73+
<groupId>org.projectlombok</groupId>
74+
<artifactId>lombok</artifactId>
75+
<version>${lombok.version}</version>
76+
<scope>provided</scope>
77+
</dependency>
78+
</dependencies>
79+
80+
<build>
81+
<finalName>${project.name}</finalName>
82+
<resources>
83+
<resource>
84+
<directory>src/main/resources</directory>
85+
<filtering>true</filtering>
86+
</resource>
87+
</resources>
88+
<plugins>
89+
<!-- Maven compiler plugin -->
90+
<plugin>
91+
<groupId>org.apache.maven.plugins</groupId>
92+
<artifactId>maven-compiler-plugin</artifactId>
93+
<version>${maven.compiler.plugin.version}</version>
94+
<configuration>
95+
<source>${java.version}</source>
96+
<target>${java.version}</target>
97+
</configuration>
98+
</plugin>
99+
100+
<!-- Maven shade plugin -->
101+
<plugin>
102+
<groupId>org.apache.maven.plugins</groupId>
103+
<artifactId>maven-shade-plugin</artifactId>
104+
<version>${maven.shade.plugin.version}</version>
105+
<configuration>
106+
<createDependencyReducedPom>false</createDependencyReducedPom>
107+
<filters>
108+
<filter>
109+
<artifact>*:*</artifact>
110+
<excludes>
111+
<exclude>META-INF/maven/</exclude>
112+
<exclude>META-INF/*.MF</exclude>
113+
</excludes>
114+
</filter>
115+
</filters>
116+
</configuration>
117+
<executions>
118+
<execution>
119+
<phase>package</phase>
120+
<goals>
121+
<goal>shade</goal>
122+
</goals>
123+
</execution>
124+
</executions>
125+
</plugin>
126+
</plugins>
127+
</build>
128+
</project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package ru.easydonate.exploitfix;
2+
3+
import org.bukkit.plugin.java.JavaPlugin;
4+
import ru.easydonate.exploitfix.listener.ProtocolChatPacketListener;
5+
import ru.easydonate.exploitfix.patcher.LoggerPatcher;
6+
7+
import java.util.regex.Pattern;
8+
9+
public final class ExploitFixPlugin extends JavaPlugin {
10+
11+
private static final Pattern DETECTOR_PATTERN = Pattern.compile("\\{*jndi:.*}");
12+
13+
@Override
14+
public void onLoad() {
15+
boolean hasPatched = new LoggerPatcher(this, DETECTOR_PATTERN).patch();
16+
if(!hasPatched)
17+
getServer().getPluginManager().disablePlugin(this);
18+
}
19+
20+
@Override
21+
public void onEnable() {
22+
new ProtocolChatPacketListener(this, DETECTOR_PATTERN);
23+
24+
getLogger().info("Exploit protection has been enabled!");
25+
}
26+
27+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package ru.easydonate.exploitfix.listener;
2+
3+
import com.comphenix.protocol.PacketType;
4+
import com.comphenix.protocol.ProtocolLibrary;
5+
import com.comphenix.protocol.events.ListenerPriority;
6+
import com.comphenix.protocol.events.PacketAdapter;
7+
import com.comphenix.protocol.events.PacketContainer;
8+
import com.comphenix.protocol.events.PacketEvent;
9+
import com.comphenix.protocol.wrappers.WrappedChatComponent;
10+
import net.md_5.bungee.api.chat.BaseComponent;
11+
import net.md_5.bungee.api.chat.TextComponent;
12+
import net.md_5.bungee.chat.ComponentSerializer;
13+
import org.bukkit.entity.Player;
14+
import org.bukkit.plugin.Plugin;
15+
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
19+
public final class ProtocolChatPacketListener extends PacketAdapter {
20+
21+
private final Pattern detectorPattern;
22+
23+
public ProtocolChatPacketListener(Plugin plugin, Pattern detectorPattern) {
24+
super(plugin, ListenerPriority.LOWEST,
25+
PacketType.Play.Client.CHAT,
26+
PacketType.Play.Server.CHAT
27+
);
28+
this.detectorPattern = detectorPattern;
29+
30+
ProtocolLibrary.getProtocolManager().addPacketListener(this);
31+
}
32+
33+
@Override
34+
public void onPacketSending(PacketEvent event) {
35+
if(event.getPacketType() != PacketType.Play.Server.CHAT)
36+
return;
37+
38+
PacketContainer packet = event.getPacket();
39+
WrappedChatComponent chatComponent = packet.getChatComponents().readSafely(0);
40+
if(chatComponent == null)
41+
return;
42+
43+
String componentJson = chatComponent.getJson();
44+
BaseComponent[] componentsArray = ComponentSerializer.parse(componentJson);
45+
String message = TextComponent.toPlainText(componentsArray);
46+
47+
Matcher matcher = detectorPattern.matcher(message.toLowerCase());
48+
if(matcher.find()) {
49+
event.setCancelled(true);
50+
packet.getChatComponents().write(0, WrappedChatComponent.fromText(""));
51+
}
52+
}
53+
54+
@Override
55+
public void onPacketReceiving(PacketEvent event) {
56+
if(event.getPacketType() != PacketType.Play.Client.CHAT)
57+
return;
58+
59+
PacketContainer packet = event.getPacket();
60+
String message = packet.getStrings().read(0);
61+
62+
Matcher matcher = detectorPattern.matcher(message.toLowerCase());
63+
if(matcher.find()) {
64+
Player player = event.getPlayer();
65+
getPlugin().getLogger().warning(player.getName() + " tried to use the Log4j2 exploit!");
66+
67+
event.setCancelled(true);
68+
packet.getStrings().write(0, "");
69+
}
70+
}
71+
72+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ru.easydonate.exploitfix.patcher;
2+
3+
import lombok.AllArgsConstructor;
4+
import org.apache.logging.log4j.core.LogEvent;
5+
import org.apache.logging.log4j.core.filter.AbstractFilter;
6+
7+
import java.util.regex.Pattern;
8+
9+
@AllArgsConstructor
10+
public final class LoggerFilter extends AbstractFilter {
11+
12+
private final Pattern detectorPattern;
13+
14+
@Override
15+
public Result filter(LogEvent event) {
16+
String message = event.getMessage().getFormattedMessage();
17+
if(message.contains("$") && detectorPattern.matcher(message.toLowerCase()).find())
18+
return Result.DENY;
19+
20+
return super.filter(event);
21+
}
22+
23+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package ru.easydonate.exploitfix.patcher;
2+
3+
import org.apache.logging.log4j.LogManager;
4+
import org.apache.logging.log4j.core.Appender;
5+
import org.apache.logging.log4j.core.Logger;
6+
import org.apache.logging.log4j.core.filter.AbstractFilterable;
7+
import org.bukkit.plugin.Plugin;
8+
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.regex.Pattern;
12+
import java.util.stream.Collectors;
13+
14+
public final class LoggerPatcher {
15+
16+
private final Plugin plugin;
17+
private final LoggerFilter loggerFilter;
18+
19+
public LoggerPatcher(Plugin plugin, Pattern detectorPattern) {
20+
this.plugin = plugin;
21+
this.loggerFilter = new LoggerFilter(detectorPattern);
22+
}
23+
24+
public boolean patch() {
25+
try {
26+
List<String> processedAppenders = patchAvailableLoggers();
27+
plugin.getLogger().info("Logger filter has been applied for appenders: " + String.join(", ", processedAppenders));
28+
return true;
29+
} catch (Throwable throwable) {
30+
plugin.getLogger().severe("Couldn't add filters to some logger(s).");
31+
plugin.getLogger().severe("Logger version is probably incompatible!");
32+
plugin.getLogger().severe("Details: " + throwable.getMessage());
33+
return false;
34+
}
35+
}
36+
37+
private List<String> patchAvailableLoggers() {
38+
Map<String, Appender> appenders = ((Logger) LogManager.getRootLogger()).getAppenders();
39+
40+
return appenders.values().stream()
41+
.filter((appender -> appender instanceof AbstractFilterable))
42+
.peek(appender -> ((AbstractFilterable) appender).addFilter(loggerFilter))
43+
.map(Appender::getName)
44+
.collect(Collectors.toList());
45+
}
46+
47+
}

src/main/resources/plugin.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name: ${project.name}
2+
main: ru.easydonate.exploitfix.ExploitFixPlugin
3+
version: ${project.version}
4+
author: SoKnight
5+
load: STARTUP
6+
depend: [ProtocolLib]
7+
description: ${project.description}
8+
api-version: 1.13

0 commit comments

Comments
 (0)