PicoCTF - PowerAnalysis Part 1 / Part 2
Background
Simple Welcome 0x13(2023 HW - Power Analysis)
Recon
這一題幾乎就和上課教的差不多,只是因為有雜訊,所以要慎選trace point,我是直接看第一個trace的分布,決定採用300~400的point,而不管是利用自己刻的correlation coefficient還是用scipy的pearsonr都一樣可以順利解出key但是如果像homework一樣用numpy的corrcoef會有兩個bytes和正解不一樣,超哭,找超久(10/18更新,如果用自己刻的也是要碰用氣,所以如果可以的話,多送幾個trace,或者多用幾個算correlation coefficient的library)
- Part 2的部分幾乎一模一樣,就只是他先幫你紀錄好所有的trace,再讓我們做後續的分析
Exploit
- 首先先把資料從server拉下來,在存成json
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
28from pwn import * from string import ascii_letters, digits import json from tqdm import trange def gen_plaintext(length): return ''.join(random.choice(ascii_letters + digits) for _ in range(length)) pt = [gen_plaintext(16) for _ in range(50)] print(pt) json_file = [None] * len(pt) for i in trange(len(pt)): r = remote('saturn.picoctf.net', 52339) r.sendlineafter(b'hex: ', pt[i].encode('utf-8').hex().encode()) r.recvuntil(b'power measurement result: ') pm = r.recvline().decode().strip() json_file[i] = {} json_file[i]["pt"] = [ord(digit) for digit in pt[i]] json_file[i]["pm"] = pm r.close() json_object = json.dumps(json_file) with open("./Crypto/PowerAnalysis- Part 1/trace.json", 'w') as outfile: outfile.write(json_object)
- 然後再去解析AES key
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122import json from tqdm import trange import numpy as np import copy from string import ascii_letters, digits from numpy import corrcoef import matplotlib.pyplot as plt from scipy.stats import pearsonr jsonFile = open('./PicoCTF/Crypto/PowerAnalysis- Part 1/trace.json', 'r') j = json.load(jsonFile) s_box = [ [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76], [0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0], [0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15], [0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75], [0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84], [0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF], [0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8], [0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2], [0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73], [0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB], [0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79], [0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08], [0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A], [0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E], [0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF], [0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16] ] def data_preprocess(json_data): pt_col = [] # ct_col = [] trace_col = [] for bytes in range(16): tmp_pt_col = [] # tmp_ct_col = [] for trace_idx in range(len(json_data)): tmp_pt_col.append(json_data[trace_idx]['pt'][bytes]) # tmp_ct_col.append(json_data[trace_idx]['ct'][bytes]) pt_col.append(tmp_pt_col) # ct_col.append(tmp_ct_col) for point in range(300, 400):#len(json_data[0]['pm']) tmp_trace_col = [] for trace_idx in range(len(json_data)): tmp_trace_col.append(json_data[trace_idx]['pm'][point]) trace_col.append(tmp_trace_col) return pt_col, trace_col def sbox_preprocess(pt_col): sbox_result_tmp = [] for sbox_key in range(256): # 總共有256個sbox key tmp = [] for trace in range(len(pt_col)): # 有50個trace tmp.append(pt_col[trace] ^ sbox_key) sbox_result_tmp.append(tmp) return sbox_result_tmp def choose_sbox(sbox_result_tmp): sbox_result = copy.deepcopy(sbox_result_tmp) for sbox_key in range(256): for trace in range(50): hex_value = '{0:0>2x}'.format(sbox_result_tmp[sbox_key][trace]) x, y = hex_value[0], hex_value[1] sbox_result[sbox_key][trace] = s_box[int(x, 16)][int(y, 16)] return sbox_result def cal_hamming_weight(sbox_result_col): hw_model = copy.deepcopy(sbox_result_col) for i in range(len(sbox_result_col)): # 256 for j in range(len(sbox_result_col[i])): # 50 hw_model[i][j] = bin(sbox_result_col[i][j]).count('1') return hw_model def cal_correlation(hw_model_col_result, trace_col): correlation_result = [] for i in trange(len(hw_model_col_result)):#(ascii_letters + digits).encode(): for j in range(biggest_length):#len(trace_col) # correlation_result.append(corrcoef(hw_model_col_result[i], trace_col[j])[0, -1]) # correlation_result.append(pearsonr(hw_model_col_result[i], trace_col[j])[0]) correlation_result.append(run_pearson_correlation(hw_model_col_result[i], trace_col[j])) return correlation_result def run_pearson_correlation(x, y): mean_x = np.mean(x) mean_y = np.mean(y) covariance = np.sum((x - mean_x) * (y - mean_y)) std_dev_x = np.sqrt(np.sum((x - mean_x)**2)) std_dev_y = np.sqrt(np.sum((y - mean_y)**2)) correlation = covariance / (std_dev_x * std_dev_y) return correlation def display_pt(offset:int, data_offset = (0, len(j[0]["pm"]))): plt.plot(range(data_offset[0], data_offset[1]), j[offset]["pm"][data_offset[0]:data_offset[1]]) plt.savefig(fname="./PicoCTF/Crypto/PowerAnalysis- Part 1/pt_" + str(offset) + ".jpg") plt.clf() # display_pt(1, (0, 700)) # display_pt(1) pt_col, trace_col = data_preprocess(j) flag = '' biggest_length = 100#len(trace_col) for idx in trange(16): sbox_preprocess_result = sbox_preprocess(pt_col[idx]) choose_sbox_result = choose_sbox(sbox_preprocess_result) hw_model_col_result = cal_hamming_weight(choose_sbox_result) correlation_result = cal_correlation(hw_model_col_result, trace_col) key_idx = correlation_result.index(max(correlation_result)) # flag += (ascii_letters + digits)[key_idx // biggest_length] from Crypto.Util.number import long_to_bytes flag += long_to_bytes(key_idx // biggest_length).hex() print('The key of AES is: ' + flag )
Flag: picoCTF{4999139026d84bf20427eb48d4edec53}
Exploit Part 2
為了不要讓主程式的變化太大,因此我有調整了一下data preprocessing的部分,還找到了一個bug, :::spoiler Exp
1 |
|
:::
Flag: picoCTF{b7698f76b7e524ee7cd80dbde0cdff59}