尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Fastjson 1.2.80 autoType Throwable 异常类绕过分析

Fastjson 1.2.80 autoType Throwable 异常类绕过分析 Fastjson 1.2.80 autoType Throwable 异常类绕过分析写在前面1.2.47 缓存绕过之后官方在 1.2.48 堵了缓存1.2.68 又祭出safeMode这把“终极武器”。但 safeMode 默认不开–只要用户没显式setSafeMode(true)autoType 这扇门就还留着缝。1.2.80 就是顺着这条缝用Throwable异常类配合expectClass机制完成了 autoType 在 safeMode 时代的最后一击。这篇拆expectClass这条常被忽略的路径看 Throwable 是怎么借它绕过黑名单的。纯源码分析无截图。一、漏洞简介漏洞组件Alibaba fastjson影响版本1.2.68 ≤ version ≤ 1.2.80safeMode 之后、1.2.83 修复前漏洞类型autoType 黑名单绕过Throwable expectClass导致反序列化 RCECVE无fastjson 后续绕过均未申请 CVE修复版本1.2.83收窄 expectClass 路径前提未开启 safeModesafeMode 默认 false根因checkAutoType 的expectClass分支在 autoTypeSupportfalse 时仍可加载 expectClass 的子类Throwable 的反序列化路径会把用户可控的类名以expectClassThrowable.class传入绕过黑名单二、1.2.68 safeMode开了才安全先澄清一个误区。1.2.68 引入的safeMode确实是 autoType 的终结技// ParserConfig.checkAutoType (1.2.68)publicClass?checkAutoType(StringtypeName,Class?expectClass){if(safeMode){thrownewJSONException(safeMode not support autoType: typeName);// 直接拒}...}开了 safeModetype一律不认什么绕过都没用。但它默认是 false要用户主动ParserConfig.getGlobalInstance().setSafeMode(true)。绝大多数项目没开–于是 autoType 仍在工作1.2.80 的绕过就是针对这种“没开 safeMode”的默认配置。三、expectClass被忽略的旁路checkAutoType 有个第二参数expectClass平时很少被注意publicClass?checkAutoType(StringtypeName,Class?expectClass)它的本意是当 fastjson 已经知道“这个字段期望的类型是 X”比如某个方法的参数类型是Throwable解析type时传入expectClassX允许加载 X 的子类。这是为正常多态反序列化设计的–比如字段声明的是Exception实际 JSON 里给个具体子类。关键源码1.2.68 ~ 1.2.80简化// checkAutoType (1.2.68核心分支)if(safeMode)throw...;// ① 黑名单仍查longhashfnv1a_64(className);for(inti0;idenyHashCodes.length;i){if(hashdenyHashCodes[i])throw...;}// ② expectClass 旁路★ 关键if(expectClass!null){if(expectClassObject.class||expectClass.isAssignableFrom(/* 待加载类 */)){// 走这条加载 typeName只要它是 expectClass 的子类就放行Class?clazzTypeUtils.loadClass(typeName,defaultClassLoader,false);if(clazz!nullexpectClass.isAssignableFrom(clazz)){returnclazz;// ★ 不强制 autoTypeSupport绕过}}}...注意第 ② 步只要expectClass不为 null且待加载类是它的子类就放行–这条路径不检查 autoTypeSupport。换句话说即使 autoType 关着只要能骗 fastjson 以一个非 null 的expectClass调 checkAutoType就能加载expectClass的任意子类只要不在黑名单。问题变成怎么让 fastjson 用expectClass某个宽泛类型去调 checkAutoType而且这个宽泛类型有“不在黑名单的危险子类”–Throwable 正好满足。四、Throwable 的反序列化路径fastjson 对Throwable/Exception有专门的处理ThrowableReader/ 异常类的 deserializer。当 JSON 里type是java.lang.Exception或 Throwablefastjson 走异常解析分支它会把 JSON 里下一个type具体异常类名以expectClass Throwable.class调 checkAutoType// ThrowableReader 解析异常对象简化StringexClassName/* 读到的第二个 type具体异常类名 */;Class?exClassparser.getConfig().checkAutoType(exClassName,Throwable.class);// ★ expectClassThrowable// - 命中第②步 expectClass 旁路加载 exClass只要它是 Throwable 子类且不在黑名单ObjectexexClass.newInstance();// 填字段异常类的 message、cause 等 setterpayload 雏形两段type{type:java.lang.Exception,type:com.xxx.MaliciousException,field:...}第一个typejava.lang.Exception进 Throwable 解析分支Throwable 本身不在黑名单。第二个typecom.xxx.MaliciousException被 ThrowableReader 以expectClassThrowable.class调 checkAutoType。命中 expectClass 旁路只要MaliciousException是 Throwable 子类且不在黑名单就放行加载。五、利用链需要一个 Throwable 子类 gadget绕过黑名单只是“能加载类”要 RCE 还得这个类有副作用。这里和前几篇不一样1.2.80 本身只提供“加载任意 Throwable 子类”的能力gadget 得自己找。常见的姿势找一个构造方法或 setter 里有 JNDI/反射/加载动作的 Throwable 子类通常在第三方库里。比如某些库的自定义异常在构造时会记录上下文、加载资源被挪用成触发点。典型 PoC 常结合 Groovy、Spring 等库里的特定异常类具体哪个类随依赖而变核心是“它是 Throwable 子类 有副作用”。typejava.lang.Exception - 进 Throwable 解析分支 └ 第二个 type某 Throwable 子类(不在黑名单) └ checkAutoType(name, Throwable.class) └ expectClass 旁路 - 加载该异常类(autoTypeSupport 不查) └ 实例化 setter/构造副作用 - RCE所以 1.2.80 的利用门槛比 1.2.24/1.2.47 高–它要目标 classpath 上有合适的 Throwable gadget。但“能绕过黑名单加载任意 Throwable 子类”这一步本身已是 autoType 防线的失守。六、修复1.2.83 收窄 expectClass1.2.83 的修复针对 expectClass 旁路对expectClass路径也加上更严格的校验收紧哪些 expectClass 允许走旁路或对 Throwable 这类宽泛基类的子类也过黑名单// 1.2.83 思路简化expectClass 旁路也要过黑名单if(expectClass!null){// 不再无条件放行子类先过黑名单longhashfnv1a_64(className);for(inti0;idenyHashCodes.length;i){if(hashdenyHashCodes[i])throw...;}// 且 expectClass 必须在允许的范围内如非 Object/Throwable 这种过宽基类...}同时官方再次强调真正可靠的修复是开启 safeMode。只要 safeMode 开着第 ② 步根本走不到checkAutoType 顶部就抛异常了expectClass 旁路无从发挥。七、小结1.2.80 这篇我们看到 autoType 防线在 safeMode 时代的最后一道裂痕旁路参数也是攻击面expectClass本是为多态设计的“信任通道”但只要它存在且不检查 autoTypeSupport就成了绕过黑名单的侧门。任何“为方便而开的信任通道”都要问它能不能被外部输入触发默认配置是安全水位线safeMode 默认 false意味着绝大多数用户其实没受保护。一个“要手动开才安全”的防御等于把安全责任推给用户–而用户多半不会开。gadget 可移植1.2.80 把“加载任意类”收窄到“加载任意 Throwable 子类”提高了门槛但没堵死。只要 classpath 上有合适的异常类 gadget仍可 RCE。至此 fastjson 的 autoType 绕过史–从 1.2.24 裸奔、1.2.41 前后缀、1.2.47 缓存、到 1.2.80 Throwable–就走完了。最后那篇防御演进我们看官方是怎么一步步把这些洞堵上、最终走向 safeMode 的。参考fastjson GitHubhttps://github.com/alibaba/fastjson系列前篇1.2.24 autoType 分析、1.2.41-43 黑名单绕过、1.2.47 缓存绕过
返回列表