Fastjson 1.2.24 反序列化漏洞:从原理到实战的深度拆解
如果你是一名Java开发者,或者对应用安全领域有所涉猎,那么“Fastjson反序列化漏洞”这个词组对你来说一定不陌生。它几乎成了近年来Java生态中影响最广、讨论最多的安全议题之一。特别是CVE-2017-18349,这个编号背后代表的是Fastjson 1.2.24及之前版本中一个极其危险的远程代码执行漏洞。网上关于如何“复现”这个漏洞的文章汗牛充栋,但大多停留在“照葫芦画瓢”的步骤罗列上,对于漏洞为何能发生、利用链是如何一步步构建起来的,往往语焉不详。
今天,我们不打算再重复那些简单的复现步骤。相反,我们将深入Fastjson的“腹地”,从源码层面剖析JdbcRowSetImpl这个看似普通的JDBC工具类,是如何被编织进一条通往远程命令执行的致命链条中的。我们不仅会看“是什么”,更要弄清楚“为什么”,并探讨在不同JDK版本环境下,攻击与防御的微妙博弈。无论你是想加固自己的应用,还是希望深入理解Java反序列化漏洞的机理,这篇文章都将为你提供一个坚实的技术视角。
1. 漏洞的根源:Fastjson的AutoType机制与设计取舍
要理解CVE-2017-18349,首先必须搞懂Fastjson一个核心但危险的设计:AutoType。
在标准的JSON序列化/反序列化中,一个JSON对象{"name":"Alice","age":30}被还原成Java对象时,反序列化库需要知道它应该被实例化成哪个具体的类。通常,这需要开发者显式指定目标类,例如JSON.parseObject(jsonString, User.class)。但Fastjson为了提供更大的便利性,引入了一个特性:允许在JSON字符串中通过一个特殊的键@type来指定目标类的全限定名。
{
"@type": "com.example.User",
"name": "Alice",
"age": 30
}
当Fastjson解析到@type时,它会尝试使用Class.forName()或类似的机制去加载并实例化com.example.User这个类。这个功能的本意是好的,它使得泛型处理、多态类型的序列化变得更加灵活。然而,安全领域的铁律之一是:“反序列化不可信数据是危险的”。当AutoType面对一个精心构造的、指向危险类的@type值时,灾难就开始了。
Fastjson 1.2.24及更早版本中,AutoType功能默认是开启的,并且没有任何有效的黑名单或白名单机制来限制可以反序列化的类。这意味着,攻击者可以指定任何存在于目标应用类路径(Classpath)中的类,Fastjson都会乖乖地将其实例化。
注意:这里的关键在于,Fastjson在反序列化过程中,不仅会创建对象,还会根据JSON中的键值对,自动调用对象中对应的setter方法或直接访问public字段来为属性赋值。这正是漏洞利用的“扳机”。
那么,攻击者会选择哪个类作为攻击的起点呢?一个理想的“攻击起点类”(通常称为Gadget)需要满足几个条件:
- 存在于大部分Java环境的默认类库中(攻击成本低)。
- 在其setter或getter方法中,存在可能触发危险操作(如网络连接、文件操作、代码执行)的逻辑。
- 这些危险操作的参数,可以通过JSON属性来间接控制。
com.sun.rowset.JdbcRowSetImpl这个JDK自带的类,完美地符合了以上所有条件。
2. JdbcRowSetImpl:被精心设计的“完美受害者”
JdbcRowSetImpl是Java标准库中javax.sql.rowset包下的一个类,它实现了JdbcRowSet接口。简单来说,它是一个在内存中缓存数据库查询结果的数据集对象,支持通过JNDI(Java Naming and Directory Interface)查找数据源。正是这个JNDI查找功能,成为了漏洞利用的突破口。
让我们直接切入核心,看看JdbcRowSetImpl中关键的setAutoCommit方法:
public void setAutoCommit(boolean autoCommit) throws SQLException {
if (this.conn != null) {
this.conn.setAutoCommit(autoCommit);
} else {
this.conn = this.connec


783

被折叠的 条评论
为什么被折叠?



