July 25, 2023

巅峰极客2023 REVERSE

M1_Read

0x00 Daily Shell Check

无壳64位

image-20230725142553984

0x01 DFA

Refer: https://blog.csdn.net/fenfei331/article/details/126385120

属于是知识盲区,不过去年好像听谁提过一句 DFA 攻击,在 AES-128 中其实就是在第九轮的列混合之前的时候修改一个字节,而第九轮就是最后一次列混合了,第十轮是没有列混合的。

img

于是会导致这样出来的密文与原密文有四个字节不一样,经过多次修改就会有多组错误密文,然后通过正确密文和错误密文就可以推算出第10轮的密钥,继而推出原始密钥。

所以在实际应用中,就需要找准列混合的函数位置,在他之前修改数据。

而在实际样本分析中,如果 结果全部不同 说明时机太早了,只有一个不同 说明时机太晚了。

Frida Hook

那么现在就是去 hook 程序中的轮密钥加的位置了,在一堆函数中翻翻翻配合 fincrypt 可以猜测 sub_140004BF0 是 AES 加密

image-20230727164637240

于是 hook 的思路

写出脚本

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
import frida
import sys

session = frida.attach("m1_read.exe")

script = session.create_script("""
var baseAddr = Module.findBaseAddress("m1_read.exe");
var whiteAES = new NativeFunction(baseAddr.add(0x4BF0), 'pointer', ['pointer', 'pointer'])
var count = 9;
Interceptor.attach(baseAddr.add(0x4C2C), {
onEnter: function(args) {
count++;
if(count == 9) {
// console.log(Math.floor(Math.random() * 16)).writeU8(Math.floor(Math.random() * 256));
this.context.rdi.add(Math.floor(Math.random() * 16)).writeU8(Math.floor(Math.random() * 256));
}
},
onLeave: (retval) => {

}
})


for (let index = 0; index < 32; index++) {
var l = Memory.allocAnsiString("1234567890abcdef");
var b = Memory.alloc(16);
whiteAES(l, b);
console.log(b.readByteArray(16));
count = 0;
}
""")
script.load()

(学习了 sink 师傅的 frida 脚本)

这样子就可以拿到多组的结果了,随后利用该工具来获取最后一轮的 key

https://github.com/SideChannelMarvels/JeanGrey

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
data = """
ca 42 9f dc 6b fa 9b 5e 54 0c 8f 14 b0 3b ae 88 .B..k..^T....;..

ca 3a 9f dc 1d fa 9b 5e 54 0c 8f 87 b0 3b 6e 88 .:.....^T....;n.

ca 69 9f dc 9f fa 9b 5e 54 0c 8f 11 b0 3b f5 88 .i.....^T....;..

ca d4 9f dc bd fa 9b 5e 54 0c 8f a5 b0 3b 3f 88 .......^T....;?.

ca 42 44 dc 6b 17 9b 5e f3 0c 8f 14 b0 3b ae e0 .BD.k..^.....;..

ca c3 9f dc a3 fa 9b 5e 54 0c 8f 6f b0 3b d6 88 .......^T..o.;..

ca 42 9f 9b 6b fa 3d 5e 54 44 8f 14 6f 3b ae 88 .B..k.=^TD..o;..

ca 42 6b dc 6b ba 9b 5e 56 0c 8f 14 b0 3b ae e8 .Bk.k..^V....;..

ca 42 6c dc 6b 55 9b 5e e3 0c 8f 14 b0 3b ae 6e .Bl.kU.^.....;.n

ca 42 9f ea 6b fa 45 5e 54 d4 8f 14 61 3b ae 88 .B..k.E^T...a;..

ca 42 f3 dc 6b 09 9b 5e bf 0c 8f 14 b0 3b ae 69 .B..k..^.....;.i

ca 42 9f 93 6b fa 61 5e 54 c3 8f 14 fe 3b ae 88 .B..k.a^T....;..

ca f3 9f dc 8d fa 9b 5e 54 0c 8f 84 b0 3b 21 88 .......^T....;!.

ca d6 9f dc b2 fa 9b 5e 54 0c 8f f9 b0 3b e2 88 .......^T....;..

ca 42 9f fd 6b fa b9 5e 54 f7 8f 14 a6 3b ae 88 .B..k..^T....;..

ca 40 9f dc cf fa 9b 5e 54 0c 8f e4 b0 3b 96 88 .@.....^T....;..
"""


arr_data = ""
for t in data.split('\n'):
tmp = bytearray.fromhex(t[:47])
if tmp != b'':
arr_data += tmp.hex() + '\n'
print(arr_data)


import phoenixAES

with open("tracefile", "wb") as t:
t.write("""
ca429fdc6bfa9b5e540c8f14b03bae88
ca3a9fdc1dfa9b5e540c8f87b03b6e88
ca699fdc9ffa9b5e540c8f11b03bf588
cad49fdcbdfa9b5e540c8fa5b03b3f88
ca4244dc6b179b5ef30c8f14b03baee0
cac39fdca3fa9b5e540c8f6fb03bd688
ca429f9b6bfa3d5e54448f146f3bae88
ca426bdc6bba9b5e560c8f14b03baee8
ca426cdc6b559b5ee30c8f14b03bae6e
ca429fea6bfa455e54d48f14613bae88
ca42f3dc6b099b5ebf0c8f14b03bae69
ca429f936bfa615e54c38f14fe3bae88
caf39fdc8dfa9b5e540c8f84b03b2188
cad69fdcb2fa9b5e540c8ff9b03be288
ca429ffd6bfab95e54f78f14a63bae88
ca409fdccffa9b5e540c8fe4b03b9688
ca42a0dc6bf59b5e450c8f14b03baefe
ca42dedc6b039b5e2b0c8f14b03baeed
91429fdc6bfa9bb9540c3514b0fcae88
ca2a9fdc77fa9b5e540c8ff7b03bd388
ca429fbf6bfa7c5e547c8f14823bae88
ca429f086bfafc5e54a08f14143bae88
caf89fdc25fa9b5e540c8f65b03b6888
a0429fdc6bfa9bda540c5e14b015ae88
ca42c6dc6bf59b5e620c8f14b03bae72
ca009fdc01fa9b5e540c8ff0b03b1288
ca429f306bfa345e54b78f14dc3bae88
ca429f2b6bfa665e547b8f14793bae88
ca42f8dc6ba19b5e590c8f14b03baeb5
cac89fdcfafa9b5e540c8f63b03b0488
ca429fe76bfa755e54b18f146b3bae88
ca429fd66bfa485e541a8f14a43bae88
ca4270dc6b369b5ee10c8f14b03bae6a
caf39fdc8dfa9b5e540c8f84b03b2188
ca429f9e6bfa885e548c8f14623bae88
ca429f9f6bfa635e540f8f14d13bae88
ca429f666bfa795e54928f14ed3bae88
ca1e9fdce1fa9b5e540c8ff8b03b0288
ca42e4dc6be79b5e0b0c8f14b03bae68
ca423bdc6bb19b5e010c8f14b03bae3e
ca429f146bfa365e54958f14783bae88
2d429fdc6bfa9b6a540cb414b0ecae88
95429fdc6bfa9be8540c2a14b03dae88
ca42b5dc6b659b5e030c8f14b03baedb
ca429f0f6bfad85e54208f145c3bae88
ca4268dc6b439b5e020c8f14b03baea7
ca569fdc65fa9b5e540c8f39b03b9c88
ca4d9fdc58fa9b5e540c8f9db03be988
caff9fdc2cfa9b5e540c8f33b03b7b88
ca429f5f6bfa905e549d8f14043bae88
""".encode('utf8'))
phoenixAES.crack_file('tracefile', verbose=0)

(注意尾巴还有一个异或0x66,最后一轮Key获得之后要异或该值,或将多组密文都异或0x66也可获取)

有了最后一轮 key 就可以还原出最原先的 key

https://github.com/SideChannelMarvels/Stark

image-20230727165357326

0x02 Get Flag

那么有了 key,直接解密 out.bin 里的数据即可

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

key = bytes.fromhex("00000000000000000000000000000000")
cipher = AES.new(key, AES.MODE_ECB)
enc = bytearray.fromhex("0B987EF5D94DD679592C4D2FADD4EB89")

for i in range(16):
enc[i] ^= 0x66

print(cipher.decrypt(enc))

Get Flag!

image-20230727165623391

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.