PaddingOracle攻击原理

admin 2022年3月28日09:27:41评论247 views字数 4477阅读14分55秒阅读模式

编者注:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责。


根据加解密时是否用同一组密钥,可以分为对称加密和非对称加密。对称加密中根据对数据处理粒度的不同,可以分为分组加密算法(AES、3DES、DES、Blowfish、RC2、CAST)和流加密算法(ChaCha20、Salsa20、RC4)


●常见的非对称加密算法有RSA、ElGamal、DSA、ECC等


分组加密算法中根据加解密时对数据的分组编排方式,经典工作模式有ECB、CBC、PCBC、CFB、OFB、CTR等,其中后三者可以将分组加密转化为流加密形式。为了在保证机密性的前提下进一步保证完整性,现代工作模式有CCM(CBC-MAC)、EAX、GCM、SIV(Synthetic Initialization Vector)、OCB(Offset CodeBook)等。


分组加密方式简介


分组加密方式只能使用一个固定大小的密钥加密相同字节长度的明文,所以需要将加密的明文按照密钥大小拆分为多块(所以也叫块加密),如果拆分后最后一个块明文长度不够,就需要填充字节来补齐长度。按照常见的PKCS#5或PKCS#7标准,最后需要填充几个字节,那么所填充的字节的值就用几;如果明文最后一个块刚好满足长度大小,那就需要填充完整一个块。


举个例子,对称密钥为 12345678 时长度为8,当待加密的明文为 abcdefg 时其长度为7,填充后的块为 [a][b][c][d][e][f][g][0x01] ;当待加密的明文为 abcdefghabcdef 时其长度为14,填充后的块为 [a][b][c][d][e][f][g][h][a][b][c][d][e][f][0x02][0x02] ;当待加密的明文为 abcdefgh 时其长度为8,填充后的块为 [a][b][c][d][e][f][g][h][0x08][0x08][0x08][0x08][0x08][0x08][0x08][0x08]


异或和可逆性


异或的概念对于二进制位而言,就是两个位不同则得到1,两个位相同则得到0。比如:


1 ^ 1 = 01 ^ 0 = 10 ^ 1 = 10 ^ 0 = 0


可以看出异或的结果与参与运算的两个值先后顺序没有关系,按小学的说法可以称为异或交换律。= =


再看仔细一些可以知道,如果A^B=C,那么A^C=B、B^C=A,说明异或具有可逆性。

两个十进制的异或就是都转为二进制再逐位异或。两个字节的异或,就是对字节取ASCII码(十进制)再。。。两个长度相同字符串的异或就是逐字节。。。所以字符串的异或本质就是二进制位的异或,这说明异或的可逆性同样适用于字符串。


 CBC工作模式简介


PaddingOracle攻击原理


Plaintext指明文块,Ciphertext指密文块,key指对称密钥, 符号表示异或。


IV(Initialization Vector)是每次加密时都应随机生成的一串与分块大小相同的随机值,随机IV的存在使得相同的对称密钥加密两次相同的明文也会得到不同的密文,规避了ECB模式相关安全问题。如果某些具体实现中IV重复使用或是可以预测,亦或是使用全0的IV则会导致明文块泄漏,但这不是本文讨论的重点。


加密时先将第一块明文与初始IV异或,再将异或后的块用对称密钥加密得到第一块密文。第一块密文会作为第二块的IV,与第二块明文异或后再用对称密钥加密得到第二块密文,直到最后一块密文加密完成。


●从第二块明文开始,每块明文加密都需要用到上一块的密文作为IV,加密过程无法并行 


解密时先将密文用对称密钥解密得到一个中间值,将此中间值与IV异或得到明文。注意我现在没有说第一块了,因为IV此时都是已知的,每两个密文块就可以解出一个明文块,解密过程可以并行。


因为解密第一块密文时需要初始的IV,而初始IV在密码学中本就没有保密性要求,通常都会将初始IV拼接到密文头部一起发给客户端(至于为什么拼接在头部而不是尾部或是单独分开,因为上一块密文就是下一块密文IV,拼接到头部其实就是让IV作为第零块密文,顺其自然地成为第一块密文的IV)。


PaddingOracle


PaddingOracle一般是指对称加密算法CBC工作模式的一种攻击方式。如果能够区分密文解密出错的原因,是由于填充错误(比如填充的 [0x01][0x02] ),还是由于正常解密出的明文在具体的业务环境中报错(比如判断role是 admin 还是 member ,结果解密出来是 !@#$ ),就能在不知道对称密钥的情况下,利用错误回显或是时间延迟的侧信道,爆破和推测出密文被对称密钥解密后的中间值,进一步可以推测出密文被完整解密后的原始明文,或是利用中间值结合可控的IV逆推构造出想要的明文。


●利用错误回显或是时间延迟做判断的这个过程就称为oracle


推导明文


下面来分析下具体流程,我们先从多个加密块的第一个块说起,我将密文块被对称密钥解密后的值称为中间值,中间值与IV异或后会得到完整解密的明文块。


首先需要思考的是,解密时如何判断填充的字节有没有出错呢?答案是从完整解密后的明文块最后一个字节开始读,如果发现最后一个字节是 0x03 ,那么就继续读倒数第二个字节、倒数第三个字节并确认其都是 0x03 ,如果倒数第二或第三个字节不是 0x03 就说明出现了填充错误。


那么通过某种手段使明文最后一个字节为 0x01 时,读完最后一个字节后就不会再向前校验了,所以这个块无论如何都不会出现填充错误。明文最后一个字节是由中间值最后一个字节与IV最后一个字节异或而来,那么就存在以下推导:


# 必然存在一个guess_iv[-1]值符合guess_iv[-1] ^ middle[-1] = 0x01# 根据异或可逆性反推出真实中间值middle[-1]middle[-1] = guess_iv[-1] ^ 0x01# 得到真实中间值middle[-1]后,与原本的iv[-1]算出真实的明文plain[-1]plain[-1] = iv[-1] ^ middle[-1]


虽然但是,那怎么知道这个必然存在的值是什么呢?在IV可控且能区分出有没有填充错误时,我们可以对IV最后一个字节进行爆破,如果不是这个 必然存在的值 ,解密后明文最后一个字节不是 0x01 就会出现填充错误,没有填充错误时就说明我们爆破到了这个 必然存在的值 。因为1个字节是8个二进制位,最多只需要爆破2的8次方=256次就可以得到。


●可能有小伙伴会说假如这个块本身就是填充的 0x02 呢,那解密成 0x02 0x01 就都不会出现填充错误,注意开头说了我们目前分析的是多个加密块的第一个块,这种情况下第一个块不可能出现填充字节,而正常的明文一般也不会出现 0x02 ,更多细节我们稍后讨论


知道中间值最后一个字节后,我们就能继续推导构造后两个字节的明文值,进而得到倒数第二个字节的中间值:


# 我们已经知道中间值最后一个字节guess_iv[-1] ^ middle[-1] = 0x02# 可以直接逆推出需要构造的guess_iv[-1]guess_iv[-1] = middle[-1] ^ 0x02# 同样的方法爆破出guess_iv[-2]guess_iv[-2] ^ middle[-2] = 0x02# 进一步推导出中间值middle[-2]middle[-2] = guess[-2] ^ 0x02# 得到真实中间值middle[-2]后,与原本的iv[-2]算出真实的明文plain[-2]plain[-2] = iv[-2] ^ middle[-2]


重复这个套路,可以一直向前爆破和推导出这个块中间值和明文的每个字节,再对每个块重复这个套路就可以得到每个块中间值和明文的每个字节,与正常解密过程一样可以并行处理。这里清晰后就是时候讨论我们一直刻意忽略的,只有一个块或是最后一个块的填充问题了。


如果填充值是 0x03 或更大,由于是从后往前推出 [0x01][0x02][0x02] ,存在多位相互校验就不会出现Oracle时的误判。而不论明文刚好本身倒数第二个字节是 0x02 还是最后一个块填充后有两个 0x02 ,都有可能出现明文最后一个字节首先爆破成的是 0x02 (而非 0x01 ),但由于不会出现填充错误,导致我们误以为使用这个guess_iv[-1]实际构造的出的是 0x01


在群里讨论后,@香依香偎 师傅给出的思路是在最后一个填充字节判断成功的情况下,构造倒数第二字节为任意值都不出现填充错误,就说明倒数第一个字节确实构造成了 0x01 ,也就是上文所说的情况了;而如果构造倒数第二字节时出现了填充错误,就说明我们构造出的明文最后一个字节其实是 0x02 (妙啊)。同时@Vanish 牛也提醒了,在这种得到错误 middle[-1] 的情况下,进行后续步骤就会出错。所以这种情况推导 middle[-1] guess_iv[-1] ^ 0x02 就行了。


构造密文


理解了推导明文的过程,构造密文(也称为CBC翻转)就很简单了。爆破推测出每一个字节的中间值,调整各个IV的各个字节使其与中间值异或后就是我们想要的明文:


# 推导需要构造出的IVmiddle[i] ^ admin[i] = iv[i]# 中间值与构造的IV异或后会得到想要的明文middle[i] ^ iv[i] = admin[i]


由于第N块密文的IV就是第N-1块密文本身,所以我们需要从后向前先推出最后一块、再倒数第二、第三。。。一直推到第一块并构造出需要的原始IV,其实就是个逆序加密的过程,与正常加密过程一样不能够并行处理。


没有IV与IV不可控


设想一种没有IV且IV不可控的情况,服务器端加密 xxx: abc; user: member;... 原始信息,只将加密后的密文作为Cookie发往浏览器,而将用于加密的初始IV维护在服务器Session中,此时得不到初始IV也就没法套路出第一块密文的明文块了(但中间值还是能推测出来的),后续密文块的IV就是前一个密文块,所以第一块之外的密文还是能解出明文。对于CBC翻转来说,第一块明文的内容就没法构造了,为了配合后续块解密,被我们构造出的第一块密文也会被初始IV异或得不成样子。


假如此时通过某种途径泄漏出了Session里的初始IV,也就是有初始IV但IV不可控的情况,那么就能完整解密出包括第一块在内的全部明文。CBC翻转情况不变。


又假如通过某种途径导致Session里的初始IV可控(但读不到原本的初始IV),也就是没有初始IV但IV可控的情况,那么就能完整构造出包括第一块密文在内的全部密文。明文解密情况不变。


所以能不能读到初始IV影响原本第一块明文的解密,初始IV可不可控影响第一块明文的构造。



参考内容


Cipher block chaining (CBC)


Automated Padding Oracle Attacks With PadBuster


Padding Oracle Attack的一些细节与实现


PaddingOracle攻击原理
PaddingOracle攻击原理

默安科技安全研究院旗下团队,“逐日”寓意为追逐技术永不停歇,专注于安全攻防研究,包括漏洞挖掘、逆向工程、红蓝对抗、代码审计、产品赋能等方向。



本文始发于微信公众号(默安逐日实验室):PaddingOracle攻击原理

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月28日09:27:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PaddingOracle攻击原理http://cn-sec.com/archives/536995.html

发表评论

匿名网友 填写信息