环境搭建
下载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
类中
此方法中主要调用了三个方法
getRememberedSerializedIdentity
convertBytesToPrincipals
onRememberedPrincipalFailure
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
字段中即可触发反序列化漏洞。