Shiro550漏洞分析
0x01 环境搭建
- jdk8u65
- Tomcat8
- shiro 1.2.4
漏洞影响版本:Shiro <= 1.2.4
shiro550 的根本原因:固定 key 加密
项目地址:
1 | https://github.com/phith0n/JavaThings/tree/master/shirodemo |
0x02 漏洞分析
漏洞原理
用户在登录时勾选了“Remember Me”选项,服务端会生成一个经过 AES 加密(密钥硬编码或可预测)并序列化的 rememberMe Cookie,登录成功后,响应包的 Set-Cookie 头中会出现 rememberMe=deleteMe(用于清除无效 cookie)以及真正的 rememberMe=<base64加密数据>。此后客户端每次请求都会携带该 Cookie,Shiro 默认使用固定密钥(如 kPH+bIxk5D2deZiIxcaaaA==)对序列化对象进行加密。攻击者可以构造恶意反序列化 payload(例如 CommonsCollections 链),用相同密钥加密后作为 rememberMe Cookie 发送。服务端解密并反序列化该 Cookie 时,触发任意命令执行,进而获取服务器权限(getshell)。

Shiro1.2.4 及之前的版本中,AES 加密的密钥默认硬编码在代码里(Shiro-550),Shiro 1.2.4 以上版本官方移除了代码中的默认密钥,要求开发者自己设置,如果开发者没有设置,则默认动态生成,降低了固定密钥泄漏的风险。
漏洞分析
解密过程
入口:CookieRememberMeManager.getRememberedSerializedIdentity()
判断是否为 HTTP 请求,获取 rememberMe Cookie 值
谁调用了 getRememberedSerializedIdentity() 这个方法。找到这里,主要
取出 bytes 数组,调用 convertBytesToPrincipals(bytes)


跟进convertBytesToPrincipals() 方法,将之前的 bytes 数组转换成了认证信息,在 convertBytesToPrincipals() 这个方法当中,很明确地做了两件事,一件是 decrypt 的解密,另一件是 deserialize 的反序列化。

到解密过程之 decrypt() 方法

点进 getDecryptionCipherKey() ,

在点进去decryptionCipherKey参数,发现了setDecryptionCipherKey方法

找谁调用了setDecryptionCipherKey(),最终追溯到 DEFAULT_CIPHER_KEY_BYTES(固定常量)



然后回到convertBytesToPrincipals()方法,跟进deserialize()方法,调用 readObject(),是典型的反序列化入口

加密过程
直接断点到这里

跟进 rememberIdentity() 方法,这里一串调用,保存用户名。

跟进this.rememberIdentity(subject, principals):

进入 convertPrincipalsToBytes() 方法,里面和我们之前看的解密里面的 convertBytesToPrincipals() 非常相似,不过将解密变成了加密,将反序列化改成了序列化。

后续差多,通过 AES 加密之后的 Cookie,拿去 Base64 编码。

所以可构造恶意序列化 payload → 用公开密钥 AES 加密 → Base64 编码 → 放入 rememberMe Cookie 发送 → 服务端解密并反序列化 → 触发 RCE
0x03 Shiro-550 漏洞利用
简单点就直接使用ysoserial生成Payload
常见适用于 Shiro 的链:CommonsBeanutils1、CommonsCollections2、CommonsCollections4、JRMPClient 等
Shiro 框架的 shiro-core 模块强依赖 commons-beanutils。 即使目标应用没有显式引入该库,只要使用了 Shiro 的权限注解(如 @RequiresRoles)、JSP 标签库或某些配置解析功能,Beanutils 就会被自动带入。
但是许多 Shiro 应用可能只引入了 shiro-core,没有附带 commons-collections,但一定有 commons-beanutils。该链将无法直接使用。
无依赖变种(Shiro环境常用):通过使用JDK自带的 String.CASE_INSENSITIVE_ORDER(其内部类 CaseInsensitiveComparator实现了 Comparator且可序列化)作为替代比较器,可以构造不依赖 commons-collections的CB链。这也是Shiro-550漏洞利用中常见的“无依赖”CB链(即CommonsBeanutils1Shiro)的核心思路。
然后py用 Shiro 默认密钥加密并 Base64 编码
1 | import base64 |

随着JDK版本升级(特别是引入JEP 290序列化过滤器等安全机制),CB链的利用可能会受到进一步限制,需要配合其他绕过技术。但这更多是JDK版本而非CB库版本的限制。
0x04 漏洞修复
升级至≥1.2.6版本,官方移除了默认密钥强制要求。在shiro.ini或配置类中设置随机生成的密钥
shiro 在 1.4.2 版本之前, AES 的模式为 CBC, IV 是随机生成的,并且 IV 并没有真正使用起来,所以整个 AES 加解密过程的 key 就很重要了,正是因为 AES 使用 Key 泄漏导致反序列化的 cookie 可控,从而引发反序列化漏洞。

