improve security, then try to write a dumper and give up after 6 hours and writing and deleting 500 lines of DENSE code
This commit is contained in:
parent
b9a93100d1
commit
d6cd268f3c
16 changed files with 194 additions and 16 deletions
Binary file not shown.
|
@ -33,11 +33,11 @@ import java.util.function.Consumer;
|
|||
|
||||
public class BaseBand {
|
||||
public static int majorVersion = 1;
|
||||
public static int buildNumber = 351;
|
||||
public static String hash = "d8b4b094ef6e5822";
|
||||
public static int buildNumber = 399;
|
||||
public static String hash = "b00740a0b2e5152d";
|
||||
|
||||
public static String name = "BaseBand";
|
||||
public long timeOfCompile = 1695967780477L;
|
||||
public long timeOfCompile = 1695983122629L;
|
||||
public CommandManager commandRegistry;
|
||||
public EventBus eventBus;
|
||||
public ArrayList<Module> modules = new ArrayList<>();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package de.tudbut.security;
|
||||
|
||||
import de.tudbut.tools.ReflectUtil;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -10,8 +12,18 @@ import java.util.List;
|
|||
|
||||
public class AccessKiller {
|
||||
|
||||
private static final Field reflectionData;
|
||||
|
||||
static {
|
||||
try {
|
||||
reflectionData = getField(Class.class.getDeclaredField("reflectionData"));
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Field getField(Field f) {
|
||||
f.setAccessible(true);
|
||||
ReflectUtil.forceAccessible(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
@ -22,7 +34,7 @@ public class AccessKiller {
|
|||
clazz.getDeclaredConstructors();
|
||||
clazz.getInterfaces();
|
||||
|
||||
SoftReference<?> data = (SoftReference<?>) getField(Class.class.getDeclaredField("reflectionData")).get(clazz);
|
||||
SoftReference<?> data = (SoftReference<?>) reflectionData.get(clazz);
|
||||
Object reflectionData = data.get();
|
||||
assert reflectionData != null;
|
||||
return reflectionData;
|
||||
|
@ -110,4 +122,12 @@ public class AccessKiller {
|
|||
public static void killClassReflection() {
|
||||
killReflectionFor(Class.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills access to possible ways to restore reflective access after it has been removed.
|
||||
* This should prevent all other ways of accessing fields, but other ways may exist.
|
||||
*/
|
||||
public static void ensureKills() {
|
||||
killMethodAccess(Class.class, "getDeclaredFields0", "getDeclaredMethods0", "getDeclaredConstructors0");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,9 +58,9 @@ public class DataKeeper<T> {
|
|||
private void keep() {
|
||||
lock.waitHere();
|
||||
lock.lock();
|
||||
PermissionManager permissionManager = this.permissionManager;
|
||||
PermissionManager permissionManager = this.permissionManager.clone();
|
||||
AtomicReference<T> data = new AtomicReference<>(dataInsertion.get());
|
||||
Strictness strictness = this.strictness;
|
||||
Strictness strictness = this.strictness.clone();
|
||||
dataInsertion = null;
|
||||
while(!forgetAll) {
|
||||
lock.waitHere();
|
||||
|
|
|
@ -17,4 +17,9 @@ public class ExtendedStrictness implements Strictness {
|
|||
return primary.getRawProperty(name);
|
||||
return secondary.getRawProperty(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Strictness clone() {
|
||||
return new ExtendedStrictness(primary.clone(), secondary.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package de.tudbut.security;
|
||||
|
||||
import de.tudbut.tools.ReflectUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
public interface PermissionManager {
|
||||
public interface PermissionManager extends Cloneable {
|
||||
boolean checkCaller(Strictness strictnessLevel);
|
||||
|
||||
<T> boolean checkLambda(Strictness strictnessLevel, T lambda);
|
||||
|
@ -13,7 +15,7 @@ public interface PermissionManager {
|
|||
try {
|
||||
Class<?> shutdownClass = Class.forName("java.lang.Shutdown");
|
||||
Method exitMethod = shutdownClass.getDeclaredMethod("exit", int.class);
|
||||
exitMethod.setAccessible(true);
|
||||
ReflectUtil.forceAccessible(exitMethod);
|
||||
exitMethod.invoke(null, 1);
|
||||
} catch (Exception ignored) {}
|
||||
System.exit(1);
|
||||
|
@ -31,4 +33,6 @@ public interface PermissionManager {
|
|||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
PermissionManager clone();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package de.tudbut.security;
|
||||
|
||||
import de.tudbut.parsing.TCN;
|
||||
|
||||
public interface Strictness {
|
||||
public interface Strictness extends Cloneable {
|
||||
|
||||
Object getRawProperty(String name);
|
||||
|
||||
|
@ -27,4 +25,6 @@ public interface Strictness {
|
|||
default Strictness extend(Strictness newPrimary) {
|
||||
return new ExtendedStrictness(newPrimary, this);
|
||||
}
|
||||
|
||||
Strictness clone();
|
||||
}
|
||||
|
|
|
@ -57,5 +57,10 @@ public class StrictnessBuilder {
|
|||
public Object getRawProperty(String name) {
|
||||
return properties.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Strictness clone() {
|
||||
return new StrictnessImpl((HashMap<String, Object>) properties.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,9 @@ public class AllowAllRestriction implements PermissionManager {
|
|||
public <T> boolean checkLambda(Strictness strictnessLevel, T lambda) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionManager clone() {
|
||||
return new AllowAllRestriction();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package de.tudbut.security.permissionmanager;
|
|||
import de.tudbut.security.PermissionManager;
|
||||
import de.tudbut.security.Strictness;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -39,7 +41,7 @@ public class CallClassRestriction extends Restriction {
|
|||
|
||||
boolean isCalledByAllowed = false;
|
||||
for (StackTraceElement element : st) {
|
||||
if(allow.contains(element.getClassName())) {
|
||||
if (allow.contains(element.getClassName())) {
|
||||
isCalledByAllowed = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -39,4 +39,9 @@ public class PermissionOR implements PermissionManager {
|
|||
primary.killReflection();
|
||||
secondary.killReflection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionManager clone() {
|
||||
return new PermissionOR(primary.clone(), secondary.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import de.tudbut.security.Strictness;
|
|||
|
||||
public abstract class Restriction implements PermissionManager {
|
||||
|
||||
protected final PermissionManager parent;
|
||||
protected PermissionManager parent;
|
||||
|
||||
public Restriction(PermissionManager parent) {
|
||||
if(parent == null)
|
||||
|
@ -33,4 +33,15 @@ public abstract class Restriction implements PermissionManager {
|
|||
parent.killReflection();
|
||||
PermissionManager.super.killReflection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionManager clone() {
|
||||
try {
|
||||
Restriction cloned = (Restriction) super.clone();
|
||||
cloned.parent = parent.clone();
|
||||
return cloned;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
114
Loader/src/main/java/org/baseband/dumpy/Dumpie.java
Normal file
114
Loader/src/main/java/org/baseband/dumpy/Dumpie.java
Normal file
|
@ -0,0 +1,114 @@
|
|||
package org.baseband.dumpy;
|
||||
|
||||
/*import de.tudbut.tools.ReflectUtil;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;*/
|
||||
|
||||
public class Dumpie {
|
||||
|
||||
/*private static final Class<?> C = Class.class;
|
||||
|
||||
static {
|
||||
try {
|
||||
Field reflectionData = C.getDeclaredField("reflectionData");
|
||||
ReflectUtil.forceAccessible(reflectionData);
|
||||
reflectionData.set(C, null);
|
||||
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Field[] getFields(Class<?> clazz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
Method getDeclaredFields0 = C.getDeclaredMethod("getDeclaredFields0", boolean.class);
|
||||
ReflectUtil.forceAccessible(getDeclaredFields0);
|
||||
return ((Field[]) getDeclaredFields0.invoke(clazz, false)); // clazz.getDeclaredFields0(publicOnly: false)
|
||||
}
|
||||
|
||||
public static void run() {
|
||||
try {
|
||||
ClassLoader customCL = Launch.classLoader.getParent();
|
||||
Class<?> CustomClassLoader = customCL.getClass();
|
||||
System.out.println("DUMP CHECKPOINT: Got classloader: " + CustomClassLoader.getName());
|
||||
Field[] actualFields = getFields(CustomClassLoader);
|
||||
System.out.println("Got actual fields of CustomClassLoader: " + Arrays.toString(actualFields));
|
||||
|
||||
System.out.println("Desired field is probably: " + actualFields[1]);
|
||||
ReflectUtil.forceAccessible(actualFields[1]);
|
||||
Object dataKeeper = actualFields[1].get(customCL);
|
||||
Class<?> DataKeeper = dataKeeper.getClass();
|
||||
System.out.println("DUMP CHECKPOINT: Got DataKeeper: " + DataKeeper.getName());
|
||||
Field[] dataKeeperFields = getFields(DataKeeper);
|
||||
System.out.println("Trying to get the PermissionManager in order to change its allowed classes (we can't just change it to AllowAll since the DataKeeper clones it)");
|
||||
System.out.println("Got actual fields of DataKeeper: " + Arrays.toString(dataKeeperFields));
|
||||
|
||||
System.out.println("Desired field is probably: " + dataKeeperFields[1]);
|
||||
ReflectUtil.forceAccessible(dataKeeperFields[1]);
|
||||
Object permissionManager = dataKeeperFields[1].get(dataKeeper);
|
||||
Class<?> Restriction = permissionManager.getClass().getSuperclass();
|
||||
System.out.println("Got Restriction: " + Restriction.getName());
|
||||
Field[] restrictionFields = getFields(Restriction);
|
||||
System.out.println("Got actual fields of Restriction: " + Arrays.toString(restrictionFields));
|
||||
|
||||
System.out.println("Desired field is probably: " + restrictionFields[0]);
|
||||
ReflectUtil.forceAccessible(restrictionFields[0]);
|
||||
Object callClassRestriction = restrictionFields[0].get(restrictionFields[0].get(permissionManager)); // parent of parent of current PM
|
||||
Class<?> CallClassRestriction = callClassRestriction.getClass();
|
||||
System.out.println("Got CallClassRestriction: " + CallClassRestriction.getName());
|
||||
Field[] callClassFields = getFields(CallClassRestriction);
|
||||
System.out.println("Got actual fields of CallClassRestriction: " + Arrays.toString(callClassFields));
|
||||
|
||||
System.out.println("Desired field is probably: " + callClassFields[0]);
|
||||
ReflectUtil.forceAccessible(callClassFields[0]);
|
||||
ReflectUtil.eraseFinality(callClassFields[0]);
|
||||
System.out.println("Erased field finality: " + callClassFields[0]);
|
||||
Set<String> set = (Set<String>) callClassFields[0].get(callClassRestriction);
|
||||
System.out.println("Got allowedClassesSet: " + set);
|
||||
HashSet<String> hackedSet = new HashSet<>(set);
|
||||
hackedSet.add(DataKeeper.getName());
|
||||
callClassFields[0].set(callClassRestriction, hackedSet);
|
||||
System.out.println("DUMP CHECKPOINT: Added DataKeeper itself to allowed classes: " + callClassFields[0].get(callClassRestriction));
|
||||
|
||||
DataKeeper.getMethod("access", Consumer.class).invoke(dataKeeper, (Consumer<Object>) accessor -> {
|
||||
try {
|
||||
System.out.println("DUMP CHECKPOINT: Cracked DataKeeper!!!");
|
||||
Class<?> Accessor = accessor.getClass();
|
||||
System.out.println("DUMP CHECKPOINT: Got Accessor: " + Accessor.getName());
|
||||
Field[] accessorFields = getFields(Accessor);
|
||||
System.out.println("Got actual fields of Accessor: " + Arrays.toString(accessorFields));
|
||||
System.out.println("Desired field is probably: " + accessorFields[1]);
|
||||
ReflectUtil.forceAccessible(accessorFields[1]);
|
||||
System.out.println("DUMP COMPLETE: ---");
|
||||
System.out.println("DUMP COMPLETE: ---");
|
||||
System.out.println("DUMP COMPLETE: " + accessorFields[1].get(accessor));
|
||||
System.out.println("DUMP COMPLETE: ---");
|
||||
System.out.println("DUMP COMPLETE: ---");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Unable to dump");
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Unable to dump");
|
||||
}
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
Class<?> shutdownClass = Class.forName("java.lang.Shutdown");
|
||||
Method exitMethod = shutdownClass.getDeclaredMethod("exit", int.class);
|
||||
exitMethod.setAccessible(true);
|
||||
exitMethod.invoke(null, 1);
|
||||
} catch (Exception ignored) {}
|
||||
}*/
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ import net.minecraft.launchwrapper.ITweaker;
|
|||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
//import org.baseband.dumpy.Dumpie;
|
||||
import org.baseband.launcher.launch.Loader;
|
||||
import org.baseband.launcher.tweaker.Core;
|
||||
import org.baseband.launcher.classloader.CustomClassloader;
|
||||
|
@ -65,6 +66,7 @@ public class Tweaker implements ITweaker {
|
|||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | InterruptedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
//Dumpie.run();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ public class Loader {
|
|||
|
||||
|
||||
private static Strictness init1() {
|
||||
AccessKiller.ensureKills();
|
||||
AccessKiller.killFieldAccess(Loader.class); //nah this should work right???
|
||||
return StrictnessBuilder.create()
|
||||
.property("Restriction.CallClass.MaxDistance", 10)
|
||||
|
@ -64,7 +65,6 @@ public class Loader {
|
|||
}
|
||||
|
||||
private static DataKeeper<PermissionManager> init2() {
|
||||
//AccessKiller.killFieldAccess(Loader.class, "permissionManager");
|
||||
PermissionManager manager =
|
||||
new HideErrorRestriction(
|
||||
new BBPermissionManager(
|
||||
|
|
|
@ -29,4 +29,9 @@ public class DynamicPermissionManager implements PermissionManager {
|
|||
public void killReflection() {
|
||||
Loader.getPermissionManager().killReflection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionManager clone() {
|
||||
return this; // holds no state
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue