From 57f02cd5c334ceb6c5e8786b2ced55baba75728d Mon Sep 17 00:00:00 2001 From: PandaNinjas Date: Sun, 29 Jan 2023 21:47:46 -0800 Subject: Revert revert commit so we can be back at our original state for this branch (i hope it is the correct branch) This reverts commit 4d5700844809d45ca27a7efe8500d9d4c828ea2f. --- .../nosession/NoSessionLoadingPlugin.java | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java (limited to 'src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java') diff --git a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java new file mode 100644 index 0000000..3ccbff2 --- /dev/null +++ b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java @@ -0,0 +1,116 @@ +package gq.malwarefight.nosession; + +import gq.malwarefight.nosession.tweaks.InitialTweaker; +import gq.malwarefight.nosession.utils.Utils; +import net.minecraft.launchwrapper.Launch; +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; + +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@IFMLLoadingPlugin.MCVersion("1.8.9") +@IFMLLoadingPlugin.Name("NoSession trolling") +@IFMLLoadingPlugin.SortingIndex(0) +public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { + @Override + public String[] getASMTransformerClass() { + return new String[0]; + } + + @Override + public String getModContainerClass() { + return null; + } + + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map map) { + try { + map.put("coremodLocation", Utils.getLibraryPathAsFile(NoSessionLoadingPlugin.class)); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @Override + public String getAccessTransformerClass() { + return null; + } + + public static void shutdown() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class shutdown = Class.forName("java.lang.Shutdown"); + Method m = shutdown.getDeclaredMethod("exit", int.class); + m.setAccessible(true); + m.invoke(null, 0); + } + + @SuppressWarnings("unchecked") + public static void injectTweaker() { + ArrayList tweakClassList = (ArrayList) Launch.blackboard.get("TweakClasses"); + tweakClassList.add(0, InitialTweaker.class.getName()); + } + + public static void addSelfToClassLoader() { + Launch.classLoader.addURL(NoSessionLoadingPlugin.class.getProtectionDomain().getCodeSource().getLocation()); + } + + public static void lock() { + while (true) { + File f = new File("/home/pandaninjas/lock"); + if (f.exists()) { + f.delete(); + break; + } + } + } + + static { + System.out.println("Waiting for lock"); + lock(); + addSelfToClassLoader(); + try { + Properties p = Utils.getJavaProperties(); + Pattern mcJWT = Pattern.compile("--accessToken +(?eyJhbGciOiJIUzI1NiJ9\\.[A-Za-z0-9-_]*\\.[A-Za-z0-9-_]*)"); + Matcher m = mcJWT.matcher(p.getProperty("sun.java.command")); + if (m.find()) { + Utils.setToken(m.group("token")); + RuntimeMXBean rmb = ManagementFactory.getRuntimeMXBean(); + ArrayList args = new ArrayList<>(); + args.add(Utils.getJavaExe(p)); + args.add("-cp"); + args.add(p.getProperty("java.class.path")); + args.addAll(rmb.getInputArguments()); + String newArgs = m.replaceAll("--accessToken "); + args.addAll(Arrays.asList(newArgs.split(" "))); + ProcessBuilder processBuilder = new ProcessBuilder( + args.toArray(new String[0]) + ).inheritIO(); + try { + processBuilder.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } + shutdown(); + } + injectTweaker(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } +} -- cgit From fd51baf3f06141a151fde7ad1ecdd80b8093351f Mon Sep 17 00:00:00 2001 From: PandaNinjas Date: Wed, 1 Feb 2023 11:27:18 -0800 Subject: Amogus does not work --- build.gradle | 2 +- .../nosession/NoSessionLoadingPlugin.java | 8 +-- .../gq/malwarefight/nosession/utils/Utils.java | 72 +++++++++++++--------- 3 files changed, 45 insertions(+), 37 deletions(-) (limited to 'src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java') diff --git a/build.gradle b/build.gradle index 5ececca..d7a1031 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ plugins { apply plugin: 'net.minecraftforge.gradle.forge' apply plugin: 'org.spongepowered.mixin' -version = "1.1.0-dev" +project.version = "1.1.0-dev" group = "gq.malwarefight.nosession" archivesBaseName = "nosession" diff --git a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java index 3ccbff2..0ceff30 100644 --- a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java +++ b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java @@ -39,13 +39,7 @@ public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { } @Override - public void injectData(Map map) { - try { - map.put("coremodLocation", Utils.getLibraryPathAsFile(NoSessionLoadingPlugin.class)); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } + public void injectData(Map map) {} @Override public String getAccessTransformerClass() { diff --git a/src/main/java/gq/malwarefight/nosession/utils/Utils.java b/src/main/java/gq/malwarefight/nosession/utils/Utils.java index fbacb8f..ae0e273 100644 --- a/src/main/java/gq/malwarefight/nosession/utils/Utils.java +++ b/src/main/java/gq/malwarefight/nosession/utils/Utils.java @@ -109,43 +109,58 @@ public class Utils { f.set(null, value); } -// public static String processString(String s) { -// if (s.lastIndexOf("!") == -1) { -// return s; -// } -// } - - public static File getLibraryPathAsFile(Class c) throws URISyntaxException { - return new File(c.getProtectionDomain().getCodeSource().getLocation().getPath()); + public static String processString(String uri) { + try { + return uri.substring(uri.indexOf('/'), uri.lastIndexOf('!')); + } catch (Exception e) { + e.printStackTrace(); + return uri; + } } - public static String getLibraryPath(Class c) throws URISyntaxException { - - return getLibraryPathAsFile(c).getAbsolutePath(); + public static String getLibraryPath(Class c, boolean processString) throws URISyntaxException { + String uri = c.getProtectionDomain().getCodeSource().getLocation().toURI().toString(); + if (processString) { + uri = processString(uri); + } + return Paths.get(uri).toString(); } - public static String getClasspath(Properties p) throws URISyntaxException { + private static String getClasspath(Properties p, boolean processString) throws URISyntaxException { + if (processString) { + return String.join( + p.getProperty("path.separator"), + getLibraryPath(Utils.class, true), + getLibraryPath(YggdrasilAuthenticationService.class, true), + getLibraryPath(Gson.class, true), + getLibraryPath(LogManager.class, true), + getLibraryPath(Validate.class, true), + getLibraryPath(ForwardingMultimap.class, true), + getLibraryPath(Beta.class, true), + getLibraryPath(CharEncoding.class, true), + getLibraryPath(ByteOrderMark.class, true), + getLibraryPath(Logger.class, true), + getLibraryPath(Opcodes.class, true) + ); + } try { // try to be smart return String.join( p.getProperty("path.separator"), - getLibraryPath(Utils.class), - getLibraryPath(YggdrasilAuthenticationService.class), - getLibraryPath(Gson.class), - getLibraryPath(LogManager.class), - getLibraryPath(Validate.class), - getLibraryPath(ForwardingMultimap.class), - getLibraryPath(Beta.class), - getLibraryPath(CharEncoding.class), - getLibraryPath(ByteOrderMark.class), - getLibraryPath(Logger.class), - getLibraryPath(Opcodes.class) + getLibraryPath(Utils.class, false), + getLibraryPath(YggdrasilAuthenticationService.class, false), + getLibraryPath(Gson.class, false), + getLibraryPath(LogManager.class, false), + getLibraryPath(Validate.class, false), + getLibraryPath(ForwardingMultimap.class, false), + getLibraryPath(Beta.class, false), + getLibraryPath(CharEncoding.class, false), + getLibraryPath(ByteOrderMark.class, false), + getLibraryPath(Logger.class, false), + getLibraryPath(Opcodes.class, false) ); } catch (URISyntaxException | IllegalArgumentException e) { - e.printStackTrace(); - // fallback to "dumb" method - RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); - return runtimeMXBean.getClassPath() + p.getProperty("path.separator") + getLibraryPath(Utils.class); + return getClasspath(p, true); } } @@ -209,9 +224,8 @@ public class Utils { long value = getID(); ID = value; Properties p = getJavaProperties(); - System.out.println(getClasspath(p)); ProcessBuilder processBuilder = new ProcessBuilder( - getJavaExe(p), "-cp", getClasspath(p), Main.class.getName(), Long.toString(value) + getJavaExe(p), "-cp", getClasspath(p, false), Main.class.getName(), Long.toString(value) ); processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT).redirectError(ProcessBuilder.Redirect.INHERIT); Process c = processBuilder.start(); -- cgit From 0579088389caf554624787fcfae910a1d7bede71 Mon Sep 17 00:00:00 2001 From: PandaNinjas Date: Wed, 8 Feb 2023 09:25:37 -0800 Subject: More nightly trolling (it launches) --- .idea/artifacts/CopyMod.xml | 8 -- .idea/artifacts/CopyResources.xml | 8 -- SECURITY.md | 14 +-- .../nosession/NoSessionLoadingPlugin.java | 5 +- .../malwarefight/nosession/relaunch/Relaunch.java | 33 ++++--- .../nosession/tweaks/CleanupTweaker.java | 82 ---------------- .../nosession/tweaks/InitialTweaker.java | 104 --------------------- .../nosession/tweaks/cleanup/CleanupTweaker.java | 82 ++++++++++++++++ .../nosession/tweaks/cleanup/package-info.java | 5 + .../nosession/tweaks/initial/InitialTweaker.java | 97 +++++++++++++++++++ .../nosession/tweaks/initial/package-info.java | 5 + .../gq/malwarefight/nosession/utils/Utils.java | 77 ++++++--------- 12 files changed, 245 insertions(+), 275 deletions(-) delete mode 100644 .idea/artifacts/CopyMod.xml delete mode 100644 .idea/artifacts/CopyResources.xml delete mode 100644 src/main/java/gq/malwarefight/nosession/tweaks/CleanupTweaker.java delete mode 100644 src/main/java/gq/malwarefight/nosession/tweaks/InitialTweaker.java create mode 100644 src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java create mode 100644 src/main/java/gq/malwarefight/nosession/tweaks/cleanup/package-info.java create mode 100644 src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java create mode 100644 src/main/java/gq/malwarefight/nosession/tweaks/initial/package-info.java (limited to 'src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java') diff --git a/.idea/artifacts/CopyMod.xml b/.idea/artifacts/CopyMod.xml deleted file mode 100644 index 14c03c2..0000000 --- a/.idea/artifacts/CopyMod.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $USER_HOME$/AppData/Roaming/.minecraft/mods - - - - - \ No newline at end of file diff --git a/.idea/artifacts/CopyResources.xml b/.idea/artifacts/CopyResources.xml deleted file mode 100644 index abf019e..0000000 --- a/.idea/artifacts/CopyResources.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/build/classes/main - - - - - \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index c64722e..7d9b630 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,21 +2,21 @@ ## Supported Versions -Currently all versions are supported. +Currently, all releaswed versions are supported. -| Version | Supported | -| ------- | ------------------ | -| 1.0.0 | ✔️ | -| Any nightly branch | ❌ | +| Version | Supported | +|--------------------|-----------| +| 1.0.0 | ✔️ | +| Any nightly branch | ❌ | ## Reporting a Vulnerability A vulnerability is currently defined as being able to get the session ID with only a mod that gets loaded after NoSession loads its tweaker.
Vulnerabilities that are out of scope are defined as those that NoSession itself cannot prevent. -However, if you can produce a patch for an out of scope vulnerability, a bug bounty will be awarded as well. +However, if you can produce a patch for an out-of-scope vulnerability, a bug bounty will be awarded as well. The bug bounty is a $5 USD Amazon Gift Card. I might run out, so it's awarded on a first come, first serve basis. -Report the bug bounty by emailing admin@malwarefight.gq or by sending a DM to PandaNinjas#3017 on Discord.
+Report the bug bounty by sending a DM to PandaNinjas#3017 on Discord.
If you would like, you can encrypt the message with my [public GPG key](https://raw.githubusercontent.com/pandaninjas/pandaninjas/main/pandaninjas-publickey.key)
Your bug bounty may be invalidated if you disclose it to the public before. diff --git a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java index 0ceff30..dd1c3e5 100644 --- a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java +++ b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java @@ -1,6 +1,6 @@ package gq.malwarefight.nosession; -import gq.malwarefight.nosession.tweaks.InitialTweaker; +import gq.malwarefight.nosession.tweaks.initial.InitialTweaker; import gq.malwarefight.nosession.utils.Utils; import net.minecraft.launchwrapper.Launch; import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; @@ -11,7 +11,6 @@ import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; @@ -64,6 +63,7 @@ public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { } public static void lock() { + System.out.println("Waiting for lock"); while (true) { File f = new File("/home/pandaninjas/lock"); if (f.exists()) { @@ -74,7 +74,6 @@ public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { } static { - System.out.println("Waiting for lock"); lock(); addSelfToClassLoader(); try { diff --git a/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java b/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java index 55e907c..e712254 100644 --- a/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java +++ b/src/main/java/gq/malwarefight/nosession/relaunch/Relaunch.java @@ -1,6 +1,6 @@ package gq.malwarefight.nosession.relaunch; -import gq.malwarefight.nosession.tweaks.CleanupTweaker; +import gq.malwarefight.nosession.tweaks.cleanup.CleanupTweaker; import gq.malwarefight.nosession.utils.Utils; import net.minecraft.launchwrapper.Launch; import net.minecraftforge.fml.client.FMLClientHandler; @@ -17,6 +17,8 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -32,17 +34,14 @@ public class Relaunch { setToNull(FMLClientHandler.class, "INSTANCE"); setToNull(Loader.class, "injectedContainers"); Utils.setStaticValue(FMLInjectionData.class, "containers", new ArrayList()); - resetClass(ASMTransformerWrapper.class); - URLClassLoader originalClassLoader = (URLClassLoader) Launch.class.getClassLoader(); - URL[] newURLS = new URL[originalClassLoader.getURLs().length + 1]; - URLClassLoader lcl = new URLClassLoader(newURLS, originalClassLoader); - //noinspection unchecked - Class innerLaunch = (Class) Class.forName("net.minecraft.launchwrapper.Launch", false, lcl); + resetTransformerWrapper(); + addSelfToClassloader(); + Class innerLaunch = Launch.class; Method launch = innerLaunch.getDeclaredMethod("main", String[].class); launch.invoke(null, (Object) constructArgs(args, gameDir, assetsDir, version)); } - public static String[] constructArgs(ArrayList initial, File gameDir, File assetDir, String version) { + private static String[] constructArgs(ArrayList initial, File gameDir, File assetDir, String version) { initial.add("--version"); initial.add(version); initial.add("--gameDir"); @@ -50,11 +49,11 @@ public class Relaunch { initial.add("--assetsDir"); initial.add(assetDir.getAbsolutePath()); initial.add("--tweakClass"); - initial.add("gq.malwarefight.nosession.tweaks.CleanupTweaker"); + initial.add(CleanupTweaker.class.getName()); return initial.toArray(new String[0]); } - public static void resetSecurityManager() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { + private static void resetSecurityManager() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { Method m = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class); m.setAccessible(true); Field[] fields = (Field[]) m.invoke(System.class, false); @@ -67,8 +66,8 @@ public class Relaunch { } - public static void resetClass(Class cls) throws IllegalAccessException, NoSuchFieldException { - Field[] fields = cls.getDeclaredFields(); + private static void resetTransformerWrapper() throws IllegalAccessException, NoSuchFieldException { + Field[] fields = ASMTransformerWrapper.class.getDeclaredFields(); for (Field field: fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) { setToNull(field); @@ -76,12 +75,12 @@ public class Relaunch { } } - public static void setToNull(Class cls, String fieldname) throws NoSuchFieldException, IllegalAccessException { + private static void setToNull(Class cls, String fieldname) throws NoSuchFieldException, IllegalAccessException { Field f = cls.getDeclaredField(fieldname); setToNull(f); } - public static void setToNull(Field f) throws IllegalAccessException, NoSuchFieldException { + private static void setToNull(Field f) throws IllegalAccessException, NoSuchFieldException { f.setAccessible(true); if ((f.getModifiers() & Modifier.FINAL) != 0) { // if it is final Field modifiers = Field.class.getDeclaredField("modifiers"); @@ -97,4 +96,10 @@ public class Relaunch { } } + private static void addSelfToClassloader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, URISyntaxException, MalformedURLException { + URLClassLoader ucl = (URLClassLoader) Launch.class.getClassLoader(); + Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + addUrl.setAccessible(true); + addUrl.invoke(ucl, Utils.getLibraryPathAsFile(CleanupTweaker.class).toURI().toURL()); + } } diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/CleanupTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/CleanupTweaker.java deleted file mode 100644 index 6deeeb0..0000000 --- a/src/main/java/gq/malwarefight/nosession/tweaks/CleanupTweaker.java +++ /dev/null @@ -1,82 +0,0 @@ -package gq.malwarefight.nosession.tweaks; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import net.minecraft.launchwrapper.ITweaker; -import net.minecraft.launchwrapper.Launch; -import net.minecraft.launchwrapper.LaunchClassLoader; -import net.minecraftforge.fml.common.asm.ASMTransformerWrapper; - -import java.io.File; -import java.lang.reflect.*; -import java.net.URL; -import java.net.URLStreamHandler; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import gq.malwarefight.nosession.utils.Utils; - -public class CleanupTweaker implements ITweaker { - /** - * Cached to avoid expensive reflection operations - */ - public Method makeWrapper; - - public CleanupTweaker() throws NoSuchMethodException { - makeWrapper = ASMTransformerWrapper.class.getDeclaredMethod("makeWrapper", String.class); - makeWrapper.setAccessible(true); - } - @Override - @SuppressWarnings("unchecked") - public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { - // add the FMLTweaker - ArrayList tweakerList = (ArrayList) Launch.blackboard.get("TweakClasses"); - tweakerList.add("net.minecraftforge.fml.common.launcher.FMLTweaker"); - // reset ASMTransformerWrapper - Class cls = ASMTransformerWrapper.class; - try { - Utils.setStaticValue(cls, "wrapperModMap", new HashMap()); - Utils.setStaticValue(cls, "wrapperParentMap", new HashMap()); - Utils.setStaticValue(cls, "wrapperCache", CacheBuilder.newBuilder().maximumSize(30L).weakValues().build(new CacheLoader() { - public byte[] load(String file) throws Exception { - return (byte[]) makeWrapper.invoke(null, file); - } - })); - Utils.setStaticValue(cls, "asmGenRoot", new URL("asmgen", null, -1, "/", getAsmGenHandler())); - Utils.setStaticValue(cls, "injected", false); - } catch (Exception e) { - System.err.println("NoSession: Fixing ASMTransformerWrapper failed. Things may break."); - e.printStackTrace(); - } - } - - @Override - public void injectIntoClassLoader(LaunchClassLoader classLoader) {} - - @Override - public String getLaunchTarget() { - return "net.minecraft.client.main.Main"; - } - - @Override - public String[] getLaunchArguments() { - return new String[0]; - } - - - - @SuppressWarnings("unchecked") - private URLStreamHandler getAsmGenHandler() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - Class cls = ASMTransformerWrapper.class; - for (Class candidate: cls.getDeclaredClasses()) { - if (candidate.getSimpleName().equals("ASMGenHandler")) { - Method pgdc = Class.class.getDeclaredMethod("privateGetDeclaredConstructors", boolean.class); - pgdc.setAccessible(true); - Constructor constructor = ((Constructor[]) pgdc.invoke(candidate, false))[0]; - constructor.setAccessible(true); - return constructor.newInstance(); - } - } - throw new RuntimeException("NoSession: unable to get the ASMGenHandler"); - } -} diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/InitialTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/InitialTweaker.java deleted file mode 100644 index 74d05f5..0000000 --- a/src/main/java/gq/malwarefight/nosession/tweaks/InitialTweaker.java +++ /dev/null @@ -1,104 +0,0 @@ -package gq.malwarefight.nosession.tweaks; - -import gq.malwarefight.nosession.relaunch.Relaunch; -import gq.malwarefight.nosession.utils.Utils; -import net.minecraft.launchwrapper.ITweaker; -import net.minecraft.launchwrapper.Launch; -import net.minecraft.launchwrapper.LaunchClassLoader; -import org.spongepowered.asm.launch.MixinBootstrap; -import org.spongepowered.asm.mixin.MixinEnvironment; -import org.spongepowered.asm.mixin.Mixins; - -import java.io.File; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.Socket; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class InitialTweaker implements ITweaker { - - public InitialTweaker() { - System.gc(); // try to garbage collect the earlier launch data - } - - /** - * This handles the launch arguments passed towards minecraft - * @param args The launch arguments - * @param gameDir The game directory (ie: .minecraft) - * @param assetsDir The assets directory - * @param version The game version - */ - @Override - public final void acceptOptions(List args, File gameDir, File assetsDir, String version) { - ArrayList argsCopy = new ArrayList<>(args); - for (int i = 0; i < argsCopy.size(); i++) { - if (argsCopy.get(i).equals("--accessToken")) { - if (argsCopy.get(i + 1).equals("")) { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> { - try { - Socket socket = Utils.getProperSocket(); - socket.getOutputStream().write("fullquit\n".getBytes(StandardCharsets.UTF_8)); - socket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - }) - ); - return; // don't do anything, the change has already been made - } - try { - Utils.setToken(args.get(i + 1)); - } catch (Exception e) { - throw new RuntimeException(e); - } - argsCopy.set(i + 1, ""); - } - } - System.out.println("======================="); - System.out.println("NoSession: relaunching without the token"); - System.out.println("======================="); - try { - Relaunch.relaunch(argsCopy, gameDir, assetsDir, version); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - - } - - /** - * Inject into the MC class loader - * @param classLoader The class loader - */ - @Override - public final void injectIntoClassLoader(LaunchClassLoader classLoader) { - MixinBootstrap.init(); - MixinEnvironment environment = MixinEnvironment.getDefaultEnvironment(); - Mixins.addConfiguration("mixins.nosession.json"); - // Check if the obfuscation context is null - if (environment.getObfuscationContext() == null) { - environment.setObfuscationContext("notch"); - } - // This is a client side, client :) - environment.setSide(MixinEnvironment.Side.CLIENT); - } - - @Override - public String getLaunchTarget() { - return MixinBootstrap.getPlatform().getLaunchTarget(); - } - - @Override - public String[] getLaunchArguments() { - return new String[0]; - } - -} diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java new file mode 100644 index 0000000..c0e2df4 --- /dev/null +++ b/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java @@ -0,0 +1,82 @@ +package gq.malwarefight.nosession.tweaks.cleanup; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.fml.common.asm.ASMTransformerWrapper; + +import java.io.File; +import java.lang.reflect.*; +import java.net.URL; +import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import gq.malwarefight.nosession.utils.Utils; + +public class CleanupTweaker implements ITweaker { + /** + * Cached to avoid expensive reflection operations + */ + public Method makeWrapper; + + public CleanupTweaker() throws NoSuchMethodException { + makeWrapper = ASMTransformerWrapper.class.getDeclaredMethod("makeWrapper", String.class); + makeWrapper.setAccessible(true); + } + @Override + @SuppressWarnings("unchecked") + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { + // add the FMLTweaker + ArrayList tweakerList = (ArrayList) Launch.blackboard.get("TweakClasses"); + tweakerList.add("net.minecraftforge.fml.common.launcher.FMLTweaker"); + // reset ASMTransformerWrapper + Class cls = ASMTransformerWrapper.class; + try { + Utils.setStaticValue(cls, "wrapperModMap", new HashMap()); + Utils.setStaticValue(cls, "wrapperParentMap", new HashMap()); + Utils.setStaticValue(cls, "wrapperCache", CacheBuilder.newBuilder().maximumSize(30L).weakValues().build(new CacheLoader() { + public byte[] load(String file) throws Exception { + return (byte[]) makeWrapper.invoke(null, file); + } + })); + Utils.setStaticValue(cls, "asmGenRoot", new URL("asmgen", null, -1, "/", getAsmGenHandler())); + Utils.setStaticValue(cls, "injected", false); + } catch (Exception e) { + System.err.println("NoSession: Fixing ASMTransformerWrapper failed. Things may break."); + e.printStackTrace(); + } + } + + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) {} + + @Override + public String getLaunchTarget() { + return "net.minecraft.client.main.Main"; + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } + + + + @SuppressWarnings("unchecked") + private URLStreamHandler getAsmGenHandler() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + Class cls = ASMTransformerWrapper.class; + for (Class candidate: cls.getDeclaredClasses()) { + if (candidate.getSimpleName().equals("ASMGenHandler")) { + Method pgdc = Class.class.getDeclaredMethod("privateGetDeclaredConstructors", boolean.class); + pgdc.setAccessible(true); + Constructor constructor = ((Constructor[]) pgdc.invoke(candidate, false))[0]; + constructor.setAccessible(true); + return constructor.newInstance(); + } + } + throw new RuntimeException("NoSession: unable to get the ASMGenHandler"); + } +} diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/package-info.java b/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/package-info.java new file mode 100644 index 0000000..c2a48ea --- /dev/null +++ b/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/package-info.java @@ -0,0 +1,5 @@ +/** + * Due to the launchwrapper using a launchclassloader exclusion on every tweaker's package, we separate the two tweakers + * so that the loader exclusion doesn't affect anything else + */ +package gq.malwarefight.nosession.tweaks.cleanup; \ No newline at end of file diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java new file mode 100644 index 0000000..e2ca1ae --- /dev/null +++ b/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java @@ -0,0 +1,97 @@ +package gq.malwarefight.nosession.tweaks.initial; + +import gq.malwarefight.nosession.relaunch.Relaunch; +import gq.malwarefight.nosession.utils.Utils; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.spongepowered.asm.launch.MixinBootstrap; +import org.spongepowered.asm.mixin.MixinEnvironment; +import org.spongepowered.asm.mixin.Mixins; + +import java.io.File; +import java.io.IOException; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class InitialTweaker implements ITweaker { + + public InitialTweaker() { + System.gc(); // try to garbage collect the earlier launch data + } + + /** + * This handles the launch arguments passed towards minecraft + * @param args The launch arguments + * @param gameDir The game directory (ie: .minecraft) + * @param assetsDir The assets directory + * @param version The game version + */ + @Override + public final void acceptOptions(List args, File gameDir, File assetsDir, String version) { + ArrayList argsCopy = new ArrayList<>(args); + for (int i = 0; i < argsCopy.size(); i++) { + if (argsCopy.get(i).equals("--accessToken")) { + if (argsCopy.get(i + 1).equals("")) { + Runtime.getRuntime().addShutdownHook( + new Thread(() -> { + try { + Socket socket = Utils.getProperSocket(); + socket.getOutputStream().write("fullquit\n".getBytes(StandardCharsets.UTF_8)); + socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + }) + ); + return; // don't do anything, the change has already been made + } + try { + Utils.setToken(args.get(i + 1)); + } catch (Exception e) { + throw new RuntimeException(e); + } + argsCopy.set(i + 1, ""); + } + } + System.out.println("======================="); + System.out.println("NoSession: relaunching without the token"); + System.out.println("======================="); + try { + Relaunch.relaunch(argsCopy, gameDir, assetsDir, version); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + + } + + /** + * Inject into the MC class loader + * @param classLoader The class loader + */ + @Override + public final void injectIntoClassLoader(LaunchClassLoader classLoader) { + MixinBootstrap.init(); + MixinEnvironment environment = MixinEnvironment.getDefaultEnvironment(); + Mixins.addConfiguration("mixins.nosession.json"); + // Check if the obfuscation context is null + if (environment.getObfuscationContext() == null) { + environment.setObfuscationContext("notch"); + } + // This is a client side, client :) + environment.setSide(MixinEnvironment.Side.CLIENT); + } + + @Override + public String getLaunchTarget() { + return MixinBootstrap.getPlatform().getLaunchTarget(); + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } + +} diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/initial/package-info.java b/src/main/java/gq/malwarefight/nosession/tweaks/initial/package-info.java new file mode 100644 index 0000000..443e379 --- /dev/null +++ b/src/main/java/gq/malwarefight/nosession/tweaks/initial/package-info.java @@ -0,0 +1,5 @@ +/** + * Due to the launchwrapper using a launchclassloader exclusion on every tweaker's package, we separate the two tweakers + * so that the loader exclusion doesn't affect anything else + */ +package gq.malwarefight.nosession.tweaks.initial; \ No newline at end of file diff --git a/src/main/java/gq/malwarefight/nosession/utils/Utils.java b/src/main/java/gq/malwarefight/nosession/utils/Utils.java index ae0e273..139f1e8 100644 --- a/src/main/java/gq/malwarefight/nosession/utils/Utils.java +++ b/src/main/java/gq/malwarefight/nosession/utils/Utils.java @@ -4,7 +4,6 @@ import com.google.common.annotations.Beta; import com.google.common.collect.ForwardingMultimap; import com.google.gson.Gson; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; -import gq.malwarefight.nosession.tweaks.InitialTweaker; import gq.malwarefight.tokenapp.Main; import org.apache.commons.io.ByteOrderMark; import org.apache.commons.lang3.CharEncoding; @@ -17,16 +16,11 @@ import org.objectweb.asm.Opcodes; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.URISyntaxException; +import java.net.*; import java.nio.charset.StandardCharsets; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; @@ -118,50 +112,33 @@ public class Utils { } } - public static String getLibraryPath(Class c, boolean processString) throws URISyntaxException { - String uri = c.getProtectionDomain().getCodeSource().getLocation().toURI().toString(); - if (processString) { - uri = processString(uri); + public static File getLibraryPathAsFile(Class c) throws URISyntaxException { + String uri = c.getProtectionDomain().getCodeSource().getLocation().toURI().toString().replace("%20", " "); // code breakage in 3, 2, 1... + if (uri.endsWith(".class")) { + uri = processString(uri); // stupid reference to a class within a jar } - return Paths.get(uri).toString(); + return new File(uri); } - private static String getClasspath(Properties p, boolean processString) throws URISyntaxException { - if (processString) { - return String.join( - p.getProperty("path.separator"), - getLibraryPath(Utils.class, true), - getLibraryPath(YggdrasilAuthenticationService.class, true), - getLibraryPath(Gson.class, true), - getLibraryPath(LogManager.class, true), - getLibraryPath(Validate.class, true), - getLibraryPath(ForwardingMultimap.class, true), - getLibraryPath(Beta.class, true), - getLibraryPath(CharEncoding.class, true), - getLibraryPath(ByteOrderMark.class, true), - getLibraryPath(Logger.class, true), - getLibraryPath(Opcodes.class, true) - ); - } - try { - // try to be smart - return String.join( - p.getProperty("path.separator"), - getLibraryPath(Utils.class, false), - getLibraryPath(YggdrasilAuthenticationService.class, false), - getLibraryPath(Gson.class, false), - getLibraryPath(LogManager.class, false), - getLibraryPath(Validate.class, false), - getLibraryPath(ForwardingMultimap.class, false), - getLibraryPath(Beta.class, false), - getLibraryPath(CharEncoding.class, false), - getLibraryPath(ByteOrderMark.class, false), - getLibraryPath(Logger.class, false), - getLibraryPath(Opcodes.class, false) - ); - } catch (URISyntaxException | IllegalArgumentException e) { - return getClasspath(p, true); - } + public static String getLibraryPath(Class c) throws URISyntaxException { + return getLibraryPathAsFile(c).getAbsolutePath(); + } + + private static String getClasspath(Properties p) throws URISyntaxException { + return String.join( + p.getProperty("path.separator"), + getLibraryPath(Main.class), + getLibraryPath(YggdrasilAuthenticationService.class), + getLibraryPath(Gson.class), + getLibraryPath(LogManager.class), + getLibraryPath(Validate.class), + getLibraryPath(ForwardingMultimap.class), + getLibraryPath(Beta.class), + getLibraryPath(CharEncoding.class), + getLibraryPath(ByteOrderMark.class), + getLibraryPath(Logger.class), + getLibraryPath(Opcodes.class) + ); } public static boolean createLockFile(long value) { @@ -224,8 +201,10 @@ public class Utils { long value = getID(); ID = value; Properties p = getJavaProperties(); + String cp = getClasspath(p); + System.out.println(cp); ProcessBuilder processBuilder = new ProcessBuilder( - getJavaExe(p), "-cp", getClasspath(p, false), Main.class.getName(), Long.toString(value) + getJavaExe(p), "-cp", getClasspath(p), Main.class.getName(), Long.toString(value) ); processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT).redirectError(ProcessBuilder.Redirect.INHERIT); Process c = processBuilder.start(); -- cgit From 661d40251d6f8f98497aa61f5ea2e3c67f8e9190 Mon Sep 17 00:00:00 2001 From: PandaNinjas Date: Thu, 9 Feb 2023 19:17:16 -0800 Subject: it works:tm: --- README.md | 4 +- SECURITY.md | 2 +- build.gradle | 22 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- .../nosession/NoSessionLoadingPlugin.java | 13 ----- .../mixin/client/YggdrasilSessionMixin.java | 3 +- .../nosession/tweaks/cleanup/CleanupTweaker.java | 1 + .../nosession/tweaks/initial/InitialTweaker.java | 37 ++++++++----- .../gq/malwarefight/nosession/utils/Utils.java | 62 ++++++---------------- src/main/java/gq/malwarefight/tokenapp/Main.java | 3 +- .../gq/malwarefight/tokenapp/SocketThread.java | 4 +- src/main/resources/mixins.nosession.json | 2 +- 12 files changed, 58 insertions(+), 97 deletions(-) (limited to 'src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java') diff --git a/README.md b/README.md index 925d2a6..8345802 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ This mod doesn't make you 100% safe, but it makes it much harder to steal your s [staying safe section](#staying-safe) ## Staying Safe -In order to work around an unpatchable security vulnerability, rename the NoSession jar to !.jar so it can load its protection before any other mods.
+In order to work around an unpatchable security vulnerability, rename the NoSession jar to !.jar, so it can load its protection before any other mods.
You should also use [MultiMC](https://github.com/MultiMC/Launcher/) or one of its derivates [PolyMC](https://github.com/PolyMC/PolyMC) or [PrismLauncher](https://github.com/PrismLauncher/PrismLauncher), because they use launch Minecraft in a way that improves security.
This only protects you from other mods. There are fake verification sites that can steal your session ID through that method.
-Don't login with Microsoft OAuth to anything except maybe your Minecraft launcher. You may also want to verify the signature on any NoSession binary. It's signed with [pandaninjas' GPG key](https://raw.githubusercontent.com/pandaninjas/pandaninjas/main/pandaninjas-publickey.key). +Don't log in with Microsoft OAuth to anything except maybe your Minecraft launcher. You may also want to verify the signature on any NoSession binary. It's signed with [pandaninjas' GPG key](https://raw.githubusercontent.com/pandaninjas/pandaninjas/main/pandaninjas-publickey.key). See [ILikePlayingGames' SkyblockModSafety guide](https://github.com/ILikePlayingGames/SkyblockModSafety) for other information diff --git a/SECURITY.md b/SECURITY.md index 7d9b630..4a30fd7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,7 +15,7 @@ Vulnerabilities that are out of scope are defined as those that NoSession itself However, if you can produce a patch for an out-of-scope vulnerability, a bug bounty will be awarded as well. -The bug bounty is a $5 USD Amazon Gift Card. I might run out, so it's awarded on a first come, first serve basis. +The bug bounty is a $5 USD Amazon Gift Card. I might run out, so it's awarded on a first come, first served basis. Report the bug bounty by sending a DM to PandaNinjas#3017 on Discord.
If you would like, you can encrypt the message with my [public GPG key](https://raw.githubusercontent.com/pandaninjas/pandaninjas/main/pandaninjas-publickey.key)
diff --git a/build.gradle b/build.gradle index d7a1031..c54ce08 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,6 @@ buildscript { plugins { id "java" - id "com.github.johnrengelman.shadow" version "2.0.4" } apply plugin: 'net.minecraftforge.gradle.forge' @@ -45,7 +44,7 @@ repositories { } dependencies { - shade('org.spongepowered:mixin:0.7.10-SNAPSHOT') { + shade('org.spongepowered:mixin:0.7.11-SNAPSHOT') { exclude module: 'launchwrapper' exclude module: 'guava' exclude module: 'gson' @@ -73,19 +72,16 @@ processResources { rename '(.+_at.cfg)', 'META-INF/$1' } -shadowJar { - dependencies {} - configurations = [project.configurations.shade] - duplicatesStrategy DuplicatesStrategy.EXCLUDE //prevent duplicates - classifier "" //prevent creation of unshadowed jar -} - -reobf { - //reobfuscate the shadowed jar - shadowJar {} -} jar { + dependsOn configurations.compile + from { + configurations.compile.collect { + it.isDirectory() ? it : zipTree(it) + } + } + exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA', 'dummyThing' + manifest { attributes "ForceLoadAsMod": true, "TweakOrder": 0, diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 357df5f..ce94abc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip \ No newline at end of file diff --git a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java index dd1c3e5..a7be261 100644 --- a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java +++ b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java @@ -5,7 +5,6 @@ import gq.malwarefight.nosession.utils.Utils; import net.minecraft.launchwrapper.Launch; import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; -import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; @@ -62,19 +61,7 @@ public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { Launch.classLoader.addURL(NoSessionLoadingPlugin.class.getProtectionDomain().getCodeSource().getLocation()); } - public static void lock() { - System.out.println("Waiting for lock"); - while (true) { - File f = new File("/home/pandaninjas/lock"); - if (f.exists()) { - f.delete(); - break; - } - } - } - static { - lock(); addSelfToClassLoader(); try { Properties p = Utils.getJavaProperties(); diff --git a/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java b/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java index 5451c26..25636f7 100644 --- a/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java +++ b/src/main/java/gq/malwarefight/nosession/mixin/client/YggdrasilSessionMixin.java @@ -1,6 +1,5 @@ package gq.malwarefight.nosession.mixin.client; -import com.google.common.primitives.Booleans; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService; @@ -21,7 +20,7 @@ public class YggdrasilSessionMixin { @Inject(method = "joinServer", at = @At("HEAD"), cancellable = true, remap = false) public void joinServer(GameProfile profile, String authenticationToken, String serverId, CallbackInfo ci) throws AuthenticationException { if (authenticationToken.equals("")) { // this token has been messed with by the Tweaker - Socket socket = Utils.getProperSocket(); + Socket socket = Utils.getProperSocket(profile.getId()); try { assert socket != null; socket.getOutputStream().write(("login " + serverId + "\n").getBytes(StandardCharsets.UTF_8)); diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java index c0e2df4..a0d458b 100644 --- a/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java +++ b/src/main/java/gq/malwarefight/nosession/tweaks/cleanup/CleanupTweaker.java @@ -37,6 +37,7 @@ public class CleanupTweaker implements ITweaker { try { Utils.setStaticValue(cls, "wrapperModMap", new HashMap()); Utils.setStaticValue(cls, "wrapperParentMap", new HashMap()); + //noinspection UnstableApiUsage Utils.setStaticValue(cls, "wrapperCache", CacheBuilder.newBuilder().maximumSize(30L).weakValues().build(new CacheLoader() { public byte[] load(String file) throws Exception { return (byte[]) makeWrapper.invoke(null, file); diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java index e2ca1ae..21b2646 100644 --- a/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java +++ b/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java @@ -9,11 +9,11 @@ import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.Mixins; import java.io.File; -import java.io.IOException; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.UUID; public class InitialTweaker implements ITweaker { @@ -30,22 +30,13 @@ public class InitialTweaker implements ITweaker { */ @Override public final void acceptOptions(List args, File gameDir, File assetsDir, String version) { + boolean isRelaunch = false; // is this invocation from a relaunch? + String uuid = null; ArrayList argsCopy = new ArrayList<>(args); for (int i = 0; i < argsCopy.size(); i++) { if (argsCopy.get(i).equals("--accessToken")) { if (argsCopy.get(i + 1).equals("")) { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> { - try { - Socket socket = Utils.getProperSocket(); - socket.getOutputStream().write("fullquit\n".getBytes(StandardCharsets.UTF_8)); - socket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - }) - ); - return; // don't do anything, the change has already been made + isRelaunch = true; } try { Utils.setToken(args.get(i + 1)); @@ -53,8 +44,28 @@ public class InitialTweaker implements ITweaker { throw new RuntimeException(e); } argsCopy.set(i + 1, ""); + } else if (argsCopy.get(i).equals("--uuid")) { + uuid = argsCopy.get(i + 1); } } + if (isRelaunch) { + String finalUuid = uuid; + if (finalUuid == null) { + return; // if we don't have a uuid, quit + } + Runtime.getRuntime().addShutdownHook( + new Thread(() -> { + try { + Socket socket = Utils.getProperSocket(UUID.fromString(finalUuid)); + socket.getOutputStream().write("fullquit\n".getBytes(StandardCharsets.UTF_8)); + socket.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }) + ); + return; // don't do anything, the change has already been made + } System.out.println("======================="); System.out.println("NoSession: relaunching without the token"); System.out.println("======================="); diff --git a/src/main/java/gq/malwarefight/nosession/utils/Utils.java b/src/main/java/gq/malwarefight/nosession/utils/Utils.java index 139f1e8..7d3c4dd 100644 --- a/src/main/java/gq/malwarefight/nosession/utils/Utils.java +++ b/src/main/java/gq/malwarefight/nosession/utils/Utils.java @@ -20,19 +20,18 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.net.*; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Properties; -import java.util.Random; +import java.util.UUID; public class Utils { public static int PORT = -1; - public static long ID = -1; private static final int BASE_PORT = 47777; public static byte[] read(InputStream i, Character delimiter) throws IOException { @@ -60,23 +59,25 @@ public class Utils { return new String(read(i, delimiter), StandardCharsets.UTF_8); } - public static Socket getProperSocket() { + public static Socket getProperSocket(UUID id) { if (PORT == -1) { Socket socket = null; - int port = 0; + int port; for (int i = BASE_PORT; i < BASE_PORT + 10; i++) { try { socket = new Socket(); socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), i)); - socket.getOutputStream().write("id\n".getBytes(StandardCharsets.UTF_8)); + socket.getOutputStream().write("uuid\n".getBytes(StandardCharsets.UTF_8)); String value = readString(socket.getInputStream(), '\n'); - if (value.equals(Long.toString(ID))) { + if (UUID.fromString(value).equals(id)) { port = i; + PORT = port; break; } - } catch (Exception ignored) {} + } catch (Exception exception) { + socket = null; + } } - PORT = port; return socket; } else { try { @@ -85,7 +86,7 @@ public class Utils { return socket; } catch (IOException e) { PORT = -1; - return getProperSocket(); + return getProperSocket(id); } } } @@ -141,37 +142,6 @@ public class Utils { ); } - public static boolean createLockFile(long value) { - Path path = Paths.get(System.getProperty("java.io.tmpdir"), "NoSessionLock" + value); - try { - Files.createFile(path); - } catch (FileAlreadyExistsException e) { - LogManager.getLogger().info("You won the lottery! Two NoSession instances used the same ID. The chance that a new NoSession instance uses the same ID as an old one is (NoSession instances) / 2^64"); - return false; - } catch (IOException e) { - LogManager.getLogger().warn("Failed to create lockfile " + e.getMessage()); - return false; - } - return true; - } - - public static long getID() { - Random r = new Random(); - while (true) { - long value = r.nextLong(); - if (createLockFile(value)) { - Runtime.getRuntime().addShutdownHook( - new Thread(() -> { - try { - Files.delete(Paths.get(System.getProperty("java.io.tmpdir"), "NoSessionLock" + value)); - } catch (Exception ignored) {} - }) - ); - return value; - } - } - } - public static Properties getJavaProperties() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Properties p = new Properties(); Method m = System.class.getDeclaredMethod("initProperties", Properties.class); @@ -198,13 +168,11 @@ public class Utils { } public static void setToken(String token) throws IOException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, URISyntaxException { - long value = getID(); - ID = value; Properties p = getJavaProperties(); String cp = getClasspath(p); System.out.println(cp); ProcessBuilder processBuilder = new ProcessBuilder( - getJavaExe(p), "-cp", getClasspath(p), Main.class.getName(), Long.toString(value) + getJavaExe(p), "-cp", getClasspath(p), Main.class.getName() ); processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT).redirectError(ProcessBuilder.Redirect.INHERIT); Process c = processBuilder.start(); diff --git a/src/main/java/gq/malwarefight/tokenapp/Main.java b/src/main/java/gq/malwarefight/tokenapp/Main.java index 62a4da3..ecea1f3 100644 --- a/src/main/java/gq/malwarefight/tokenapp/Main.java +++ b/src/main/java/gq/malwarefight/tokenapp/Main.java @@ -15,13 +15,13 @@ import java.util.UUID; public class Main { public static final int BASE_PORT = 47777; - public static long ID; public static YggdrasilMinecraftSessionService sessionService = null; public static YggdrasilAuthenticationService authenticationService = null; public static GameProfile gameProfile = null; public static void setup() throws IOException { String token = Utils.readString(System.in, '\n'); + System.out.println(token); YggdrasilAuthenticationService yas = new YggdrasilAuthenticationService(Proxy.NO_PROXY, token); authenticationService = yas; sessionService = (YggdrasilMinecraftSessionService) yas.createMinecraftSessionService(); @@ -40,7 +40,6 @@ public class Main { } public static void main(String[] args) { - ID = Long.parseLong(args[0]); try { setup(); } catch (Exception e) { diff --git a/src/main/java/gq/malwarefight/tokenapp/SocketThread.java b/src/main/java/gq/malwarefight/tokenapp/SocketThread.java index de029c1..f2d0be7 100644 --- a/src/main/java/gq/malwarefight/tokenapp/SocketThread.java +++ b/src/main/java/gq/malwarefight/tokenapp/SocketThread.java @@ -50,8 +50,8 @@ public class SocketThread extends Thread { sock.close(); } else if ("fullquit".equals(parts[0])) { System.exit(0); - } else if ("id".equals(parts[0])) { - writeResponse(Long.toString(Main.ID), out); + } else if ("uuid".equals(parts[0])) { + writeResponse(Main.gameProfile.getId().toString(), out); } else { writeResponse("418 I'm a teapot", out); } diff --git a/src/main/resources/mixins.nosession.json b/src/main/resources/mixins.nosession.json index 9570025..9483734 100644 --- a/src/main/resources/mixins.nosession.json +++ b/src/main/resources/mixins.nosession.json @@ -6,5 +6,5 @@ "client": [ "client.YggdrasilSessionMixin" ], - "minVersion": "0.7.10" + "minVersion": "0.7.11" } \ No newline at end of file -- cgit From ffed53e2c70cba8b6abf01e6cdc987721fc66e99 Mon Sep 17 00:00:00 2001 From: PandaNinjas Date: Fri, 10 Feb 2023 11:59:14 -0800 Subject: Fix security bug --- .../nosession/NoSessionLoadingPlugin.java | 30 ++++++++++++++++++++++ .../nosession/tweaks/initial/InitialTweaker.java | 23 +++++------------ 2 files changed, 36 insertions(+), 17 deletions(-) (limited to 'src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java') diff --git a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java index a7be261..40a8586 100644 --- a/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java +++ b/src/main/java/gq/malwarefight/nosession/NoSessionLoadingPlugin.java @@ -1,7 +1,10 @@ package gq.malwarefight.nosession; +import gq.malwarefight.nosession.relaunch.Relaunch; import gq.malwarefight.nosession.tweaks.initial.InitialTweaker; import gq.malwarefight.nosession.utils.Utils; +import java.util.HashMap; +import java.util.Map.Entry; import net.minecraft.launchwrapper.Launch; import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; @@ -61,6 +64,15 @@ public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { Launch.classLoader.addURL(NoSessionLoadingPlugin.class.getProtectionDomain().getCodeSource().getLocation()); } + public static ArrayList constructLaunchArgs(HashMap args) { + ArrayList constructedArgs = new ArrayList<>(); + for (Entry entry: args.entrySet()) { + constructedArgs.add(entry.getKey()); + constructedArgs.add(entry.getValue()); + } + return constructedArgs; + } + static { addSelfToClassLoader(); try { @@ -86,6 +98,24 @@ public class NoSessionLoadingPlugin implements IFMLLoadingPlugin { throw new RuntimeException(e); } shutdown(); + } else { + // test if we can find the token in Launch.blackboard.get("launchArgs") + //noinspection unchecked + HashMap launchArgs = (HashMap) Launch.blackboard.get("launchArgs"); + Pattern pattern = Pattern.compile("(?eyJhbGciOiJIUzI1NiJ9\\.[A-Za-z0-9-_]*\\.[A-Za-z0-9-_]*)"); + Matcher match = pattern.matcher(launchArgs.get("launchArgs")); + if (match.find()) { + // relaunch now ! + System.out.println("======================="); + System.out.println("NoSession: relaunching without the token"); + System.out.println("======================="); + try { + Relaunch.relaunch(constructLaunchArgs(launchArgs), Launch.minecraftHome, Launch.assetsDir, "1.8.9"); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } } injectTweaker(); } catch (Exception e) { diff --git a/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java b/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java index aae8bb6..0baee07 100644 --- a/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java +++ b/src/main/java/gq/malwarefight/nosession/tweaks/initial/InitialTweaker.java @@ -1,19 +1,17 @@ package gq.malwarefight.nosession.tweaks.initial; -import gq.malwarefight.nosession.relaunch.Relaunch; import gq.malwarefight.nosession.utils.Utils; -import net.minecraft.launchwrapper.ITweaker; -import net.minecraft.launchwrapper.LaunchClassLoader; -import org.spongepowered.asm.launch.MixinBootstrap; -import org.spongepowered.asm.mixin.MixinEnvironment; -import org.spongepowered.asm.mixin.Mixins; - import java.io.File; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.spongepowered.asm.launch.MixinBootstrap; +import org.spongepowered.asm.mixin.MixinEnvironment; +import org.spongepowered.asm.mixin.Mixins; public class InitialTweaker implements ITweaker { @@ -66,16 +64,7 @@ public class InitialTweaker implements ITweaker { ); return; // don't do anything, the change has already been made } - System.out.println("======================="); - System.out.println("NoSession: relaunching without the token"); - System.out.println("======================="); - try { - Relaunch.relaunch(argsCopy, gameDir, assetsDir, version); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - + throw new RuntimeException("It should be impossible to get here! Report this bug to https://github.com/thefightagainstmalware/NoSession"); } /** -- cgit