复现此题学习一下AES算法、DFA攻击和Frida的食用方法

0x00 AES算法

参考:https://zhuanlan.zhihu.com/p/397940508

0x01 DFA攻击

参考:https://blog.csdn.net/fenfei331/article/details/126385120

关键:在倒数第一轮列混合和倒数第二轮列混合之间(在AES-128中也就是第8轮和第9轮之间,因为最后第10轮不做列混合),修改此时中间结果的一个字节,会导致最终密文和正确密文有4个字节的不同。通过多次的修改,得到多组错误的密文,然后通过正确密文和这些错误密文能够推算出第10轮的密钥(加密模式下),继而能推算出原始密钥。

实际应用中,需要先找准列混合的函数位置,然后在他之前去插入缺陷数据。

0x02 Frida

参考:https://www.52pojie.cn/thread-1128884-1-1.html

就是用来HOOK的(

0x03 题目分析

先上Findcrypt,可以找到AES的S盒,但是没有调用的地方

函数不多,一个个找可以找到类似AES的函数

函数结尾有AES-128的特征,16B参与运算

找不到密钥和具体调用S盒的地方,但是根据已存在的AES的S盒和函数结构推测使用的就是AES算法,考虑使用DFA获取密钥

上Frida写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# getKey.py
import frida
import os

session = frida.attach("m1_read.exe")
currentDir = os.getcwd()


def getJsScript(fileName="getKey.js", fileDir=currentDir) -> str:
with open(fileDir + "\\" + fileName, encoding='utf-8') as jsScript:
return jsScript.read().rstrip()


script = session.create_script(getJsScript())
script.load()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// getKey.js
var baseAddr = Module.findBaseAddress("m1_read.exe")
// AES函数偏移:0x4BF0
var whiteAES = new NativeFunction(baseAddr.add(0x4BF0), 'pointer', ['pointer','pointer'])
// count = 9,这样第一轮数据恰好对应正确的数据
var count = 9

Interceptor.attach(baseAddr.add(0x4C2C),{
// 列混合处的偏移:0x4C2C
// 此位置为call了au_re___security_check_cookie之后的mov rbx, rdi
// 详见下图
// 若不确定,可以通过测试来看:
// 1. 若正确数据与异常数据全部不同,则修改太早
// 2. 若正确数据与异常数据仅一个不同,则修改太晚
onEnter: function(args){
count++;
// 第九轮修改中间结果
if(count == 9){
// 参考汇编代码可以发现rdi记录第九轮中间数据的地址
// lea rdi, [rbx + 2] #详见下下图
// "add(Math.floor(Math.random()*16))":
// 表示对操作的地址进行偏移,值属于{1,2,3}
// (0,4的可能性基本为0)
//
// "writeU8(Math.floor(Math.random()*256))":
// 表示对写入的值进行修改,值属于{1,2,3,...,E,F}
// (0,16的可能性基本为0)
// 综上,这实现了对中间数据的单个Byte修改,取消注释下述代码即可看出
var p = ptr(this.context.rdi)
// console.log("ori: ", p.readByteArray(16), "\n")
p.add(Math.floor(Math.random()*16)).writeU8(Math.floor(Math.random()*256))
// console.log("out: ", p.readByteArray(16), "\n")
}
},
onLeave:(retval) =>{

}
})

for (let index = 0; index < 33; index++){
// 取消注释下述代码即可得到每一轮的数据
var l = Memory.allocAnsiString("0123456789abcdef");
var b = Memory.alloc(16);
whiteAES(l, b);
console.log(hexdump(b.readByteArray(16),{header:false}));
count = 0;
}

图1

图2

运行脚本的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
00000000  72 93 98 12 0f 00 94 f4 03 7a 44 ee dd 99 20 6f  r........zD... o
00000000 72 93 98 5a 0f 00 aa f4 03 2d 44 ee 16 99 20 6f r..Z.....-D... o
00000000 72 56 98 12 b6 00 94 f4 03 7a 44 30 dd 99 b9 6f rV.......zD0...o
00000000 1c 93 98 12 0f 00 94 89 03 7a ce ee dd c8 20 6f .........z.... o
00000000 72 93 98 c4 0f 00 d4 f4 03 d4 44 ee ac 99 20 6f r.........D... o
00000000 72 17 98 12 c1 00 94 f4 03 7a 44 7a dd 99 02 6f r........zDz...o
00000000 72 93 98 e5 0f 00 ad f4 03 0a 44 ee 08 99 20 6f r.........D... o
00000000 72 84 98 12 6a 00 94 f4 03 7a 44 68 dd 99 a6 6f r...j....zDh...o
00000000 d2 93 98 12 0f 00 94 57 03 7a 31 ee dd 36 20 6f .......W.z1..6 o
00000000 72 93 65 12 0f 7c 94 f4 90 7a 44 ee dd 99 20 0f r.e..|...zD... .
00000000 72 93 98 3a 0f 00 e8 f4 03 aa 44 ee 98 99 20 6f r..:......D... o
00000000 72 93 98 44 0f 00 49 f4 03 b2 44 ee 24 99 20 6f r..D..I...D.$. o
00000000 73 93 98 12 0f 00 94 1f 03 7a 76 ee dd 6b 20 6f s........zv..k o
00000000 72 7d 98 12 7e 00 94 f4 03 7a 44 bf dd 99 23 6f r}..~....zD...#o
00000000 72 20 98 12 8a 00 94 f4 03 7a 44 c4 dd 99 35 6f r .......zD...5o
00000000 5e 93 98 12 0f 00 94 35 03 7a 1a ee dd 20 20 6f ^......5.z... o
00000000 72 93 98 a5 0f 00 1e f4 03 77 44 ee 15 99 20 6f r........wD... o
00000000 72 93 98 5c 0f 00 07 f4 03 a5 44 ee 06 99 20 6f r..\......D... o
00000000 72 93 eb 12 0f e0 94 f4 13 7a 44 ee dd 99 20 2a r........zD... *
00000000 72 93 98 97 0f 00 f8 f4 03 c5 44 ee 2a 99 20 6f r.........D.*. o
00000000 72 93 98 ab 0f 00 99 f4 03 d0 44 ee 5b 99 20 6f r.........D.[. o
00000000 72 93 98 cb 0f 00 bd f4 03 9d 44 ee 58 99 20 6f r.........D.X. o
00000000 72 73 98 12 05 00 94 f4 03 7a 44 c5 dd 99 3d 6f rs.......zD...=o
00000000 72 dd 98 12 bf 00 94 f4 03 7a 44 b9 dd 99 45 6f r........zD...Eo
00000000 72 93 67 12 0f 5c 94 f4 d6 7a 44 ee dd 99 20 bb r.g..\...zD... .
00000000 72 84 98 12 42 00 94 f4 03 7a 44 da dd 99 f3 6f r...B....zD....o
00000000 72 68 98 12 b2 00 94 f4 03 7a 44 5c dd 99 b1 6f rh.......zD\...o
00000000 72 e5 98 12 66 00 94 f4 03 7a 44 27 dd 99 42 6f r...f....zD'..Bo
00000000 72 fb 98 12 6e 00 94 f4 03 7a 44 7c dd 99 cc 6f r...n....zD|...o
00000000 72 93 98 86 0f 00 27 f4 03 18 44 ee e0 99 20 6f r.....'...D... o
00000000 72 93 63 12 0f 29 94 f4 8a 7a 44 ee dd 99 20 b0 r.c..)...zD... .
00000000 72 93 98 10 0f 00 cc f4 03 01 44 ee cd 99 20 6f r.........D... o
00000000 72 e0 98 12 77 00 94 f4 03 7a 44 ba dd 99 9a 6f r...w....zD....o

程序最后有一步异或0x66,因此上面的数据需要进行异或后才能使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 异或处理脚本
data = """
00000000 72 93 98 12 0f 00 94 f4 03 7a 44 ee dd 99 20 6f r........zD... o
00000000 72 93 98 5a 0f 00 aa f4 03 2d 44 ee 16 99 20 6f r..Z.....-D... o
00000000 72 56 98 12 b6 00 94 f4 03 7a 44 30 dd 99 b9 6f rV.......zD0...o
00000000 1c 93 98 12 0f 00 94 89 03 7a ce ee dd c8 20 6f .........z.... o
00000000 72 93 98 c4 0f 00 d4 f4 03 d4 44 ee ac 99 20 6f r.........D... o
00000000 72 17 98 12 c1 00 94 f4 03 7a 44 7a dd 99 02 6f r........zDz...o
00000000 72 93 98 e5 0f 00 ad f4 03 0a 44 ee 08 99 20 6f r.........D... o
00000000 72 84 98 12 6a 00 94 f4 03 7a 44 68 dd 99 a6 6f r...j....zDh...o
00000000 d2 93 98 12 0f 00 94 57 03 7a 31 ee dd 36 20 6f .......W.z1..6 o
00000000 72 93 65 12 0f 7c 94 f4 90 7a 44 ee dd 99 20 0f r.e..|...zD... .
00000000 72 93 98 3a 0f 00 e8 f4 03 aa 44 ee 98 99 20 6f r..:......D... o
00000000 72 93 98 44 0f 00 49 f4 03 b2 44 ee 24 99 20 6f r..D..I...D.$. o
00000000 73 93 98 12 0f 00 94 1f 03 7a 76 ee dd 6b 20 6f s........zv..k o
00000000 72 7d 98 12 7e 00 94 f4 03 7a 44 bf dd 99 23 6f r}..~....zD...#o
00000000 72 20 98 12 8a 00 94 f4 03 7a 44 c4 dd 99 35 6f r .......zD...5o
00000000 5e 93 98 12 0f 00 94 35 03 7a 1a ee dd 20 20 6f ^......5.z... o
00000000 72 93 98 a5 0f 00 1e f4 03 77 44 ee 15 99 20 6f r........wD... o
00000000 72 93 98 5c 0f 00 07 f4 03 a5 44 ee 06 99 20 6f r..\......D... o
00000000 72 93 eb 12 0f e0 94 f4 13 7a 44 ee dd 99 20 2a r........zD... *
00000000 72 93 98 97 0f 00 f8 f4 03 c5 44 ee 2a 99 20 6f r.........D.*. o
00000000 72 93 98 ab 0f 00 99 f4 03 d0 44 ee 5b 99 20 6f r.........D.[. o
00000000 72 93 98 cb 0f 00 bd f4 03 9d 44 ee 58 99 20 6f r.........D.X. o
00000000 72 73 98 12 05 00 94 f4 03 7a 44 c5 dd 99 3d 6f rs.......zD...=o
00000000 72 dd 98 12 bf 00 94 f4 03 7a 44 b9 dd 99 45 6f r........zD...Eo
00000000 72 93 67 12 0f 5c 94 f4 d6 7a 44 ee dd 99 20 bb r.g..\...zD... .
00000000 72 84 98 12 42 00 94 f4 03 7a 44 da dd 99 f3 6f r...B....zD....o
00000000 72 68 98 12 b2 00 94 f4 03 7a 44 5c dd 99 b1 6f rh.......zD\...o
00000000 72 e5 98 12 66 00 94 f4 03 7a 44 27 dd 99 42 6f r...f....zD'..Bo
00000000 72 fb 98 12 6e 00 94 f4 03 7a 44 7c dd 99 cc 6f r...n....zD|...o
00000000 72 93 98 86 0f 00 27 f4 03 18 44 ee e0 99 20 6f r.....'...D... o
00000000 72 93 63 12 0f 29 94 f4 8a 7a 44 ee dd 99 20 b0 r.c..)...zD... .
00000000 72 93 98 10 0f 00 cc f4 03 01 44 ee cd 99 20 6f r.........D... o
00000000 72 e0 98 12 77 00 94 f4 03 7a 44 ba dd 99 9a 6f r...w....zD....o
"""


def cut(obj, sec):
return [obj[i:i+sec] for i in range(0, len(obj), sec)]


data = cut(data, 76)
data = data[:-1]
for i in range(len(data)):
data[i] = data[i][11:-18]
for i in data:
tmp = i.split(' ')
res = ''
for j in tmp:
res += '{:02x}'.format(int(j, 16) ^ int("66", 16))
print(res)

异或结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
14f5fe746966f292651c2288bbff4609
14f5fe3c6966cc92654b228870ff4609
1430fe74d066f292651c2256bbffdf09
7af5fe746966f2ef651ca888bbae4609
14f5fea26966b29265b22288caff4609
1471fe74a766f292651c221cbbff6409
14f5fe836966cb92656c22886eff4609
14e2fe740c66f292651c220ebbffc009
b4f5fe746966f231651c5788bb504609
14f50374691af292f61c2288bbff4669
14f5fe5c69668e9265cc2288feff4609
14f5fe2269662f9265d4228842ff4609
15f5fe746966f279651c1088bb0d4609
141bfe741866f292651c22d9bbff4509
1446fe74ec66f292651c22a2bbff5309
38f5fe746966f253651c7c88bb464609
14f5fec3696678926511228873ff4609
14f5fe3a6966619265c3228860ff4609
14f58d746986f292751c2288bbff464c
14f5fef169669e9265a322884cff4609
14f5fecd6966ff9265b622883dff4609
14f5fead6966db9265fb22883eff4609
1415fe746366f292651c22a3bbff5b09
14bbfe74d966f292651c22dfbbff2309
14f50174693af292b01c2288bbff46dd
14e2fe742466f292651c22bcbbff9509
140efe74d466f292651c223abbffd709
1483fe740066f292651c2241bbff2409
149dfe740866f292651c221abbffaa09
14f5fee069664192657e228886ff4609
14f50574694ff292ec1c2288bbff46d6
14f5fe766966aa9265672288abff4609
1486fe741166f292651c22dcbbfffc09

利用phoenixAES实现DFA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# s1是前文中的33轮数据,以字符串形式存储(包含换行,否则无法识别)
import phoenixAES
s1 = """
14f5fe746966f292651c2288bbff4609
14f5fe3c6966cc92654b228870ff4609
1430fe74d066f292651c2256bbffdf09
7af5fe746966f2ef651ca888bbae4609
14f5fea26966b29265b22288caff4609
1471fe74a766f292651c221cbbff6409
14f5fe836966cb92656c22886eff4609
14e2fe740c66f292651c220ebbffc009
b4f5fe746966f231651c5788bb504609
14f50374691af292f61c2288bbff4669
14f5fe5c69668e9265cc2288feff4609
14f5fe2269662f9265d4228842ff4609
15f5fe746966f279651c1088bb0d4609
141bfe741866f292651c22d9bbff4509
1446fe74ec66f292651c22a2bbff5309
38f5fe746966f253651c7c88bb464609
14f5fec3696678926511228873ff4609
14f5fe3a6966619265c3228860ff4609
14f58d746986f292751c2288bbff464c
14f5fef169669e9265a322884cff4609
14f5fecd6966ff9265b622883dff4609
14f5fead6966db9265fb22883eff4609
1415fe746366f292651c22a3bbff5b09
14bbfe74d966f292651c22dfbbff2309
14f50174693af292b01c2288bbff46dd
14e2fe742466f292651c22bcbbff9509
140efe74d466f292651c223abbffd709
1483fe740066f292651c2241bbff2409
149dfe740866f292651c221abbffaa09
14f5fee069664192657e228886ff4609
14f50574694ff292ec1c2288bbff46d6
14f5fe766966aa9265672288abff4609
1486fe741166f292651c22dcbbfffc09
"""
with open("testfile", "wb") as t:
t.write(s1.encode())

phoenixAES.crack_file("testfile")
# 自动打印出来第10轮的密钥
# 结果如下
# B4EF5BCB3E92E21123E951CF6F8F188E

参考:https://github.com/SideChannelMarvels/Stark

使用Stark(自行编译)提供一轮密钥暴力破解AES-128

设定好轮数即可

使用010editor查看提供的out.bin

根据M1卡的存储格式,第一行中,4B为卡号,1B为校验位,剩下为厂商信息,因此需要解密的部分为第三行

解密脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Cipher import AES

s = "0B987EF5D94DD679592C4D2FADD4EB89"
# key长度注意要写够16B的长度,否则AES识别不正确
key = bytes.fromhex("00000000000000000000000000000000")
enc = bytearray(bytes.fromhex(s))
cipher = AES.new(key, AES.MODE_ECB)

# 别忘了首先要处理异或
for i in range(16):
enc[i] ^= 0x66

flag = cipher.decrypt(enc)
print(flag)

flag{cddc8d28dabb4ea9}

复现过程很是痛苦(