shiro反序列化漏洞分析

分析源码

我们去源码里面去找找,搜索rememberMe:

发现有一个 CookieRememberMeManager 这个类,看名字就知道他多半就是处理 RememberMe的逻辑,所以根据该类查看它干了什么

这里继承 AbstractRememberMeManager 类,AbstractRememberMeManager提供了创建和验证这些令牌的方法,以及配置cookie属性的方法。

这是CookieRememberMeManager 类的构造函数。首先创建一个名为"rememberMe "的SimpleCookie 对象,并将其设置为HttpOnly 。然后,将cookie的最大生存期设置为一年,以确保用户在一年内不需要重新登录。最后,将cookie对象赋值给类中的cookie属性。这个构造函数的作用是创建一个CookieRememberMeManager对象,并设置默认的"记住我"cookie配置。如果需要更改cookie的配置,可以使用其他构造函数或通过setter方法来更改属性。

继续往下看,感觉这里是重点有没有.......

看类名可以知道此类用于将序列化后的用户身份信息存储到cookie中。

在方法中,首先通过WebUtils.isHttp(subject)方法判断Subject对象是否为HTTP-aware实例。如果不是,则返回并忽略记住我操作。如果Subject对象是HTTP-aware实例,就可以获取到HttpServletRequest和HttpServletResponse对象,从而可以设置cookie。

接下来是对这些对象执行的操作:

  1. 通过WebUtils.getHttpRequest(subject)方法获取HttpServletRequest对象。
  2. 通过WebUtils.getHttpResponse(subject)方法获取HttpServletResponse对象。
  3. 将序列化后的用户身份信息进行Base64编码。
  4. 创建一个新的SimpleCookie对象,并将其值设置为Base64编码后的身份信息。
  5. 将新的cookie对象保存到HttpServletRequest和HttpServletResponse对象中。

所以这个方法的作用是将序列化后的用户身份信息存储到cookie中,并将其保存到HTTP响应中,以便在用户下一次访问网站时自动登录。

方法调用的跟踪

接下来去查看一下该方法在什么地方被调用(快捷键:Ctrl+Alt+Shift+F7)

左下角如果有弹框的话,将所以选项勾上,下拉范围选项框选择所有。

在这可以看到该类继承的AbstractRememberMeManager 类调用了该方法。

发现这个方法被 rememberIdentity 方法给调用了。

在这里会发现 rememberIdentity 方法会被 onSuccessfulLogin 方法给调用,跟踪到这一步,就看到了 onSuccessfulLogin登录成功的方法。

当登录成功后会调用AbstractRememberMeManage.onSuccessfulLogin 方法,该方法主要实现了生成加密的RememberMe Cookie, 然后将RememberMe Cookie 设置为用户的Cookie值。在rememberSerializedIdentity方法里面去实现了。

回到 onSuccessfulLogin 这个地方,这里看到调用了isRememberMe 很显而易见得发现这个就是一个判断用户是否选择了Remember Me选项。

另一方面 rememberIdentity 方法会调用 rememberSerializedIdentity方法,到这里为止,我们已经接触到序列化了。

继续跟踪,有一个叫getRememberedPrincipals 的方法调用getRememberedSerializedIdentity 。看名字就知道 getRememberedPrincipals是一个取得Remember验证的方法。

这里我们再跟进getRememberedPrincipals方法,(快捷键:Ctrl+Alt+h)

我们继续跟踪convertBytesToPrincipals方法

因为convertBytesToPrincipals 方法就是处理getRememberedPrincipals方法 的东西,看名字应该是进行字节转换的。

该方法首先检查是否存在加密服务,如果存在,则使用密钥对字节数组进行解密。接着,该方法使用"deserialize"方法将字节数组序列化。

我们可以先看反序列化

发现有一个反序列化入口 **readObject()**这里就是要利用的点

然后看解码那个地方他的逻辑是如何的

该方法名为"decrypt",有一个参数:"encrypted",代表需要解密的字节数组。

该方法首先将需要解密的字节数组赋值给一个名为"serialized"的新的字节数组。然后,该方法通过调用"getCipherService"方法获取加密服务,如果加密服务存在,则用"getDecryptionCipherKey"方法获取解密密钥,并使用加密服务对字节数组进行解密。解密后,将解密后的结果赋值给"serialized"字节数组。最后,该方法返回"serialized"字节数组,即解密后的结果。

在这里我们需要关注俩个点,接口的抽象方法,有两个参数

第一个是要解密的数据

第二个参数就是解密的key了,这个是我们十分关心的,所以我们跟进第二个参数

跟踪返回 decryptionCipherKey

跟踪 setDecryptionCipherKey方法

跟踪 setCipherKey方法

相关推荐
阿蒙Amon3 分钟前
TypeScript学习-第7章:泛型(Generic)
javascript·学习·typescript
睡美人的小仙女12712 分钟前
Threejs加载环境贴图报错Bad File Format: bad initial token
开发语言·javascript·redis
fanruitian29 分钟前
uniapp android开发 测试板本与发行版本
前端·javascript·uni-app
rayufo32 分钟前
【工具】列出指定文件夹下所有的目录和文件
开发语言·前端·python
RANCE_atttackkk36 分钟前
[Java]实现使用邮箱找回密码的功能
java·开发语言·前端·spring boot·intellij-idea·idea
摘星编程1 小时前
React Native + OpenHarmony:Timeline垂直时间轴
javascript·react native·react.js
缺点内向1 小时前
C#编程实战:如何为Word文档添加背景色或背景图片
开发语言·c#·自动化·word·.net
一起养小猫1 小时前
Flutter for OpenHarmony 实战:记账应用数据统计与可视化
开发语言·jvm·数据库·flutter·信息可视化·harmonyos
zhougl9962 小时前
Java 所有关键字及规范分类
java·开发语言
java1234_小锋2 小时前
Java高频面试题:MyISAM索引与InnoDB索引的区别?
java·开发语言