前言
shiro-550漏洞的产生源自硬编码问题,在 1.2.4之前,密钥在代码中是固定的
而在1.2.5 <= Apache Shiro <= 1.4.1,我们再看AbstractRememberMeManager类,已经修改为生成随机的密钥
在本篇文章中,分析着重于代码方向,至于加密算法和测信道攻击,之前接触的较少。在这方面我处于能理解,但是让我来说,感觉还是很难说明白的阶段,可以多看看其他大佬的文章,交叉印证学习
1.漏洞原理
Shiro-721漏洞的产生源自AES-128-CBC模式,它受CBC字节反转攻击和Padding Oracle Attack(侧信道攻击)的影响,导致可以从一个正常的rememberMe的值基础上,根据Padding Oracle Attack的原理,通过爆破构造出恶意的RememberMe,重新发送到服务器端进行解析并触发反序列化达到RCE的效果
影响版本:Apache Shiro <= 1.4.1
2.环境搭建
- jdk8u65
- tomcat8 (https://tomcat.apache.org/download-80.cgi?Preferred=https%3A%2F%2Fdlcdn.apache.org%2F)
- 整合的shiro-721网站测试项目( https://github.com/jas502n/SHIRO-721/blob/master/samples-web-1.4.1.war)
2.1 项目搭建
下载项目之后,先解压,然后在idea中创建一个web-app 的 maven arch项目,然后项目解压后的拖入到webapp中
添加Tomcat并设置部署后直接启动即可
3.漏洞分析
3.1 密钥生成过程
具体的shio登录和验证过程分析之前在Shiro550那一篇分析中有详细的,咱们这篇就不详细过了
Shiro-550详细分析
我们进行一次rememberMe登录,并在AbstractRememberMeManager.encrypt方法打下断点
继续前进,到达加密这部分,我们看下getEncryptionCipherKey方法
我们可以看下这个是直接返回的值,进一步分析由来在最初,没有直接赋值,通过setCipherKey方法获得的值赋给加密密钥和解密密钥
我们查看generateNewKey方法
因为这一步算是初始化中,调试的话需要重新启动调试,并不是在登录过程中触发,直接打断点是触发不了的
init方法完成了初始化密钥生成器,然后再generateKey方法中生成密钥
使用 this.random 随机数生成器生成随机字节,并填充到 var2 数组中再返回SecretKeySpec对象
最后回到最初,通过getEncoded方法获取密钥序列
3.2 漏洞点分析
我们发现版本更新点以后,那么这个漏洞产生在什么地方呢,我发现网上大部分的文章都说是要进行Padding Oracle Attack来攻击漏洞,但是分析下来感觉对但是有的又说的不是很全面
3.2.1 Padding Oracle Attack
填充提示攻击( Padding Oracle Attack ),Padding的含义是“填充”,在解密时,如果算法发现解密后得到的结果,它的填充方式不符合规则,那么表示输入数据有问题,对于解密的类库来说,往往便会抛出一个异常,提示Padding不正确
但是它本身的使用是有条件的
1.攻击者能够获得密文,以及密文对应的初始化向量iv
2.攻击者能够触发密文的解密过程,并且能够知道密文的解密结果是否正确
3.2.2 满足条件一
我们首先分析条件一是怎么满足的,获得密文以及密文对应的初始化向量iv,咱们这个漏洞的前提就是有一个正常登录的rememberMe,所以密文条件直接达成
密码学里的iv,并没有保密性的要求,所以对于使用CBC Mode的加密算法来说,iv经常会随着密文一起发送。常见的做法是将iv作为一个前缀,附着在密文的前面。对于CBC Mode来说,iv的长度必须与分组的长度相等。
在进行加密的过程中,我们可以看到iv的产生,也就是ivBytes的值,为[-113, 11, 31, 89, 56, 39, 100, 25, 117, -77, -99, 81, 42, -30, -67, -110]
然后看整体aes加密后的值,iv的值[-113, 11, 31, 89, 56, 39, 100, 25, 117, -77, -99, 81, 42, -30, -67, -110]就在开头
所以我们通过解密获得的一个正常登录shiro的rememberMe,base64解码之后的首位16个字节就是此次的iv
3.2.3 满足条件二
条件二为能够触发密文的解密过程,并且能够知道密文的解密结果是否正确
我们查看解密过程,直接定位到AbstractRememberMeManager.decrypt方法
这里CipherService接口类decrypt()函数的实现类是org/apache/shiro/crypto/JcaCipherService类,decrypt()函数就是调用JcaCipherService类的decrypt()函数,我们逐步往下看
这就是整个解密的过程,我们可以看到如果中间出什么错误的时候,只有一个捕获错误的,会抛出一个CryptoException异常
在dofinal方法中有 IllegalBlockSizeException和BadPaddingException 这两个异常,分别用于捕获块大小异常和填充错误异常,如果触发了会抛到crypt方法的异常捕获里
最终被getRememberedPrincipals() 方法捕获,并执行 onRememberedPrincipalFailure() 方法
最终会调用removeFrom(),在响应头部中添加字段Set-Cookie: rememberMe=deleteMe
所以如果Padding结果不正确的话,响应包就会出现Set-Cookie: rememberMe=deleteMe
我们利用这个机制,可以进行类似布尔盲注的攻击,通过观察有没有这个字段来判断有没有成功
3.3 CBC字节翻转攻击和Padding Oracle Attack
在算法分析方面这里只是简单说一下,更加详细的可以看看以下两位师傅的分析,非常明了
https://goodapple.top/archives/217
https://www.mi1k7ea.com/2020/10/14/%E6%B5%85%E6%9E%90Shiro-Padding-Oracle-Attack%EF%BC%88Shiro721%EF%BC%89/#0x06-%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90
3.3.1 CBC字节反翻转攻击
CBC字节翻转攻击是一种对分组密码的攻击,属于侧信道攻击。这种攻击针对的是CBC Mode,而不是某一种具体的分组密码算法。
CBC加密过程:
1.将需要加密的数据分组
2.第一个分组的明文在加密之前先和iv进行异或计算,然后进行加密运算
3.从第二组开始,所有的明文先于前一分组加密后的密文进行异或,然后进行加密运算
4.将所有加密后的密文组拼接到一起就是加密后的密文了
解密过程:
1.第一组密文在解密之后与初始向量iv异或得到第一组明文
2.第二组密文解密之后和第一组密文异或得到第二组明文
3.以此类推,得到所有明文组,最后拼接就是加密前的明文
也就是说,解密一组明文需要本组和前一组的密文。
CBC字节翻转攻击的核心原理是通过破坏一个比特的密文来篡改一个比特的明文。
通过CBC字节翻转攻击,假如我们能够触发加解密过程,并且能够获得每次加密后的密文。那么我们就能够在不知道key的情况下,通过修改密文或IV,来控制输出明文为自己想要的内容,而且只能从最后一组开始修改,并且每改完一组,都需要重新获取一次解密后的数据,要根据解密后的数据来修改前一组密文的值。
3.3.2 Padding Oracle Attack
Padding Oracle流程:
- 当收到一个有效的密文(一个被正确填充并包含有效数据的密文)时,应用程序正常响应(200 OK)
- 当收到无效的密文时(解密时填充错误的密文),应用程序会抛出加密异常(500 内部服务器错误)
- 当收到一个有效密文(解密时正确填充的密文)但解密为无效值时,应用程序会显示自定义错误消息 (200 OK)
我们可以使用程序的行为来确定提供的加密值是否被正确填充,在上面的代码分析中,我们分析出shiro中,如果填充不正确,那么在返回包中就会出现deleteMe字段
3.4 攻击分析
我们在了解了算法和代码结合产生的漏洞点之后,应该怎么利用Padding Oracle Attack
构造密文的步骤:
从最后一组开始,爆破出该组的intermediary并构造出iv,然后将本组的iv当作前一组的密文
爆破前一组的intermediary并构造出iv,然后将本组的iv当作前一组的密文
…
最后会得到第一组的iv,至此已经构造出了所有合法密文以及iv
tips:在CBC加密的过程中,流程是先把明文和iv进行异或,将异或得到的值称为intermediary,然后把intermediary进行加密得到最后的密文
3.5 后续修补
在Shiro 1.2.4之后,shiro放弃了CBC加密,引入了GCM加密方式
具体代码变化
https://github.com/apache/shiro/commit/a8018783373ff5e5210225069c9919e071597d5e#diff-d61135f70077e55187e227aa61a3f72eef52568787ecbd59913e8a609b35019c
4.参考
https://www.mi1k7ea.com/2020/10/14/%E6%B5%85%E6%9E%90Shiro-Padding-Oracle-Attack%EF%BC%88Shiro721%EF%BC%89/#0x06-%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90
https://goodapple.top/archives/217