Shiro反序列化分析笔记
This_is_Y Lv6

# 环境搭建

下载 https://codeload.github.com/apache/shiro/zip/refs/tags/shiro-root-1.2.4

java版本为:

idea打开其中的 /shiro-shiro-root-1.2.4/samples/web。pom中如下设置。

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

image-20240318153850052

添加一个Tomcat本地服务,设置好不冲突的端口和工件。

image-20240318154015281

点击启动后如果不报错,就会自动打开浏览器。

image-20240318154212422

流程分析

加密及登陆过程

首先可以在/shiro-core/1.2.4/shiro-core-1.2.4-sources.jar!/org/apache/shiro/mgt/AbstractRememberMeManager.java中找到传说的硬编码的aes密钥

image-20240319111143843

一个登陆流程是先从executeLogin() -> subject.login(token) -> securityManager.login(this, token) ,在这个login里面,info = authenticate(token);是负责验证帐号密码是否成功的,

image-20240319114353409

跟进后一路到了doAuthenticate()中,这里通过getRealms()获取到数据源,然后通过doSingleRealmAuthentication()方法,对用户输入的帐号密码进行验证,之后返回info信息。

回到securityManager.login(this, token)中,在获取到info成功后,就会向下走到onSuccessfulLogin(token, info, loggedIn); -> rememberMeSuccessfulLogin(token, info, subject) -> rmm.onSuccessfulLogin(subject, token, info); 然后就到了AbstractRememberMeManager.java中,先使用forgetIdentity(subject);清除之前的Identity,然后创建新Identity(防止之前的认证信息被复用)。

image-20240319163300897

之后进入 rememberIdentity(subject, token, info); -> rememberIdentity(subject, principals); -> convertPrincipalsToBytes(accountPrincipals);在这里面先将身份信息序列化为byte数组,再encrypt()加密,返回。返回后回到rememberIdentity()中,再进入rememberSerializedIdentity(subject, bytes);

image-20240319164055280

rememberSerializedIdentity()中。把加密的密文base64后,就设置为cookie返回了。

image-20240319171042013

解密流程

在上面convertPrincipalsToBytes(accountPrincipals);中,有一个encrypt(),进入AbstractRememberMeManager.java中找到encrypt(),decrypt()就在下面。

image-20240319171911418

参考

https://www.freebuf.com/articles/web/318142.html

https://su18.org/post/shiro-1

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
访客数 访问量