Jackson反序列化漏洞简介(三): JsonTypeInfo的用途

之前有段时间在搞jackson反序列化漏洞的检测,网上看到各种各样的文章,很多抄来抄去的,真是辣鸡,虽然我不懂,但也知道他们有些人在胡扯。本系列文章系统地介绍java里的json反序列化漏洞成因、防御方式、检测方式、利用方式。因为本人接触这些不久,如有错误,还请大佬留言指正。

本文是第三篇,讲之前漏掉的一种可以进行漏洞利用的写法。

一、JsonTypeInfo

先看一段代码,我们没有开启EnableDefaultTyping ,但是在类的字段里添加了一个修饰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
public int age;
public String name = "default";
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
public Object object;

Person() {
System.out.println("Person.init()");
}

@Override
public String toString() {
return String.format("Person.age=%d, Person.name=%s, %s", age, name,
object == null ? "null" : object);
}
}

打出来了

{"age":10,"name":"Alice","object":{"@class":"com.leadroyal.example.Dna","length":100}}

我们明明没有EnableDefaultTyping,但这里还是出现了类的名字。。。。。这是为什么 JsonTypeInfo有5个取值,分别是

1
2
3
4
5
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonTypeInfo(use = JsonTypeInfo.Id.COSTOM)

下面我们一一介绍,其中有些是可以被反序列化时进行代码执行的。

二、详细

JsonTypeInfo.Id.NONE

输出

{"age":10,"name":"Alice","object":{"length":100}}

在没有注解的情况下,可以每个字段都可以认为是NONE,也就是最最最普通的处理,是安全的、不会被攻击的,因为字符串里根本没有包含类的信息进去。

JsonTypeInfo.Id.CLASS

输出

{"age":10,"name":"Alice","object":{"@class":"com.leadroyal.example.Dna","length":100}}

是有类的信息的,显然这个和之前的利用方式一样,而且确实可以利用,

Exp为

{"age":10,"name":"Alice","object":{"@class":"com.leadroyal.example.Vuln","cmd":"calc.exe"}}

JsonTypeInfo.Id.MANIMAL_CLASS

输出

{"age":10,"name":"Alice","object":{"@c":"com.leadroyal.example.Dna","length":100}}

区别之一是用 @c 代替 @class,更短一点,区别之二是使用了更短的类名(这个例子里没有体现出来,因为不知道怎么构造,但官方文档是这么说的),主要是为了寻找方便,验证通过,确实可以利用,Exp为

{"age":10,"name":"Alice","object":{"@c":"com.leadroyal.example.Vuln","cmd":"calc.exe"}}

JsonTypeInfo.Id.NAME

输出

{"age":10,"name":"Alice","object":{"@type":"Dna","length":100}}

但是,反序列化失败了,提醒我Dna不是一个Object,ExcuseMe?你自己序列化过的自己不会反,岂不是在逗我么。。。

这时候把Person里的代码改成Dna object ,才可以被反出来,也就是说,一定一定要是一模一样的类型才会给反(经过尝试,子类都不给反的)

这次的比较奇怪,没有带包名也可以被反出来,这种写法第一反应是肯定会有冲突的,毕竟类SimpleName被撞掉还是可以的,但尝试了很多次,没有撞成功,仍然可以被正确反出来。这个也是符合预期的,因为是按照Java里的定义,去加载这个json;而不是按照json的定义,去创建java结构体。所以这种情况是无法利用的。

JsonTypeInfo.Id.CUSTOM

这个无法直接用,需要手写一个解析器才可以配合使用,所以直接回抛出异常。

三、结论

JsonTypeInfo.Id.CLASSJsonTypeInfo.Id.MANIMAL_CLASS 仍然是不安全的,无论开启EnableDefaultTyping 与否,用它来修饰的字段是Object的话,攻击者就可以控制类型,从而有被RCE的风险。