Padding Oracle Attack 初探

时隔多年之后终于开始写下转到新博客之后的第一篇技术文了!流下了感动的泪水!


  • 立个flag,每个月更新一篇安全研究
  • [其实一开始想两周的,想了一想,还是不要作死好了]
  • 关于Padding Oracle Attack 的原理以及后文的一些脚本借鉴于道哥的《白帽子讲web安全》

Padding Oracle Attack 原理剖析

Padding Oracle Attack

Padding Oracle Attack是在Eurocrypt2002大会上,Vaudenay所介绍的一种针对CBC模式的攻击方法。它可以在不知道密钥的情况下,通过对padding bytes的尝试,获取加密过程中的Intermediary Value,从而还原明文或构造出任意明文的密文

加解密原理

分组加密算法在实现加解密时,需要把消息进行分组,分组(block)的大小一般有64bit,128bit,256bit等。
本文以CBC模式为例,对攻击原理进行简单的阐述。

我们以8个字节一个block为例,首先将第一组的明文与初始iv进行异或之后进行相应的加密算法运算。计算完第一组后,将第一组获得的密文作为第二组的iv进行运算,如此类推,得到所有明文加密的结果。
如果在这个加密的过程中,最后一个分组的消息长度(明文长度)没有达到block的大小,则需要对其填充一些字节(padding)。

上图padding例子使用现行最常见的padding标准PKCS#5。当需要填充1个字节时,填充值为0x01;当需要填充2个字节时,其填充值为0x02,0x02;当需要填充3个字节时,其填充值为0x03,0x03,0x03……

类似的,解密过程与加密过程类似。首先将第一分组的密文进行解密运算,之后与初始iv进行异或,得出对应的明文。计算完第一分组后,将第一分组的密文作为第二分组的iv参与运算,如此类推得到所有分组密文的解密结果。
加解密原理大致阐述了一下,读者还记得上面提到的Padding Oracle Attack的特点吗?即在不知道密钥的情况下,还原明文或构造出任意明文的密文。所以下面请将注意力转移到解密部分,我们来仔细分析解密部分的一些特点,想办法做出Padding Oracle Attack的功能。

攻击原理

在密钥一定的情况下,对密文进行解密算法运算,我们是可以得出一个与明文唯一对应的密文。在上文所说的解密过程中,进行解密算法运算只是每一组运算中的一个步骤,接下来是另一个步骤,即异或出结果。在这个过程中,使用解密算法运算得出的密文我们将其称为Intermediary Value。

小结一:每组密文解密所得到的Intermediary Value都是固定的(因为与明文唯一对应),而我们暂时不知道它的值(因为我们不知道密钥)


接下来我们来分析异或部分

可以看到,Intermediary Value ⊕ iv = 明文。
请再次仔细想一想,在不知道密钥的情况下,还原明文或构造出任意明文的密文。所以,我们可以认为明文已知。
又因为Intermediary虽然未知,但是它的值是固定的,因此我们可以将上面这个表达式转换为
明文 = Intermediary Value ⊕ iv
所以,我们慢慢调整iv的值,以期得到与我们想要的明文一致的iv值,并一个字节一个字节的尝试,直到得出分组所使用的iv值。(iv每一个字节从0x00到0xFF进行尝试)

小结二:通过上面的推断,我们已经获取到了iv和明文值

继续看这个公式 明文 = Intermediary Value ⊕ iv
我们继续做一下转换
Intermediary Value = 明文 ⊕ iv
因为明文和iv都已知了,因此我们可以通过异或得到Intermediary Value的值。Intermediary Value已知,那么我们就可以通过Intermediary Value ⊕ 我们想要的明文 => 得到对应的iv
推导出最后一个分组使用的iv后,将此iv作为第一个分组的密文,再次进行推导,以此类推,便可以找到解密为任意明文的密文和iv对了

总结:明文 = Intermediary Value ⊕ iv

通过推导,我们可以得到解密为任意明文的密文和iv对,达成了既定目标。这里值得注意的是,需要对密文进行解密才能得出对应的Intermediary Value,因此如果我们在没有密钥的情况下,需要通过一定的办法,触发app的解密程序,获取Intermediary Value,从而继续我们上面对iv的推导。

Padding Oracle Attack 攻击实例(CTF题目)

题目来源

常见的一道基础CBC翻转字节攻击

题目关键代码(伪代码)

做题步骤

  • 1.源码泄露
  • 2.代码审计

题目核心逻辑伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
第一次访问:
登录,输入用户名和密码,其中用户名不允许输入admin
对用户名和密码序列化后作为aes-128-cbc加密明文,随机生成16字节字符串作为iv;并设置$_SESSION['username']为传入的用户名
对第二步产生的密文和iv分别作为cookie,使用setcookie为用户设置这两个cookie
---
第二次访问:
对用户提交的cookie(cipher,iv)进行检测,如果存在继续下面的操作
使用提交的cookie进行解密运算,对解出的密文进行反序列化
设置$_SESSION['username']为反序列化后获得的用户名
---
逻辑判断:
首先不允许直接设置用户名为admin
如果$_SESSION['username'] == admin,则获得flag

所以我们可以知道,考点在于使用服务器为用户设置的密文和iv,进行某些操作,使得密文解密后的用户名为admin

解题方法

1.利用网上到处都是的CBC翻转字节攻击代码进行
2.利用《白帽子讲web安全》内的Padding Oracle Attack的示例代码进行攻击(修改过的脚本代码附后)
我们在这里使用第二种方法进行,由于存在源码泄露,我在源码中找到了加密密钥,因此我不需要对触发app的解密代码来获取Intermediary Value。可以直接使用密钥进行解密运算,从而获取解题所需的密文和iv对。

获取到密文和iv对之后,我们替换掉原先设置的密文和iv对,即可getflag。

章节小结

实际上这里取巧了,获得了题目加密的密钥。如果题目不能获取到密钥的话(实际攻击场景中常见),需要对脚本进行一些修改,触发攻击对象的解密程序,获取Intermediary Value。

Padding Oracle Attack 脚本修改中的一些思考

实际上写下这篇博文也是因为这个思考,最近所在的实验室办校内ctf比赛。作为客服的我无聊看了一下web题,又无意中突然发现题目的密钥长度没有达到算法预期,不禁产生了疑问。所以下面部分是对PHP的openssl_encrypt/openssl_decrypt 中对key处理的研究

问题来源

源码跟进分析


可以看到,我们在使用openssl_encrypt函数时,输入的key(密钥)即是图中的参数password,而在第6624行中,密钥作为形参传到了一个名为”php_openssl_cipher_init”的函数中,我们继续跟进。

可以看到在函数中的第6511和第6512两行中,分别获取了用户输入的密钥长度和加密算法对应的规定密钥长度,显然,我们想要找到处理就在这个地方,继续往下看。

图片上我加了注释,解释应该十分清晰了。

脚本修改

根据上面得出的处理结果,对攻击脚本进行修改(主要增加密钥处理功能)

脚本源码

https://github.com/Porlockzzz/attackScript/blob/master/padding_oracle_attack.py

0%