/1dreamGN/Blog

1dreamGN

高版本JDK下JNDI漏洞利用方法精简总结

29
2025-06-20

前言

高版本JDK在RMI和LDAP的 trustURLCodebase 做了限制,修复后的JDK版本无法在不修改该参数的情况下通过远程加载ObjectFactory类的方式执行Java代码。目前公开常用的利用方法有通过Tomcat的 org.apache.naming.factory.BeanFactory 工厂类调用 javax.el.ELProcessor#eval 方法或 groovy.lang.GroovyShell#evaluate 方法,以及通过LDAP的 javaSerializedData 反序列化gadget,但在一些特殊情况下这些方法可能不适用,于是探讨其他利用方法。

基于BeanFactory的利用方法

绕过原理

LDAP和RMI收到服务端反序列化的 Reference 对象后,会根据 classFactory 属性从本地classpath中实例化一个ObjectFactory对象,然后调用其 getObjectInstance 方法。Tomcat的 org.apache.naming.factory.BeanFactory 类会把 Reference 对象的 className 属性作为类名实例化对象,从 Reference 对象的Addrs参数集合中获取 forceString 类型的参数,按逗号和等号分割后,根据propName作为方法名称反射调用相应方法。 javax.el.ELProcessor#evalgroovy.lang.GroovyShell#evaluate 这两个方法可只传一个String参数执行攻击代码,且依赖库常见,因此被经常使用。

可用的利用类

  1. MLet:JDK自带的 javax.management.loading.MLet 类,继承自URLClassloader,有一个无参构造方法和 addURL(String)loadClass(String) 方法。可用于gadget探测,但单靠 ClassLoader.loadClass 无法触发static代码块,暂时无法RCE。

  2. GroovyClassLoader:原理和MLet基本相同,可实现RCE,但由于已有 groovy.lang.GroovyShell 可用,该类价值不大。

  3. SnakeYamlnew org.yaml.snakeyaml.Yaml().load(String) 符合条件,依赖库使用比Groovy更常见,有一定利用价值。

  4. XStreamnew com.thoughtworks.xstream.XStream().fromXML(String) 符合条件,可用于攻击。

  5. MVEL:入口 org.mvel2.MVEL#eval(String) 因无参构造方法是private修饰,不符合条件,但可从 org.mvel2.sh.ShellSession#exec(String) 进入,通过执行内置命令调用 MVEL.eval 解析表达式。

  6. NativeLibLoader:JDK的 com.sun.glass.utils.NativeLibLoader 类有 loadLibrary(String) 方法,可加载指定路径的动态链接库文件,结合WEB功能或写文件gadget上传动态链接库后可执行命令。

XXE & RCE

漏洞发现

通过搜索实现 javax.naming.spi.ObjectFactory 接口的类,发现Tomcat的 org.apache.catalina.users.MemoryUserDatabaseFactory 工厂类可能存在漏洞。该类会实例化 MemoryUserDatabase 对象,从 Reference 中取出 pathnamereadonly 参数赋值,然后调用 open()save() 方法。

XXE漏洞

open() 方法会根据 pathname 发起本地或远程文件访问,使用commons-digester解析返回的XML内容,存在XXE漏洞。

RCE漏洞及利用方法

  1. 问题分析:在Linux系统下,由于目录跳转问题,需要在 CATALINA.BASE 文件夹下创建特定目录,可使用 BeanFactory 执行创建目录的利用类,如 org.h2.store.fs.FileUtils#createDirectory(String)

  2. 利用方法

    • 创建Tomcat管理员:让JNDI返回特定的 ResourceRef 对象,可覆盖 CATALINA.BASE/conf/tomcat-users.xml 文件,实现创建Tomcat管理员的目的。

    • 写Webshell:让JNDI返回另一个 ResourceRef 对象,可将包含攻击代码的XML写入web目录,实现写Webshell的功能。

JDBC RCE

根据classpath下可用的jdbc驱动构造相应的payload,实现RCE。

dbcp

分为dbcp1和dbcp2,又分为commons-dbcp和Tomcat自带的dbcp。当 InitialSize > 0 时,会调用 getLogWriter 方法创建数据库连接。提供了不同版本dbcp的RCE方法。

tomcat - jdbc

可使用 org.apache.tomcat.jdbc.pool.DataSourceFactory 实现RCE。

druid

参考《JNDI jdk高版本绕过—— Druid》 ,和dbcp原理一样,可构造相应的 Reference 对象实现RCE。

Deserialize

虽然在查看 ObjectFactory 时发现有几个类有反序列化的地方,但JNDI本身就能反序列化。

引用

https://tttang.com/archive/1405/