环境配置
- jdk8u65
- Tomcat8
- shiro 1.2.4
漏洞影响版本:Shiro <= 1.2.4
环境配置参考shiro
注意事项:可以将p神项目中的pom.xml更改为1.8版本,要不然可能跑不起来。
shiro-550 漏洞分析

当rememberMe字段开启时,如果登录成功,返回包将会返回Set-Cookie,其中设置rememberMe字段,并且在之后的所有请求的cookie中都会存在rememberMe=字段,可以通过该字段进行反序列化, 从而 getshell。

造成这个漏洞的原因是因为在Shiro1.2.4 及之前的版本中,AES加密的密钥为硬编码在代码里,因此可以伪造rememberMe的加密。
shiro的鉴权功能默认在拦截器中会进行调用,由于ShiroFilter的匹配规则是/*,所以所有的请求都会被他处理,并进行权限校验,具体流程可以参考:https://www.cnblogs.com/77cxw/p/18092865
这里从DefultSecurityManager#createSubject开始分析,这个方法用于创建一个完整的用户主体对象,并且对接受的请求做了一系列操作( 如:复制上下文、处理会话和身份信息等),在处理身份信息的过程中将会触发解密以及反序列化的一系列操作。

跟进resolverPrincipals方法,这个方法拥有处理用户的身份信息,在shiro1.2.4中也就是rememberMe字段。

在resolvePrincipals中,首先获取当前上下文中已存储的身份信息,并判断是否为空,如果为空,则查找并获取之前rememberMe记住的身份信息,也就是进入getRememberedIdentity方法中。

这个方法用于判断rememberMe是否打开,如果不为空,则说明启用了rememberMe功能,继续跟进getRememberedPrincipals方法,这是一个接口方法,具体的实现方法位于org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals

这个方法就是我们获取rememberMe的序列化数据,以及对其进行解密和反序列化操作的方法了,首先可以看到这个方法先从getRememberedSerializedIdentity方法中获取了序列化数据,可以跟进去瞅瞅,也就是org.apache.shiro.web.mgt.CookieRememberMeManager#getRememberedSerializedIdentity这个类继承了AbstractRememberMeManager类,从而实现了getRememberedSerializedIdentity方法。

这个类的主要作用就是获取Cookie中的rememberMe的值,并返回其base64解密后的结果,回到getRememberedPrincipals方法中,在获取到了序列化数据之后,如果不为空,就会进入convertBytesToPrincipals方法中对其进行解密和反序列化操作,也就是decrypt()和deserialize()

decrypt()解密
分析解密的主要原因就是,我们需要伪造一个Cookie值,因此需要获得AES解密的密钥。

进入decrypt()方法,可以看到其解密操作是cipherService.decrypt方法,这个方法获取的第二个参数就是密钥,也就是getDecryptionCipherKey()方法返回的数据。

跟进后发现其返回decryptionCipherKey这个参数,赋值的方法就是下面的setDecryptionCipherKey方法

查找谁调用了这个方法,从而寻找密钥的值,找到setCipherKey方法。

继续查找谁调用了这个方法。

找到AbstractRememberMeManager,并给了一个固定的参数,这个参数在上面有赋值,从而得到固定的key。

deserialize()反序列化

跟进到deserialize()方法里,可以发现这是一个接口,查看实现方法有哪些。

可以找到shiro包里的deserial()方法,其中调用了readObject(),所以存在反序列化漏洞。
加密过程
加密过程通过调试来进行分析,将断点打在onSuccessfulLogin中

跟进到rememberIdentity方法里,这里用于用户名赋值以及保存。

继续跟进到convertPrincipalsToBytes,这里进行了数据序列化操作,以及加密操作。

加密操作和解密是差不多的,进入encrypt()

看到getEncryptionCipherKey()中,继续跟进就可以找到调用的常量和之前的解密的一样。
、
shiro-550漏洞利用
加密
这里直接使用Drunkbaby师傅的脚本
1 | # -*-* coding:utf-8 |
CC11
用之前的链子就行,生成ser.bin然后加密。

CB1
cb链有版本问题,之前用的是1.9.2的,shiro自带的是1.8.3的,更改一下版本就可以了

https://www.cnblogs.com/77cxw/p/18092865
https://y0n3er.github.io/2023/07/Java%E5%AD%A6%E4%B9%A0%E4%B9%8BShiro550/