高版本JDK下JNDI漏洞利用方法精简总结
编辑前言
高版本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#eval
和 groovy.lang.GroovyShell#evaluate
这两个方法可只传一个String参数执行攻击代码,且依赖库常见,因此被经常使用。
可用的利用类
MLet:JDK自带的
javax.management.loading.MLet
类,继承自URLClassloader,有一个无参构造方法和addURL(String)
、loadClass(String)
方法。可用于gadget探测,但单靠ClassLoader.loadClass
无法触发static代码块,暂时无法RCE。GroovyClassLoader:原理和MLet基本相同,可实现RCE,但由于已有
groovy.lang.GroovyShell
可用,该类价值不大。SnakeYaml:
new org.yaml.snakeyaml.Yaml().load(String)
符合条件,依赖库使用比Groovy更常见,有一定利用价值。XStream:
new com.thoughtworks.xstream.XStream().fromXML(String)
符合条件,可用于攻击。MVEL:入口
org.mvel2.MVEL#eval(String)
因无参构造方法是private修饰,不符合条件,但可从org.mvel2.sh.ShellSession#exec(String)
进入,通过执行内置命令调用MVEL.eval
解析表达式。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
中取出 pathname
、readonly
参数赋值,然后调用 open()
和 save()
方法。
XXE漏洞
open()
方法会根据 pathname
发起本地或远程文件访问,使用commons-digester解析返回的XML内容,存在XXE漏洞。
RCE漏洞及利用方法
问题分析:在Linux系统下,由于目录跳转问题,需要在
CATALINA.BASE
文件夹下创建特定目录,可使用BeanFactory
执行创建目录的利用类,如org.h2.store.fs.FileUtils#createDirectory(String)
。利用方法:
创建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本身就能反序列化。
引用
- 0
- 0
-
分享