Demo
最基础的操作
1 | public class Student { |
序列化操作
1 | import com.fasterxml.jackson.databind.ObjectMapper; |
反序列化操作
1 | import com.fasterxml.jackson.databind.ObjectMapper; |
只使用默认提供的这几个方法是没有什么安全漏洞的,但是需要去对一些特殊类(接口、抽象类等)进行序列化操作时,就需要下面的数据绑定了
多态类型数据绑定
对于有多个子类型的多态集成结构的对象,Jackson在序列化的时候加入一些类型信息,可以在反序列化的时候准确的还原某个类型的子类
主要有两种方式实现:
- 全局Default Typing机制
- JsonTypeInfo注解
DefaultTyping
有四个选项:
- JAVA_LANG_OBJECT:当对象属性类型为Object时生效
- OBJECT_AND_NON_CONCRETE:当对象属性类型为Object或者非具体类型(抽象类和接口)时生效。
默认的、无参的enableDefaultTyping属于该等级
- NON_CONCRETE_AND_CONCRETE:同上, 另外所有的数组元素的类型都是非具体类型或者对象类型
- NON_FINAL:对所有非final类型或者非final类型元素的数组
假设有一个存在危险函数的类,反序列化该类
1 | import com.fasterxml.jackson.databind.ObjectMapper; |
运行结果
成功反序列化,并且自动触发了类中的setter()和构造方法。也就是说,开启了这个功能,就可以反序列化任意类了
JsonTypeInfo注解
同样的,Jackson提供了@JsonTypeInfo
注解来开启多态类型的处理,使用这个注释可以更精细的定制序列化的JSON文件格式。
1 | "@Clazz") (use = JsonTypeInfo.Id.CLASS,include = JsonTypeInfo.As.PROPERTY,property = |
- use:定义使用哪一种类型识别码,有五种可选值
- JsonTypeInfo.Id.NONE
- JsonTypeInfo.Id.CLASS
- JsonTypeInfo.Id.MANIMAL_CLASS
- JsonTypeInfo.Id.NAME
- JsonTypeInfo.Id.CUSTOM
- include(可选):指定识别码是否出现在进去的
- property(可选):指定识别码的名称,默认是@Class
这个注解可以直接放在类上,也可以放在某个属性上,序列化时并不需要开启DefaultType
1 | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
NONE
序列化结果:
1 | {"name":"yoga","age":20,"obj":{"age":32}} |
表示不使用识别码,序列化后的数据不包含类信息等,无法利用
CLASS
序列化结果:
1 | {"name":"yoga","age":20,"obj":{"@class":"jackson.rce.Teacher","age":32}} |
表示使用完全限定类名做识别,@class中有详细的类名称,可以用来反序列化任意类
POC:
1 | {"name":"yoga","age":20,"obj":{"@class":"jackson.rce.demo","cmd":"calc"}} |
MINIMAL_CLASS
序列化结果:
1 | {"name":"yoga","age":20,"obj":{"@c":"jackson.rce.Teacher","age":32}} |
表示若基类和子类在同一包类,使用类名(忽略包名)作为识别码,同样@c中有详细的类名称,可以用来反序列化任意类
POC:
1 | {"name":"yoga","age":20,"obj":{"@c":"jackson.rce.demo","cmd":"calc"}} |
NAME
序列化结果:
1 | {"name":"yoga","age":20,"obj":{"@type":"Teacher","age":32}} |
表示自定义的指定名称,虽然@type中有类名,但是缺少包信息,无法利用
CUSTOM
表示自定义识别码,直接反序列化会抛异常需要自定义的解析器去实现
Conclusion
开启了DefaultTyping以及@JsonTypeInfo的Class和Minimal_Class是不安全的,可以用来反序列化任意类
反序列化流程
在readValue()和构造函数Teacher()处断点,寻找如何反序列化Teacher类的,调用栈
之前都是构造和处理参数的,直接断点在deserialize()
这里的_vanillaProcessing为true,所以调用vanillaDeserialize()
,跟进方法
一进来方法又调用createUsingDefault(),继续跟进
使用annotations去反射实例化Teacher类调用构造方法,并返回给vanillaDeserialize中的变量bean。而后又调用了deserializeAndSet()
在这里用反射的方法去调用setter方法,给反序列化的对象赋值
CVE-2017-7525
TemplatesImpl链
利用条件限制
- 开启了enableDefaultTyping或者@JsonTypeInfo的
CLASS
和Minimal_Class
- Jackson < 2.7.10 or Jackson < 2.8.9
- JDK7u21以下的环境(这里使用7u21)
POC
1 | import com.sun.org.apache.xalan.internal.xsltc.DOM; |
使用的是廖大神的POC:传送门
漏洞分析
在readValue()处和getOutputProperties()进行断点,查看调用栈
在getBinaryValue()中调用decodeBase64()对传入的数据进行解码
然后,直接来到deserializeAndSet()
很明显,这里本来是通过反射调用对应的setter方法,但是对于变量outputProperties
并没有对应的setter方法,此时他就会去调用getter方法,也就是开始了getOutputProperties()链,与此前的fastjson的过程一样
1 | getOutputProperties() -> newTransformer() -> getTransletInstance() -> AbstractTranslet.newInstance() -> Runtime.exec() |
但是在jdk1.8的某个版本后(1.8.0_102不行),defineTransletClasses()中新增了对_tfactory的处理,但是无法给它赋值,所以会抛出异常,导致poc无法生效
漏洞补丁
这里很明显是使用黑名单的方式来限制反序列化的类,于是乎就有了CVE-2017-17485等后续漏洞
CVE-2017-17485
利用Spring spel来RCE的,这里先复现一下,等学习一波spel之后再补
利用条件限制
- 开启了enableDefaultTyping或者@JsonTypeInfo的
CLASS
和Minimal_Class
- 版本
- 影响:version<= 2.9.3 or version <= 2.7.9.1 or version <= 2.8.10
- 不受影响:2.9.3.1、2.7.9.2、2.8.11
漏洞环境
CVE-2019-12384
简要分析
利用条件限制
- 2.X < 2.9.9.1
- 同时需要序列化和反序列化操作(比较鸡肋了)
- RCE的话还需要
h2database
依赖
POC
1 | import com.fasterxml.jackson.databind.ObjectMapper; |
打上断点直接来看调用栈
反序列化流程和之前的一样,然后反射调用setUrl()方法给url赋值,继续跟进,然后就结束了反序列化流程回到了主函数中。进入序列化流程
在序列化流程中,所有的属性都会遍历一遍,然后去寻找getter()方法,调用getDriverClass和getUrl后,再调用getConnection(),这里的url的值为反序列化时赋予的,可控。
这里就发起请求,造成SSRF
SSRF To RCE
H2是非常快速的一个内存SQL数据库,通常是作为全功能版SQL数据库管理系统(比如Postgresql、MSSql、MySql或者OracleDB)的替代方案。H2配置起来非常方便,并且也支持许多模型,比如内存部署、文件部署或者远程服务器部署。H2可以通过JDBC URL运行SQL脚本,该功能主要目的是方便内存数据库进行
INIT
迁移。如果单有该功能,攻击者并不能在JVM上下文中执行Java代码。然而,由于H2在JVM框架内实现,因此支持指定包含java代码的自定义别名。
通过sql来调用java代码,继续回到getConnection()
这里获取init属性,也就是jdbc url中的SQL命令
executeUpdate()执行init中的语句
漏洞补丁
还是将DriverManagerConnectionSource
类加入黑名单
Reference
http://codelife.me/blog/2012/11/03/jackson-polymorphic-deserialization/
https://b1ue.cn/archives/189.html
https://github.com/shengqi158/Jackson-databind-RCE-PoC