0x01 前言

来填坑了,拖了很久的shiro721漏洞,涉及的加密解密挺让人头疼的。注:水文,写给自己看的

漏洞影响版本是 1.2.5 <= Apache Shiro <= 1.4.1

以往版本中,AES加密的key是已知固定的,但是在1.2.5版本之后,key就是随机的了,我们不可能猜到随机的key值,但是可以绕过key构造任意密文执行反序列化

0x02 漏洞分析

环境搭建就不多说了,网上有很多的教程。

Apache Shiro Padding Oracle Attack 的漏洞利用必须满足如下前提条件:

  • 开启 rememberMe 功能;
  • rememberMe 值使用 AES-CBC 模式解密;
  • 能获取到正常 Cookie,即用户正常登录的 Cookie 值;
  • 密文可控;

Padding Oracle Attack

以下思路来自此文章:https://goodapple.top/archives/217,并基于此文章做一些简单的说明

Padding 填充,AES是分组加密,消息明文会分为特定长度的分组,比如8字节或者16字节,CBC是分组模式,在分组密码中,有两种常见的填充算法,分别是Pkcs5Padding和Pkcs7Padding。而在shiro框架中采用的是 Pkcs5Padding

举一个例子:明文为abcdefghijk,则分组与填充为

a,b,c,d,e,f,g,h
i,j,k,0x05,0x05,0x05,0x05,0x05

缺多少位,填充多少,如果明文恰好能分组,则填充下一分组全为8个0x08,无论如何都是要有填充的

加密过程与解密过程如下

网上搜的大多都是如何利用 Padding Oracle Attack 来破解明文,而在shiro框架的利用上,我们只需要构造恶意序列化串的合理密文,发送到服务端能顺利解密并且反序列化

以下摘抄与此片文章:浅析Shiro Padding Oracle Attack)

这里简单说下 Padding Oracle Attack 加密数据整体过程:

  1. 选择一个明文 P,用来生成你想要的密文C
  2. 使用适当的 Padding 将字符串填充为块大小的倍数,然后将其拆分为从 1 到 N 的块;
  3. 生成一个随机数据块(C[n] 表示最后一个密文块);
  4. 对于每一个明文块,从最后一块开始:
    1. 创建一个包括两块的密文C’,其是通过一个空块(00000…)与最近生成的密文块C[n+1](如果是第一轮则是随机块)组合成的;
    2. 这步容易理解,就是Padding Oracle的基本攻击原理:修改空块的最后一个字节直至Padding Oracle没有出现错误为止,然后继续将最后一个字节设置为2并修改最后第二个字节直至Padding Oracle没有出现错误为止,依次类推,继续计算出倒数第3、4…个直至最后一个数据为止;
    3. 在计算完整个块之后,将它与明文块 P[n] 进行XOR一起创建 C[n]
    4. 对后续的每个块重复上述过程(在新的密文块前添加一个空块,然后进行Padding Oracle爆破计算);

简单地说,每一个密文块解密为一个未知值,然后与前一个密文块进行XOR。通过仔细选择前一个块,我们可以控制下一个块解密来得到什么。即使下一个块解密为一堆无用数据,但仍然能被XOR化为我们控制的值,因此可以设置为任何我们想要的值。

实际上利用 Padding Oracle Attack 攻击获取明文的原理是理解了,就是不太理解如何合理加密的

0x03 漏洞代码分析

shiro 的 Padding Oracle Attack 攻击就类似与布尔盲注,需要有报错回显

在Apache Shiro的场景中,这个服务端的两个不同的响应特征为:

  • Padding Oracle错误时,服务端响应报文的Set-Cookie头字段返回rememberMe=deleteMe
  • Padding Oracle正确时,服务端返回正常的响应报文内容;

下面分析代码

key的生成

在 AbstractRememberMeManager 类的构造方法中

函数返回值,并不是硬编码了,跟进到 generateNewKey 方法中

init方法主要是对AES算法进行初始化,跟进这个方法

Padding 的错误处理

断点下在解密函数 org.apache.shiro.mgt.AbstractRememberMeManager#decrypt() 中

获取密文,利用decrypt()函数解密,一路跟进crypt

来到doFinal函数,而在这个函数里面,做了一些错误处理,IllegalBlockSizeException 和 BadPaddingException 这两个异常,分别用于捕获块大小异常和填充错误异常,抛出的异常最终由 getRememberedPrincipals 方法捕获

捕获到异常后会执行 onRememberedPrincipalFailure 方法,跟进,

实际上会走到 forgetIdentity 方法

这时候就开始处理请求与响应了,跟进 getCookie().removeFrom

开始设置响应包了,其中 DELETED_COOKIE_VALUE 就是 deleteMe

0x04 漏洞复现

因为要爆破,所以攻击的时间非常长,网上也有那种exp脚本,使用工具ShiroExploit

0x05 结语

水文一篇,主要写一些大致的知识点(写给自己看的)

以下是详细的分析文章:

https://www.mi1k7ea.com/2020/10/14/%E6%B5%85%E6%9E%90Shiro-Padding-Oracle-Attack%EF%BC%88Shiro721%EF%BC%89/#0x01-%E6%BC%8F%E6%B4%9E%E5%8E%9F%E7%90%86

https://goodapple.top/archives/217

https://xz.aliyun.com/t/7207#toc-3