网页 综合 更新时间 2026-11-13 22:13:49

记一次失败的shiro721bypass(但是成功打通padding oracle(加密层)) - 你好,星 - 博客园

自动蜘蛛 www.cnblogs.com 正文约 3034 字
记一次失败的shiro721bypass(但是成功打通padding oracle(加密层)) - 你好,星 - 博客园
当时闲的没事从网上拉了一个最符合shiro721特征的项目,结果发现加密层都不好打,然后rce层让白名单拦截完了。下面让我们看下这个具体的项目以及破解加密层的思路还有白名单的分析。 https://www.cnblogs.com/nihao-xing/p/23433100 不会基础的看这篇
README.md写的shiro版本1.7.1
如果shiro版本大于1.4.1,shiro721是打不出来的,自己去官网查下影响版本
打开shiroconfig.java 全局搜索文本:CookieRememberMeManager、cipherKey、rememberMe。
setRememberMeManager 说明rememberMe 开启,反序列化入口存在
serialize(写方向)无防护——正常,序列化方向不需要防护 deserialize(读方向)是防护落点——MyClassResolvingObjectInputStream 是核心 思考:这段代码有没有sink? 目前来讲是看不出来的,因为有一个问题。 ta引用了非标准类
MyClassResolvingObjectInputStream点进去看 在MyClassResolvingObjectlnputStream.java
1.白名单进一步分析 白名单策略:只放行 java.lang / java.util 前缀(及 org.apache.shiro.subject.*),其余全部拒绝。 显式拒绝:PriorityQueue、TemplatesImpl(覆盖常见 gadget 的 sink 与触发器)。 这是一个严格白名单,防护强度高。
resolveClass 是 Java 反序列化的"类加载闸门"。重写它做白名单,是最有效的反序列化 RCE 防护手段。审计时要同时检查它有没有遗漏 resolveProxyClass(动态代理接口加载走的是另一个方法)
旁路含义:动态代理(Proxy)的接口加载走 resolveProxyClass,不受白名单约束;但 Proxy 的 InvocationHandler 仍走 resolveClass(被白名单拦)。 我们已经看到了它的白名单 下面我们该干点什么?
1.看 Shiro 过滤链配置 在ShiroServiceImpl.loadFilterChainDefinitions()
最后一行决定 rememberMe 的攻击价值 filterChainDefinitionMap.put("/**", "user"); user ≠ authc。user 表示"记住我或已认证都可以"。说明 rememberMe 反序列化一旦成功,不用重新登录就能访问几乎所有功能。如果最后是 authc,rememberMe 的价值就大打折扣。、 2:从 URL 反查 Controller 全局搜索/passport/signin
定位 submitLogin , 顺藤摸瓜找到 UsernamePasswordToken 思考:为什么要搜索 UsernamePasswordToken "用户名+密码+记住我"这种登录方式,UsernamePasswordToken 是唯一入口——Shiro 源码里 login() 只收 AuthenticationToken 接口,而同时承载"用户名、密码、rememberMe"三要素的实现只有这一个类。所以搜它不会漏。
如果项目用 JWT/OAuth2/自定义 Token(比如 new BearerToken(jwt)),那根本不会出现 UsernamePasswordToken——但那种项目也没有传统 rememberMe,Shiro 反序列化这条链也就无从谈起。
UsernamePasswordToken ctrl+alt+h
PassportController.submitLogin —— 手动登录入口 RememberAuthenticationInterceptor.preHandle —— rememberMe 自动登录入口(无感知升级) 3.我们来拼一下调用链 这个调用链很长
阶段一:写入链(登录 → rememberMe 设置)
这个不能从入口正向跟(ShiroFilter 太深),改用反向追:
每条链追完后,从最底层反向做 Call Hierarchy,确保中间没有缺失的桥接方法:
四条线串完,三份证据(写入、读取、认证)互相印证,没有断层。
这是整个调用链 这调用链这么麻烦 确实麻烦。但 Shiro 是标准化框架,其实不需要逐层追——直接搜关键方法名然后反向拼就够了,五分钟的事:
Shiro 的方法名是稳定 API,每个版本都一样。审计 Shiro 不需要从 submitLogin 一层层下钻,直接搜 Shiro 内部方法名,一步跳到核心逻辑,然后 Ctrl+Alt+H 反向追调用者:
真正需要逐层追的只有项目自定义的部分(MySecSerializer → MyClassResolvingObjectInputStream),那个深度也就两步。
ShiroRealm.doGetAuthenticationInfo:
rememberMe 序列化的对象是 SimplePrincipalCollection(含 Long userId),这是后续反序列化"合法垫子"的明文结构来源。
`AbstractRememberMeManager.getRememberedPrincipals
oracle 判据:响应中 Set-Cookie: rememberMe 是否为非 deleteMe 的新值。
resolveClass 三层白名单挡住所有已知 gadget:
最终结论:加密层(721)可打通,RCE 层(白名单)不可绕过。 5最后给上加密层的Padding Oracle —— 代码与误区分析
结果:HTTP 302 + deleteMe
而 padding 错误的响应也是 HTTP 302 + deleteMe。
结果:padding 合法 → 反序列化成功 → 续期 → HTTP 200 + 新 cookie padding 非法 → 解密失败 → HTTP 302 + deleteMe
篡改密文破坏了第一个对象 → 反序列化失败。追加块不影响第一个对象 → 反序列化成功。
思考最后一个问题:handler 绕过有没有可能
实证确认了 handler 绕过的死结。给出完整分析。
实测 JDK 8 所有 InvocationHandler 实现:
结论:java.lang / java.util / org.apache.shiro.subject.* 白名单内,没有任何一个 InvocationHandler 实现类。 handler 这一环在类名层面就是死路。
handler 无法绕过。 Proxy 反序列化链在 OneBlog 白名单下被三重阻断:
唯一需要补的加固点是 resolveProxyClass 未重写(接口能绕过加载)。但即便补上,也只是堵住一个"理论旁路"——它目前本身就不构成 RCE。真正的安全边界是 resolveClass 的白名单,这一层是硬的,handler 和所有 gadget 都过不去。
访问原文 返回搜索 https://www.cnblogs.com/nihao-xing/p/23645410
本页为82搜索生成的网页快照,内容来自站内索引;演示数据的原文链接仅作示例。