Apache shiro一个开源框架,提供身份验证、授权、密码学和会话管理。

Apache shiro<1.2.4 版本存在反序列化漏洞

原理

shiro的记住我的功能,是通过cookie的rememberMe值来实现,当后端接收到来自未经身份验证的用户请求时,后端将执行以下操作来寻找记住的身份

  • 检索cookie中的rememberMe的值
  • base64解码
  • 使用AES加密
  • 反序列化

漏洞主要是存在AES采用的是CBC加密模式,密钥是写死在代码里的也就是说,我们只要拿到了密钥,就能够构造恶意代码来触发反序列化漏洞。

搭建

环境搭建 git clone https://github.com/apache/shiro 加载maven的pom.xml文件 然后编辑shiro\samples\web的pom.xml中的pom.xml文件:

  1. <dependency>
  2. <groupId>javax.servlet</groupId>
  3. <artifactId>jstl</artifactId>
  4. <!-- 这里需要将jstl设置为1.2 -->
  5. <version>1.2</version>
  6. <scope>runtime</scope>
  7. </dependency>

image.png 配置好本地tomcat即搭建完成。

分析

搭建好tomcat后,将断点下在org/apache/shiro/mgt/RememberMeManager.java#onSuccessfulLogin,开始debug。
image.png
输入密码进行登陆,勾选上RememberMe选项,程序会暂停在断点处:
image.png
首先调用forgetIdentity构造方法处理request和response请求,包括在response中加入cookie信息,然后调用rememberIdentity函数,来处理cookie中的rememberme字段。我们f7跟进rememberIdentity函数:
image.png
rememberIdentity方法首先会调用getIdentityToRemember函数来获取用户的身份,这里是“root”,接着进入rememberIdentity的构造方法;
image.png
跟进#convertPrincipalsToBytes:
image.png
跟进#encrypt:
image.png
encrypt函数就是调用AES加密对序列化后的”root”进行加密,加密的密钥由getEncryptionCipherKey()得到,跟进getEncryptionCipherKey()函数会发现其值为常量:
image.png
回到#rememberIdentity函数进入#rememberSerializedIdentity方法中:
对其进行base64编码,且设置到cookie中。
image.png

总结

所以我们在勾选rememberMe时后端进行如下操作

  • 序列化用户的身份“root”
  • 对root进行AES加密,密钥为常量
  • base64进行编码
  • 设置cookie的rememberMe的值