├── logchecker.png ├── src └── club │ └── koupah │ └── logchecker │ ├── impl │ ├── GenericChecker.java │ ├── VanillaChecker.java │ ├── BadlionChecker.java │ ├── LunarChecker.java │ └── MultiMCChecker.java │ ├── ExploitChecker.java │ ├── Checker.java │ └── utils │ └── Utils.java └── README.md /logchecker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Koupah/MC-Log4J-Exploit-Checker/HEAD/logchecker.png -------------------------------------------------------------------------------- /src/club/koupah/logchecker/impl/GenericChecker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker.impl; 2 | 3 | import java.io.File; 4 | import club.koupah.logchecker.Checker; 5 | import club.koupah.logchecker.utils.Utils; 6 | 7 | public class GenericChecker extends Checker { 8 | 9 | public GenericChecker() { 10 | super("Check Other Logs (Spigot, Bungee, Forge, etc)"); 11 | } 12 | 13 | @Override 14 | public void check() { 15 | System.out.println("Please provide a directory to check."); 16 | System.out.println(" - Note: Make sure you provide the directory containing the logs, not the parent folder!"); 17 | 18 | spacer(); 19 | 20 | File directory = Utils.getDirectoryInput(); 21 | 22 | spacer(); 23 | 24 | System.out.println("Press Enter to start scanning!"); 25 | Utils.waitForEnter(); 26 | 27 | scanLogs(directory, "the program these logs belong to was running"); 28 | 29 | returnHome(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/club/koupah/logchecker/impl/VanillaChecker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker.impl; 2 | 3 | import java.io.File; 4 | 5 | import club.koupah.logchecker.Checker; 6 | import club.koupah.logchecker.ExploitChecker; 7 | import club.koupah.logchecker.utils.Utils; 8 | 9 | public class VanillaChecker extends Checker { 10 | 11 | public VanillaChecker() { 12 | super("Check .minecraft logs"); 13 | } 14 | 15 | @Override 16 | public void check() { 17 | requireMinecraftFolder(ExploitChecker.getInstance().getArguments()); 18 | 19 | System.out.println("Your '.minecraft' directory is set to \"" + minecraftDirectory + "\""); 20 | 21 | if (Utils.containsFolder(minecraftFolder, "logs")) { 22 | 23 | System.out.println("Press Enter to start scanning!"); 24 | Utils.waitForEnter(); 25 | 26 | scanLogs(new File(minecraftFolder, "logs"), "playing Vanilla Minecraft"); 27 | } else { 28 | System.out.println("Your Minecraft Folder doesn't contain a folder called \"logs\" in it!"); 29 | System.out 30 | .println("If this is a mistake, please re-run this utility and specify a custom Minecraft Directory!"); 31 | } 32 | 33 | returnHome(); 34 | } 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/club/koupah/logchecker/impl/BadlionChecker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker.impl; 2 | 3 | import java.io.File; 4 | import club.koupah.logchecker.Checker; 5 | import club.koupah.logchecker.ExploitChecker; 6 | import club.koupah.logchecker.utils.Utils; 7 | 8 | public class BadlionChecker extends Checker { 9 | 10 | public BadlionChecker() { 11 | super("Check Badlion Client logs"); 12 | } 13 | 14 | @Override 15 | public void check() { 16 | requireMinecraftFolder(ExploitChecker.getInstance().getArguments()); 17 | 18 | System.out.println("Your '.minecraft' directory is set to \"" + minecraftDirectory + "\""); 19 | 20 | File badlionLogs = new File(minecraftFolder, "logs/blclient/minecraft"); 21 | 22 | System.out.println("Badlion Client logs folder: \"" + badlionLogs.getAbsolutePath() + "\""); 23 | 24 | if (badlionLogs.exists()) { 25 | 26 | System.out.println("Press Enter to start scanning!"); 27 | Utils.waitForEnter(); 28 | 29 | scanLogs(badlionLogs, "on Badlion Client"); 30 | } else { 31 | System.out.println("You do not seem to have a Badlion Client logs folder!"); 32 | System.out.println( 33 | "Have you actually played on Badlion Client? Please double check you did everything correctly!"); 34 | } 35 | 36 | returnHome(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/club/koupah/logchecker/ExploitChecker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import club.koupah.logchecker.impl.BadlionChecker; 8 | import club.koupah.logchecker.impl.GenericChecker; 9 | import club.koupah.logchecker.impl.LunarChecker; 10 | import club.koupah.logchecker.impl.MultiMCChecker; 11 | import club.koupah.logchecker.impl.VanillaChecker; 12 | import club.koupah.logchecker.utils.Utils; 13 | 14 | public class ExploitChecker extends Checker { 15 | 16 | /* 17 | * TODO: Clean this code up, clean up Checker code too 18 | * 19 | * SURELY someone forks and makes a nice PR to clean this up xo 20 | */ 21 | 22 | List checks; 23 | 24 | private static ExploitChecker INSTANCE; 25 | 26 | public String[] arguments; 27 | 28 | public static void main(String[] args) { 29 | System.out.println("Initializing MC Exploit Checker with " + args.length + " provided argument(s)."); 30 | 31 | new ExploitChecker(args).check(); 32 | } 33 | 34 | public ExploitChecker(String[] args) { 35 | super("ExploitChecker"); 36 | INSTANCE = this; 37 | this.arguments = args; 38 | 39 | checks = new ArrayList(Arrays.asList(new VanillaChecker(), new MultiMCChecker(), new GenericChecker())); 40 | 41 | if (Utils.isWindows()) { 42 | checks.addAll(Arrays.asList(new BadlionChecker(), new LunarChecker())); 43 | } 44 | 45 | System.out.println("Created new ExploitChecker. [" + checks.size() + " checkers available on this platform]"); 46 | 47 | } 48 | 49 | public void lunarCheck() { 50 | 51 | } 52 | 53 | @Override 54 | public void check() { 55 | 56 | while (true) { 57 | spacer(); 58 | 59 | System.out.println("What would you like to do?"); 60 | for (int i = 0; i < checks.size(); i++) { 61 | System.out.println((i + 1) + ". " + checks.get(i).getName()); 62 | } 63 | 64 | System.out.println((checks.size() + 1) + ". Exit"); 65 | 66 | int choice = Utils.getNumberInput(1, checks.size()+1) - 1; 67 | spacer(); 68 | 69 | if (choice >= checks.size()) { 70 | exit(); 71 | } else { 72 | checks.get(choice).check(); 73 | } 74 | 75 | } 76 | } 77 | 78 | public static ExploitChecker getInstance() { 79 | return ExploitChecker.INSTANCE; 80 | } 81 | 82 | public String[] getArguments() { 83 | return this.arguments; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/club/koupah/logchecker/impl/LunarChecker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker.impl; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | import club.koupah.logchecker.Checker; 7 | import club.koupah.logchecker.utils.Utils; 8 | 9 | public class LunarChecker extends Checker { 10 | 11 | public LunarChecker() { 12 | super("Check Lunar Client logs"); 13 | } 14 | 15 | @Override 16 | public void check() { 17 | File lunarLogs = new File("C:\\Users\\" + System.getProperty("user.name") + "\\.lunarclient\\offline"); 18 | 19 | if (lunarLogs.exists() && lunarLogs.isDirectory()) { 20 | System.out.println("Lunar Logs directory: \"" + lunarLogs.getAbsolutePath() + "\""); 21 | 22 | System.out.println("Press Enter to start scanning!"); 23 | Utils.waitForEnter(); 24 | 25 | spacer(); 26 | System.out.println("Log scanning has begun..."); 27 | System.out.println(" - Note: This can take anywhere from 10 seconds to 2 minutes"); 28 | spacer(); 29 | 30 | int logsChecked = 0; 31 | int foldersChecked = 0; 32 | int exploits = 0; 33 | 34 | contents: for (File file : lunarLogs.listFiles()) { 35 | 36 | if (!file.isDirectory() || !file.getName().contains(".")) // Versions all contain a '.' 37 | continue; 38 | 39 | if (Utils.containsFolder(file, "logs")) { 40 | 41 | System.out.println("Checking logs for Lunar Client v" + file.getName() + "..."); 42 | File verLogs = new File(file, "logs"); 43 | 44 | List containing = Utils.checkAllFiles(verLogs); 45 | 46 | if (containing.isEmpty()) { 47 | System.out.println("Lunar Client v" + file.getName() + " logs are clean."); 48 | } else { 49 | System.out.println("Use of the Log4J exploit was found in " + containing.size() 50 | + " log files for Lunar Client v" + file.getName() + "!"); 51 | System.out.println("Would you like to view a list of all the files that potentially contain the exploit?"); 52 | 53 | if (Utils.getBooleanInput()) { 54 | System.out.println("------------"); 55 | for (File exploitInside : containing) 56 | System.out.println("- " + exploitInside.getAbsolutePath()); 57 | System.out.println("------------"); 58 | System.out.println(" "); 59 | } 60 | 61 | exploits += containing.size(); 62 | 63 | System.out.println("Do you want to continue searching Lunar Client logs?"); 64 | if (!Utils.getBooleanInput()) { 65 | break contents; 66 | } 67 | } 68 | 69 | foldersChecked++; 70 | logsChecked += verLogs.listFiles().length; 71 | 72 | } else { 73 | System.out.println("Skipping Lunar Client v" + file.getName() + " as it has no logs folder."); 74 | } 75 | 76 | } 77 | 78 | System.out.println("Lunar Client log scanning has completed."); 79 | System.out.println("Results: "); 80 | System.out.println(" - Checked: " + logsChecked + " log files in " + foldersChecked + " folders"); 81 | System.out.println(" - Potential Exploit: " + exploits + " log files that potentially contain the exploit"); 82 | 83 | printExplanation(exploits, "on Lunar Client"); 84 | 85 | } else { 86 | System.out.println("Lunar Client logs folder does not appear to exist! (" + lunarLogs.getAbsolutePath() + ")"); 87 | System.out.println("Please make sure you've actually played Lunar Client!"); 88 | } 89 | 90 | returnHome(); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MC-Log4J-Exploit-Checker 2 | Checks your Minecraft logs folder (including zipped logs) to potentially see if you've been a victim of the recent [Log4J exploit](https://unit42.paloaltonetworks.com/apache-log4j-vulnerability-cve-2021-44228/)! 3 | You can now also check your [MultiMC](https://multimc.org/) logs on all platforms alongside [Badlion](https://client.badlion.net/) & [Lunar](https://www.lunarclient.com/) client logs on Windows! 4 | 5 | See how to [use this](#usage), [capabilities](#capabilities) and more in this README. 6 | 7 | **Please also read the [disclaimer](#disclaimer) at the bottom of this README file.** 8 | 9 | ![LogChecker Interface](/logchecker.png) 10 | 11 | ## Capabilities 12 | 13 | ### What can this do? 14 | This tool it capable of detecting if someone has attempted to use this exploit on you. 15 | This tool can go through your logs, and it **does** unzip any zipped (.gz) logs automatically in order to check them aswell. 16 | This tool is also able to tell you what files the exploit was detected in and tells you the lines that it detected the exploit on. 17 | 18 | ### What can't this do? 19 | This tool can **not** determine for certain that you were not a victim of the exploit. 20 | This tool also can not determine, if any, what code was run by the exploit nor the severity of it. 21 | 22 | ### So what is the purpose of this tool? 23 | Just because this tool can not certainly tell you if you were affected, it can tell you if any attempts were made whether or not they were successful. 24 | This tool allows you to take action **now** instead of waiting for something bad to potentially happen. 25 | 26 | ## Usage 27 | 28 | Compiled Jar and other files can be downloaded from [Releases](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases) 29 | 30 | ### Windows 31 | If on Windows you can run this two separate ways: 32 | Method 1: Downloading [LogChecker.exe](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/LogChecker.exe) from [Releases](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases) and run it 33 | 34 | OR if you don't trust random `.exe` files, and you shouldn't, you can use Method 2. 35 | 36 | Method 2: Download [LogChecker.jar](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/LogChecker.jar) and [start.bat](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/start.bat) from [Releases](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/), make sure they're both in the same folder, then run `start.bat` 37 | 38 | ### Mac/Linux 39 | Simply download [LogChecker.jar](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/LogChecker.jar) and run it in a terminal/console/whatever you guys call it! 40 | I haven't tested this on either platform but, I added premade selections for both platforms as follows. 41 | `~/Library/Application Support/minecraft` Mac Default 42 | `~/.minecraft` Linux Default 43 | 44 | ## Notes 45 | 1. I put this together fairly quickly, if you have any suggestions or issues then please open an Issue on GitHub or contact me via Discord (Koupah#5129) 46 | 2. The [LogChecker.exe](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/LogChecker.exe) is just a wrapped Jar file, you still need Java to run it 47 | 3. You do not have to run my compiled [jar file](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/LogChecker.jar). I encourage you to look through the source and compile it yourself. It's all [here](https://github.com/Koupah/MC-Log4J-Exploit-Checker/tree/main/src/club/koupah/logchecker). 48 | 4. You may also run [LogChecker.jar](https://github.com/Koupah/MC-Log4J-Exploit-Checker/releases/latest/download/LogChecker.jar) with an additional argument to specify your `.minecraft` folder location 49 | 50 | ## Disclaimer 51 | If there are no results it doesn't guarantee you were not affected as some attackers could have modified your logs. 52 | You have to remember that this is Minecraft, most attackers are more than likely script kiddies copy and pasting an exploit someone else has provided them. 53 | In a lot of cases they won't clear/modify your logs. 54 | 55 | If attempts at the exploit are found, it is your duty to investigate them and determine if they were successful, malicious, etc. 56 | 57 | I am not responsible for any actions you may or may not take after using my tool. 58 | It is not my responsibility if you rely solely upon this tool to determine if you were affected. 59 | -------------------------------------------------------------------------------- /src/club/koupah/logchecker/impl/MultiMCChecker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker.impl; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import club.koupah.logchecker.Checker; 8 | import club.koupah.logchecker.utils.Utils; 9 | 10 | public class MultiMCChecker extends Checker { 11 | 12 | public MultiMCChecker() { 13 | super("Check MultiMC logs"); 14 | } 15 | 16 | @Override 17 | public void check() { 18 | System.out.println("Please provide the directory of your MultiMC launcher."); 19 | System.out.println(" Note: The MultiMC folder should contain a folder named \"instances\""); 20 | 21 | File folder = Utils.getDirectoryInput(); 22 | 23 | if (folder.exists()) { 24 | if (Utils.containsFolder(folder, "instances")) { 25 | File instances = new File(folder, "instances"); 26 | 27 | List versionFolders = new ArrayList(); 28 | 29 | for (File ver : instances.listFiles()) { 30 | if (ver.isDirectory() && !ver.getName().startsWith("_")) 31 | versionFolders.add(ver); 32 | } 33 | 34 | System.out.println("Detected " + versionFolders.size() + " MultiMC instance(s)!"); 35 | 36 | System.out.println("Press Enter to start scanning!"); 37 | Utils.waitForEnter(); 38 | 39 | spacer(); 40 | System.out.println("Log scanning has begun..."); 41 | System.out.println(" - Note: This can take anywhere from 10 seconds to 2 minutes"); 42 | spacer(); 43 | 44 | if (!versionFolders.isEmpty()) { 45 | int logsChecked = 0; 46 | int versionsChecked = 0; 47 | int exploits = 0; 48 | 49 | contents: for (File version : versionFolders) { 50 | versionsChecked++; 51 | File mcFolder = getFirstFolder(version, "minecraft"); // '.minecraft' or 'minecraft' (I think linux or 52 | // mac doesnt use the '.') 53 | 54 | if (mcFolder == null) { 55 | System.out 56 | .println("Skipping " + version.getName() + " (Couldn't find .minecraft/minecraft folder)"); 57 | } else { 58 | if (Utils.containsFolder(mcFolder, "logs")) { 59 | File logs = new File(mcFolder, "logs"); 60 | List containing = Utils.checkAllFiles(logs); 61 | 62 | if (containing.isEmpty()) { 63 | System.out.println("MultiMC instance " + version.getName() + "'s logs are clean."); 64 | } else { 65 | System.out.println("Potential use of the Log4J exploit was found in " + containing.size() 66 | + " log files for MultiMC instance " + version.getName() + "!"); 67 | System.out.println("Would you like to view a list of all the files that potentially contain the exploit?"); 68 | 69 | if (Utils.getBooleanInput()) { 70 | System.out.println("------------"); 71 | for (File exploitInside : containing) 72 | System.out.println("- " + exploitInside.getAbsolutePath()); 73 | System.out.println("------------"); 74 | System.out.println(" "); 75 | } 76 | 77 | exploits += containing.size(); 78 | 79 | System.out.println("Do you want to continue searching MultiMC logs?"); 80 | if (!Utils.getBooleanInput()) { 81 | break contents; 82 | } 83 | } 84 | 85 | logsChecked += logs.listFiles().length; 86 | 87 | } else { 88 | System.out.println("Skipping " + version.getName() + " as it doesn't have a logs folder"); 89 | } 90 | } 91 | } 92 | 93 | System.out.println("MultiMC log scanning has completed."); 94 | System.out.println("Results: "); 95 | System.out.println(" - Checked: " + logsChecked + " log files in " + versionsChecked + " instances"); 96 | System.out.println(" - Potential Exploit: " + exploits + " log files that potentially contain the exploit"); 97 | 98 | printExplanation(exploits, "using MutliMC"); 99 | 100 | } 101 | 102 | } else { 103 | System.out.println("That folder doesn't contain an \"instances\" folder!"); 104 | System.out.println("Please double check that you've provided the right directory and try again."); 105 | } 106 | } else { 107 | System.out.println("That folder doesn't exist!"); 108 | } 109 | 110 | returnHome(); 111 | } 112 | 113 | 114 | private File getFirstFolder(File parent, String endingWith) { 115 | for (File child : parent.listFiles()) 116 | if (child.isDirectory() && child.getName().endsWith(endingWith)) 117 | return child; 118 | 119 | return null; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/club/koupah/logchecker/Checker.java: -------------------------------------------------------------------------------- 1 | package club.koupah.logchecker; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.Scanner; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import club.koupah.logchecker.utils.Utils; 11 | 12 | public abstract class Checker { 13 | 14 | public static Scanner input = new Scanner(System.in); 15 | 16 | public static ExploitChecker INSTANCE; 17 | public static String typicalFolderName = ".minecraft"; 18 | 19 | public static String minecraftDirectory; 20 | public static File minecraftFolder; 21 | 22 | public String name; 23 | 24 | public Checker(String name) { 25 | this.name = name; 26 | } 27 | 28 | public abstract void check(); 29 | 30 | public void exit() { 31 | spacer(); 32 | System.out.println("Exiting."); 33 | System.exit(0); 34 | } 35 | 36 | public void spacer() { 37 | for (int i = 0; i < 2; i++) 38 | System.out.println(" "); 39 | } 40 | 41 | public void requireMinecraftFolder(String[] args) { 42 | if (minecraftDirectory == null) { 43 | if (args.length > 0) { 44 | minecraftDirectory = args[0]; 45 | } else { 46 | if (Utils.isWindows()) { 47 | System.out.println("Using default Windows '.minecraft' folder directory as one hasn't been specified."); 48 | minecraftDirectory = System.getenv("APPDATA") + File.separator + typicalFolderName; 49 | } else { 50 | System.out.println("It seems you're using a non Windows OS, which is fine."); 51 | System.out.println("You'll need to select a default directory for your '.minecraft' folder."); 52 | System.out.println(" Note: A custom directory can be specified in the next step"); 53 | System.out.println(" "); 54 | 55 | System.out.println("Please input a selection (number)."); 56 | 57 | String[] choices = new String[] { "~/Library/Application Support/minecraft (macOS Default)", 58 | "~/.minecraft (Linux Default)" }; 59 | 60 | for (int i = 0; i < choices.length; i++) { 61 | System.out.println((i + 1) + ". " + choices[i]); 62 | } 63 | 64 | int selection = Utils.getNumberInput(1, 2); 65 | 66 | minecraftDirectory = choices[selection - 1].split(" \\(")[0]; 67 | System.out.println("Now using \"" + minecraftDirectory + "\" as '.minecraft' folder location."); 68 | } 69 | 70 | minecraftFolder = new File(minecraftDirectory); 71 | 72 | if (!minecraftFolder.exists()) { 73 | System.out.println("Note: The above '.minecraft' directory does not appear to exist!"); 74 | } 75 | 76 | System.out.println( 77 | "Would you like to input a custom '.minecraft' directory? (Currently: " + minecraftDirectory + ")"); 78 | boolean changeDir = Utils.getBooleanInput(); 79 | 80 | if (changeDir) { 81 | System.out.println("Please provide the directory for your '.minecraft' folder!"); 82 | minecraftFolder = Utils.getDirectoryInput(); 83 | minecraftDirectory = minecraftFolder.getAbsolutePath(); 84 | System.out.println("Set Minecraft Directory to \"" + minecraftDirectory + "\"!"); 85 | } 86 | } 87 | } 88 | } 89 | 90 | public void scanLogs(File logs, String platform) { 91 | spacer(); 92 | System.out.println("Log scanning has begun..."); 93 | System.out.println(" - Note: This can take anywhere from 10 seconds to 2 minutes"); 94 | spacer(); 95 | 96 | List containing = Utils.checkAllFiles(logs); 97 | 98 | spacer(); 99 | 100 | System.out.println("Log scanning has completed."); 101 | System.out.println("Results: "); 102 | System.out.println(" - Checked: " + logs.listFiles().length + " log files"); 103 | System.out 104 | .println(" - Potential Exploit: " + containing.size() + " log files that potentially contain the exploit"); 105 | 106 | printExplanation(containing.size(), platform); 107 | 108 | if (!containing.isEmpty()) { 109 | System.out.println(" "); 110 | System.out.println("Would you like to view a list of all the files that potentially contain the exploit?"); 111 | 112 | if (Utils.getBooleanInput()) { 113 | System.out.println("------------"); 114 | for (File file : containing) 115 | System.out.println("- " + file.getAbsolutePath()); 116 | System.out.println("------------"); 117 | System.out.println(" "); 118 | } 119 | } 120 | 121 | } 122 | 123 | public void returnHome() { 124 | System.out.println(" "); 125 | System.out.println("Press Enter to return home."); 126 | Utils.waitForEnter(); 127 | } 128 | 129 | public void printExplanation(int exploitCount, String platform) { 130 | System.out.println(" "); 131 | System.out.println("What does this mean?"); 132 | 133 | if (exploitCount == 0) { 134 | System.out.println( 135 | "This means that it doesn't immediately appear that you have been impacted by or exposed to this exploit whilst " 136 | + platform + ". There is still a chance that you were, however there are no log files indicating such."); 137 | } else { 138 | System.out 139 | .println("You should investigate the log files that potentially contain the exploit for some context!"); 140 | System.out.println( 141 | "If the logs are from after the Mojang patch, or any other 'official' patch, you should be fine."); 142 | System.out.println( 143 | " Please Note: Server owners may have originally implemented a bad 'patch' that was bypassed. Do not rely on this when checking dates."); 144 | 145 | System.out.println( 146 | "If you're unsure of anything, or need help, contact someone who you believe is knowledgeable."); 147 | } 148 | 149 | System.out.println("Feel free to contact me on Discord (Koupah#5129), Github (Koupah) or Twitter (@Koupahs)."); 150 | } 151 | 152 | public static String getMinecraftDirectory() { 153 | return minecraftDirectory; 154 | } 155 | 156 | public String getName() { 157 | return this.name; 158 | } 159 | 160 | public static final Pattern log4jFormat; 161 | 162 | // Literal strings to skip. "String" ignores "${String}", case sensitive 163 | public static final List ignoreExact = Arrays.asList("project.version", "git.commit.id.abbrev"); 164 | 165 | static { 166 | String pattern = "((?<=\\$\\{" + "%ignore%" + ")(?! )(.[^ \\s]*\\[?)(?=(? "); 93 | return Checker.input.nextLine(); 94 | } 95 | 96 | private static boolean contains(String checking, String[] array) { 97 | if (array.length == 0) 98 | return true; 99 | 100 | for (String string : array) 101 | if (checking.equalsIgnoreCase(string)) 102 | return true; 103 | 104 | return false; 105 | } 106 | 107 | public static String logSameLine(Object out) { 108 | System.out.print(out); 109 | return out.toString(); 110 | } 111 | 112 | public static String log(Object out) { 113 | System.out.println(out); 114 | return out.toString(); 115 | } 116 | 117 | public static List checkAllFiles(File directory) { 118 | List containing = new ArrayList(); 119 | 120 | for (File file : directory.listFiles()) { 121 | if (file.isFile()) { 122 | final String name = file.getName(); 123 | 124 | if (name.endsWith(".log")) { 125 | if (checkIfContains(file)) 126 | containing.add(file); 127 | } else if (name.endsWith(".log.gz")) { 128 | if (checkGZIP(file)) 129 | containing.add(file); 130 | } else { 131 | System.out.println("Found unsupported file \"" + name + "\" in logs folder, skipping it!"); 132 | } 133 | } 134 | } 135 | 136 | return containing; 137 | } 138 | 139 | public static boolean checkGZIP(File file) { 140 | boolean found = false; 141 | try { 142 | InputStream in = new GZIPInputStream(new FileInputStream(file)); 143 | 144 | File tempTxt = new File(tempFolder, file.getName() + ".temp"); 145 | 146 | OutputStream out = new FileOutputStream(tempTxt); 147 | 148 | byte[] buffer = new byte[65536]; 149 | int noRead; 150 | while ((noRead = in.read(buffer)) != -1) { 151 | out.write(buffer, 0, noRead); 152 | } 153 | out.close(); 154 | in.close(); 155 | 156 | found = checkIfContains(tempTxt); 157 | 158 | if (found) { 159 | System.out.println( 160 | "The above .temp exploit logs were from a compressed log: \"" + file.getAbsolutePath() + "\"."); 161 | } 162 | 163 | tempTxt.delete(); 164 | 165 | } catch (Exception e) { 166 | System.out.println("Couldn't check GZipped log \"" + file.getName() + "\" (" + e.getMessage() + ")"); 167 | } 168 | 169 | return found; 170 | } 171 | 172 | public static boolean checkIfContains(File log) { 173 | boolean found = false; 174 | 175 | try { 176 | BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(log))); 177 | 178 | String line; 179 | int lineCount = 0; 180 | while ((line = reader.readLine()) != null) { 181 | lineCount++; 182 | if (ExploitChecker.hasLog4jFormat(line)) { 183 | found = true; 184 | Matcher results = ExploitChecker.getLog4jMatcher(line); 185 | System.out 186 | .println("Potential exploit usage on line " + lineCount + " of " + log.getAbsolutePath() + ": "); 187 | 188 | results.reset(); 189 | while (results.find()) { 190 | System.out.println(" - Found: \"${" + results.group() + "}\""); 191 | } 192 | } 193 | } 194 | 195 | reader.close(); 196 | } catch (Exception e) { 197 | e.printStackTrace(); 198 | System.out.println("Couldn't read file \"" + log.getName() + "\" (" + e.getMessage() + ")"); 199 | } 200 | 201 | return found; 202 | } 203 | 204 | public static int getNumberInput(int min, int max) { 205 | String input; 206 | while ((input = getInput()) != null) { 207 | try { 208 | int number = Integer.parseInt(input); 209 | if (number < min) { 210 | System.out.println("Your input (" + number + ") is smaller than the minimum (" + min + ")."); 211 | } else if (number > max) { 212 | System.out.println("Your input (" + number + ") is larger than the maximum (" + max + ")."); 213 | } else { 214 | return number; 215 | } 216 | } catch (Exception e) { 217 | System.out.println("Invalid Number! Please input an integer between " + min + " and " + max + "."); 218 | } 219 | } 220 | 221 | return 0; 222 | } 223 | 224 | } --------------------------------------------------------------------------------