环境搭建
下载shiro源码
1 | git clone https://github.com/apache/shiro.git |
修改pom文件,添加如下内容:
1 | <!-- 需要设置编译的版本 --> |
修改完成后使用mvn命令编译war包:mvn package -DskipTests,在target目录下生成war包移动到tomcat webapps目录下启动Tomcat即可成功部署。
参考:https://paper.seebug.org/shiro-rememberme-1-2-4/
rememberMe反序列化分析
通过web.xml可以看到每次请求web都会进入到ShiroFilter,并进行相应的链式处理。
此filter的最上层为javax.servlet.Filter,即是Servlet规范中的Filter接口

在org.apache.shiro.web.servlet.OncePerRequestFilter正常流程最后会调用doFilterInternal方法。
此方法为为一个抽象方法,那么实现应该是在其子类中,根据上面的ShiroFilter的继承图可看到OncePerRequestFilter的子类为AbstractShiroFilter.
此方法中调用了createSubject方法跟进后发现是调用了org.apache.shiro.subject中的buildSubject方法

继续跟进,SecurityManager是一个接口类实现方法中在org.apache.shiro.mgt.DefaultSecurityManager 中
其中又调用了resolvePrincipals方法,此方法调用了getRememberedIdentity方法,接着又调用了RememberMeManager的getRememberedPrincipals方法

此类是一个接口类,实现在AbstractRememberMeManager类中
此方法中主要调用了三个方法
getRememberedSerializedIdentityconvertBytesToPrincipalsonRememberedPrincipalFailure
getRememberedSerializedIdentity:
此方法为抽象方法实现在其子类CookieRememberMeManager中
在其构造方法中创建另一个名为rememberMe的cookie,
1 | public CookieRememberMeManager() { |
getRememberedSerializedIdentity方法主要是获取了请求包中的cookie的内容,如果cookie中的rememberMe的值不为deleteMe则进行base64解密返回。
接着回到getRememberedPrincipals方法中来,如果getRememberedSerializedIdentity返回的内容不为空则进入到convertBytesToPrincipals方法中。

此方法先对getRememberedSerializedIdentity返回的内容进行解密,
1 | protected byte[] decrypt(byte[] encrypted) { |
使用了AES加密

再然后进入到deserialize方法,实际是执行了org.apache.shiro.io.DefaultSerializer中的deserialize方法。
可以明显的看到这里进行了反序列化操作。
回顾下cookie中的流程:
获取Cookie中的rememberMe字段的内容->base64解密一次->aes/cbc解密->反序列化
那么如果知道aes加密的key,将恶意代码序列化后加密放入cookie中的rememberMe字段中即可触发反序列化漏洞。