DFA攻击背景介绍

传统的密码安全性分析环境被称为黑盒攻击环境,攻击者只能访问密码系统的输入与输出,但随着密码系统部署环境的多样化,该分析模型已经不能够反映实际应用中攻击者的能力。2002年,Chow等人[1]提出了白盒攻击环境的概念,该攻击环境中的攻击者对算法运行环境具备完全的控制权,并且完全掌握算法的设计细节。白盒攻击环境中攻击者的能力包括但不限于:动态观测算法程序运行过程、修改算法程序运行过程中的中间值、对算法程序进行调试分析等,其中包括了差分计算分析(DCA)。

差分计算分析(DCA):DCA不需要攻击者掌握算法的设计细节,只需要采集算法程序在运行过程的中间状态,通过相应的统计分析方法提取密钥。DCA分析只需要掌握白盒实现的底层算法,能够监测白盒实现程序的运行过程即可进行分析,极大地降低了分析的部署难度。

与DCA相似的,Sanfelix,Mune和de Haas在BlackHat Europe 2015上成功提出了针对相同白盒挑战的差分故障分析(DFA)攻击,也就是我们今天要研究的差分故障分析攻击。在大部分白盒攻击模型中,故障非常容易执行且成本低廉,并且不会导致程序自我毁灭

AES算法介绍

AES是著名的非对称算法,通过每轮变换的轮密钥实现加密。它由 10、12 或 14 轮(分别用于 AES-128、AES-192 和 AES-256)组成)通过重复操作逐步转换 16 字节输入。在AES-128里,第一轮的密钥就是AES的密钥,而在AES-256里,第一轮的密钥被拆分为两个轮密钥。

而问题就出在这里,在白盒里面,密钥不会从原地进行轮密钥加,而是在生成白盒时预先计算的,而且轮密钥加会混合在其他轮次中来进行隐藏。

AES的整个加密解密流程如下图



AddRoundKey (轮密钥加)— 矩阵中的每一个字节都与该次轮密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。

**SubBytes(字节替代) **— 通过非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。

**ShiftRows(行移位) **— 将矩阵中的每个横列进行循环式移位。

MixColumns (列混淆)— 为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每列的四个字节。

DFA分析AES-128加密

DFA 攻击的一般要求是:

  • 输出必须在没有外部编码的情况下可观察(直接在密码末尾或解码后在应用程序中的其他地方)。
  • 必须能够在同一输入(可以是编码的或未知的)上多次执行密码。在几轮后捕获 AES 的状态并多次恢复它也是一种选择。

由AES加密算法流程可以看出,第10次轮秘钥加之前是没有列混淆的。

所以我们可以知道第九次轮密钥加之前是这样的:



如果我们在第九轮列混淆之前构造如下两组数据:



可以看出这两组数据只有第一个数据不一样,以当前状态继续进行,那么作为状态矩阵的输入就会影响到其余地方,由于

通过上述表达式推算,可以得到一组K10的(0,7,10,13)的位置值,同理,如果换成其他位置的值,可以得到K10的其他位置值,从而推算得到整个K10的值,再根据AES秘钥拓展算法(),最终可以还原原始的加密秘钥。

实战

2023巅峰极客逆向 m1_read

ida打开附件,findcrypto一下发现很明显的AES加密



但是找了很久都没有找到密钥,于是可以联想到是白盒AES(别问怎么联想的),用大爹的模拟执行代码进行还原密钥

我们借用qiling框架来模拟程序执行。

参数传入

函数开头传⼊参数, rcx 存储输⼊的地址

def hook_args(ql: Qiling):
ql.mem.write(0x500000000, b"\x01" * 16)
ql.arch.regs.write("rcx", 0x500000000)
#print(ql.mem.read(0x500000000, 16))
ql.mem.write(0x500000000 + 0x10, b"\x00" * 16)
ql.arch.regs.write("rdx", 0x500000000 + 0x10)
ql.mem.write(0x500000000 + 0x20, b"\x00" * 16)
ql.arch.regs.write("rbx", 0x500000000 + 0x20)
#print("Hook Success")
return
start_addr = 0x140004BF0
ql.hook_address(hook_args, start_addr)

找到插入缺陷数据的地方

上文中,我们说过要将构造多组数据将AES的密钥攻击出来,而我们是在第九次进行轮密钥加之前加入的这种数据,这种数据后文叫缺陷数据。

找到列混合的地方可以很快找到轮密钥加,在本题中我们很容易找到一个对16位字符进行操作的函数,可以肯定这就是列混合的地方。



往下翻,就能找到轮密钥加的地方



每轮v6加了1024*4个字节,也就是1000个字节,在经过八次相加之后就是8000,在这之后加入缺陷代码



在汇编层面上就是下面的代码

def hookcode(ql:Qiling):
if ql.arch.regs.read("r12") == 0x8000:
global index
#第一次需要获取正确的密文,所以不需要插入\x00,也就是说下面的write第一次不用写
ql.mem.write(0x500000000 + index,b'\x00')
index += 1
#此处是获取正确的密文
#print(ql.mem.read(0x500000000,16).hex())
#print(ql.mem.read(0x500000000,16))
return
index_addr = 0x1400052c5#这个地址就是判断是否到第酒次的地址
ql.hook_address(hookcode,index_addr)

获取密文

找到定义密文的地方,如下图所示





所以可以直接hook这个地址,拿到密文

def hook_enc(ql:Qiling):
print(ql.mem.read(0x500000000,16).hex)
return
enc_addr = 0x1400053ca
ql.hook_addr(hook_enc,enc_addr)

运行两次(每次的运行代码不同)验证正确密文和错误密文,看结果是否满足白盒AES原理



可以看出,分别得到了正确密文为

e14d5d0ee27715df08b4152ba23da8e0

第九轮列混淆时,错误的密文为

d24d5d0ee27715ac08b4bf2ba272a8e0

在第0,7,10,13个字节分别与正确密文有错误,和原理一致。

获取所有错误密文

写个for循环即可得到剩下的密文,整个代码如下

from qiling import *
from qiling.const import QL_VERBOSE index = 0
ql = Qiling(
["/home/nian/桌面/examples/m1_read.exe"],
r"/home/nian/桌面/examples/rootfs/x86_windows",
verbose=QL_VERBOSE.OFF,
) def hook_args(ql: Qiling):
ql.mem.write(0x500000000, b"\x01" * 16)
ql.arch.regs.write("rcx", 0x500000000)
#print(ql.mem.read(0x500000000, 16))
ql.mem.write(0x500000000 + 0x10, b"\x00" * 16)
ql.arch.regs.write("rdx", 0x500000000 + 0x10)
ql.mem.write(0x500000000 + 0x20, b"\x00" * 16)
ql.arch.regs.write("rbx", 0x500000000 + 0x20)
#print("Hook Success")
return def hook_code(ql: Qiling):
if ql.arch.regs.read("r12") == 0x8000:
global index
ql.mem.write(0x500000000 + index, b"\x00")
index += 1
#print(ql.mem.read(0x500000000, 16).hex())
#print(ql.mem.read(0x500000000 + 0x10, 16))
return def hook_enc(ql: Qiling):
print(ql.mem.read(0x500000000, 16).hex())
return index_addr = 0x1400052C5
start_addr = 0x140004BF0
end_addr = 0x14000542D
enc_after = 0x1400053CA
ql.hook_address(hook_args, start_addr)
ql.hook_address(hook_code, index_addr)
ql.hook_address(hook_enc, enc_after)
# e14d5d0ee27715df08b4152ba23da8e0
# e14d5d73e27708df0878152b843da8e0
for i in range(16):
ql.run(begin=start_addr, end=end_addr)

得到如下错误密文

"""d24d5d0ee27715ac08b4bf2ba272a8e0
e14d5d73e27708df0878152b843da8e0
e14dd50ee23415df7fb4152ba23da890
e16f5d0e537715df08b415e7a23dc6e0
e11a5d0e057715df08b4151ba23d99e0
574d5d0ee277157508b4df2ba234a8e0
e14d5d49e27785df0840152bff3da8e0
e14db80ee2d215dfceb4152ba23da868
e14dc60ee2bf15dfc4b4152ba23da8bf
e1425d0e5e7715df08b415b6a23d4ce0
5d4d5d0ee277159608b42f2ba297a8e0
e14d5d6ce2773ddf089d152ba93da8e0
e14d5dcde2772adf084b152bba3da8e0
e14df40ee27115df96b4152ba23da881
e11b5d0e337715df08b41544a23df3e0
fa4d5d0ee27715af08b42e2ba2c2a8e0"""

还原第十个密钥

现在已知了正确的密文和所有的错误密文,可以用phoenixAES工具来还原原理中提到的k10

https://github.com/SideChannelMarvels/JeanGrey/tree/master/phoenixAES

代码如下:

import phoenixAES

with open("tracefile","wb") as t:
t.write(
""" e14d5d0ee27715df08b4152ba23da8e0
d24d5d0ee27715ac08b4bf2ba272a8e0
e14d5d73e27708df0878152b843da8e0
e14dd50ee23415df7fb4152ba23da890
e16f5d0e537715df08b415e7a23dc6e0
e11a5d0e057715df08b4151ba23d99e0
574d5d0ee277157508b4df2ba234a8e0
e14d5d49e27785df0840152bff3da8e0
e14db80ee2d215dfceb4152ba23da868
e14dc60ee2bf15dfc4b4152ba23da8bf
e1425d0e5e7715df08b415b6a23d4ce0
5d4d5d0ee277159608b42f2ba297a8e0
e14d5d6ce2773ddf089d152ba93da8e0
e14d5dcde2772adf084b152bba3da8e0
e14df40ee27115df96b4152ba23da881
e11b5d0e337715df08b41544a23df3e0
fa4d5d0ee27715af08b42e2ba2c2a8e0
""".encode("utf-8")
)
phoenixAES.crack_file("tracefile",verbose=0)



运行后得到k10

"""B4EF5BCB3E92E21123E951CF6F8F188E"""

还原原始密钥

得到第十轮的密钥后,就可以着手还原原始密钥了,用到的工具是Stark

https://github.com/SideChannelMarvels/Stark

下载好stark之后要记得在文件目录下面make把三个c文件编译成可执行文件,再用可执行文件操作,如下图



这样一来,就得到原始密钥key0了

"""00000000000000000000000000000000"""

再利用原始密钥解密原始密文,即可得到明文

解密



out.bin里面的密文

"""0B987EF5D94DD679592C4D2FADD4EB89"""

解密即可得到明文

from Crypto.Cipher import AES

enc = bytearray(bytes.fromhex("0B 98 7E F5 D9 4D D6 79 59 2C 4D 2F AD D4 EB 89"))
enc = bytes([enc[i] ^ 0x66 for i in range(16)])
key = bytes.fromhex("00000000000000000000000000000000")
aes = AES.new(key=key, mode=AES.MODE_ECB)
print(aes.decrypt(enc))

运行,得到flag

上述就是基本的AES差分故障分析方法和例题,而除了AES之外,还有DES和SM4的白盒,它们和AES的故障攻击方法基本大同小异

这里给出研究SM4的博客供大家(wo)学习

https://www.anquanke.com/post/id/231483

白盒AES和SM4实现的差分故障分析的更多相关文章

  1. GTest Google的一种白盒单元测试框架 开源项目

    GTest为google开源的白盒单元测试跨平台测试框架,含丰富的断言.类型参数化测试.死亡测试.以及其他的测试选项设置.文件保存等,以下将对该项目C++的实现进行简要的分析,作为学习记录备份. 基本 ...

  2. JAVA语言搭建白盒静态代码、黑盒网站插件式自动化安全审计平台

    近期打算做一个插件化的白盒静态代码安全审计自动化平台和黑盒网站安全审计自动化平台.现在开源或半开源做黑盒网站安全扫描的平台,大多是基于python脚本,安全人员贡献python脚本插件增强平台功能.对 ...

  3. 浅析白盒审计中的字符编码及SQL注入

    尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范.但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如g ...

  4. JAVA白盒安全测试需要关注的API

    JAVA白盒安全测试需要关注的APIhttp://blog.csdn.net/testing_is_believing/article/details/19502167

  5. 亿能测试白盒安全测试模板V1.0发布

    亿能测试白盒安全测试模板V1.0发布http://automationqa.com/forum.php?mod=viewthread&tid=2911&fromuid=21

  6. 移动測试技术保护源码!解码全球首款移动端白盒測试工具ThreadingTest (文章转自己主动点科技)

    作者 智晓锋 - 2014/07/14 自从斯诺登曝光美监听丑闻事件之后,我国政府就将信息安全问题上升到了国家安全的高度.基于此.国内的一家创业公司推出了智能型Android真机白盒測试以及开发辅助类 ...

  7. SafeNet推出行业首款白盒password软件保护解决方式

    数据保护领域的全球率先企业SafeNet公司日前宣布,推出行业首款採用白盒安全技术的的软件保护方案.SafeNet 圣天诺 软件授权与保护解决方式如今纳入了新的功能,可在"白盒" ...

  8. testing and SQA_动态白盒測试

    一.软件測试技术: 黑盒:在不知道程序内部结构,仅仅知道程序结构的情况下採用的測试技术或策略. 白盒:在知道程序内部结构的情况下採用的測试技术或策略. 两种測试方法从不同的角度出发,反映了软件的不同側 ...

  9. 商业级别Fortify白盒神器介绍与使用分析

    转自:http://www.freebuf.com/sectool/95683.html 什么是fortify它又能干些什么? 答:fottify全名叫:Fortify SCA ,是HP的产品 ,是一 ...

  10. 白盒-CNN纹理深度可视化: 使用MIT Place 场景预训练模型

    MIT发文:深度视觉的量化表示................ Places2 是一个场景图像数据集,包含 1千万张 图片,400多个不同类型的场景环境,可用于以场景和环境为应用内容的视觉认知任务. ...

随机推荐

  1. npm ERR! shasum check failed for

    nmp install 爆了一片错 npm WARN optional SKIPPING OPTIONAL DEPENDENCY: ios-deploy@1.9.4 (node_modules\wee ...

  2. Vue跨域配置异常采坑:Request failed with status code 401

    本地用Express作为服务端,前端Vue项目配置跨域代理,调用服务端api接口始终报错"Request failed with status code 401".原来发现是端口3 ...

  3. Rust 通用编程概念

    通用编程概念 变量.基本类型.函数.控制流 变量与可变性 rust中的变量默认是不可变的,这样是为了能够让你安全并且方便地写出复杂.甚至并行的代码. 当一个变量是不可变时,一旦它绑定到了某个值上面,这 ...

  4. Taro项目引入Tailwindcss

    前情 Tailwind CSS 是一个原子类 CSS 框架,它将基础的 CSS 全部拆分为原子级别,同时还补全各种浏览器模式前缀,兼容性也不错.它的工作原理是扫描所有 HTML 文件.JavaScri ...

  5. 通用密钥,无需密码,在无密码元年实现Passkeys通用密钥登录(基于Django4.2/Python3.10)

    毋庸讳言,密码是极其伟大的发明,但拜病毒和黑客所赐,一旦密码泄露,我们就得绞尽脑汁再想另外一个密码,但记忆力并不是一个靠谱的东西,一旦遗忘密码,也会造成严重的后果,2023年业界巨头Google已经率 ...

  6. 【TVM模型编译】0.onnx模型优化流程.md

    本文以及后续文章,着重于介绍tvm的完整编译流程. 后续文章将会按照以上流程,介绍tvm源码.其中涉及一些编程技巧.以及tvm概念,不在此部分进行进一步讲解,另有文章进行介绍. 首先介绍一下,从onn ...

  7. 前端 vue 自定义导航栏组件高度及返回箭头 自定义 tabbar 图标

    前端vue自定义导航栏组件高度及返回箭头 自定义tabbar图标, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12986 效 ...

  8. Typora 主题Mo Dark 样式

    Mo Dark 主题样式 html { font-size: 16px; } /*加粗字体样式*/ strong { -webkit-background-clip: text; -webkit-te ...

  9. 大数据实战手册-开发篇之RDD:计算 transform->action

    2.2 RDD:计算 transform->action 2.2.1 aggregate x = sc.parallelize([2,3,4], 2)[Task不能跨分片,task数为2] ne ...

  10. 我坚定的认为,这个源码肯定是有 BUG 的!

    你好呀,我是歪歪. 上周我不是发了<我试图给你分享一种自适应的负载均衡.>这篇文章嘛,里面一种叫做"自适应负载均衡"的负载均衡策略,核心思路就是从多个服务提供者中随机选 ...