# HWS-2022 夏令营线上赛 WP

5 篇文章 0 订阅

#### HWS-2022 硬件安全在线夏令营线上预选赛 WriteUp

PS：比赛结束时，排名已经第五了（估计等一二三血一加成，就掉到第十名去了）不过回味一下我第二名的巅峰时刻哈哈哈（跑…ε=ε=ε=(~￣▽￣)~

#### 一、硬件(Crypto侧信道)

##### ① 硬件(Crypto侧信道)-Read&Solve
1. 参考了 CTF Wiki 的低高位取 01，得到侧信道电位频率为：1010110100101100
2. 考虑到可能是二进制，转成十进制，再转成十六进制即可得到 FLAG

##### ② 硬件(Crypto侧信道)-足够安全
1. 参考了 Google 2022 CTF 的 ELECTRIC MAYHEM CLS 的 WP，参考博客：Google CTF writeup（kurenaif）
2. 确认了 firmware 中的 aes.c 的 sbox 并没有修改之后，就知道可以套代码了
3. 只需要将 traces.json 改成题目的就行了
import json
import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio
from Crypto.Cipher import AES
import binascii
import sys

humming = [bin(n).count("1") for n in range(256)]

json_open = open('traces.json', 'r')
json_load = json.load(json_open)

sbox = (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 addkey_subbytes(pt, guesskey):
return sbox[pt ^ guesskey]

N = len(json_load)

print(N)
# print(json_load[0]['pt'])
# print(json_load[0]['ct'])
# print(json_load[0]['pm'])

bestguess = [0] * 16
data_start = 0
data_end = 1800
NUM_POINTS = data_end - data_start
NUM_TRACES = len(json_load)
traces = []

for pt_ct_pm in json_load:
traces.append(pt_ct_pm['pm'][data_start:data_end])

for k_idx in range(16):  # determine key index
cpaoutput = [0] * 256

# follow valiables may not be need
maxcpa = [0] * 256
bestcor = 0
bestkey = 0

for kguess in range(256):  # determine word key candidate
sumnum = np.zeros(NUM_POINTS)
sumden1 = np.zeros(NUM_POINTS)
sumden2 = np.zeros(NUM_POINTS)

hyp = np.zeros(NUM_TRACES)

for t_idx in range(NUM_TRACES):  # hypothesis hamming weight
hyp[t_idx] = humming[addkey_subbytes(json_load[t_idx]['pt'][k_idx],
kguess)]

h_mean = np.mean(hyp, dtype=np.float64)
t_mean = np.mean(traces, axis=0, dtype=np.float64)

assert 0 < h_mean and h_mean < 8, "meanh is not between 0 and 8"
assert len(t_mean) == NUM_POINTS, "meant is less than trace points"

cors = []

for t_idx in range(NUM_TRACES):
hdiff = (hyp[t_idx] - h_mean)
tdiff = traces[t_idx] - t_mean

sumnum = sumnum + (hdiff * tdiff)
sumden1 = sumden1 + hdiff * hdiff
sumden2 = sumden2 + tdiff * tdiff

cpaoutput[kguess] = sumnum / np.sqrt(sumden1 * sumden2)

maxcpa[kguess] = max(abs(cpaoutput[kguess]))

bestguess[k_idx] = np.argmax(maxcpa)
print("[+] best guess key [{0}] is {1:02x} (score: {2})".format(
k_idx, bestguess[k_idx], maxcpa[bestguess[k_idx]]))

# strkey = ''.join(map(chr, bestguess))
# print(strkey)
print(bestguess)
b = ""
for i in bestguess:
b += str(hex(i))[2:]
print(b) # FLAG


#### 二、MISC

##### ① 最伟大的作品
1. 一通操作发现没有用，结果放大声音一听歌才发现，原来是钢琴声
2. 在线钢琴模拟器网站复刻听到的钢琴声音，得到目标音符为：badbadcabbage

##### ② random
1. 首先根据 made 代码，判断出：只要得出 r3 的原始序列即可知道 FLAG
2. getpixel 函数的作用是获取坐标的像素值，putpixel 函数的作用是设置坐标的像素值
3. 根据 cat3.putpixel((i, j), pix[2] ^ r3[i * y + j]) 可知 1.png 的 p3 像素最后会变成 xx.png 的 p3 像素，即可以写出 pix1[2]^num == pix2[2]，num 代表随机后的 r3 序列
4. 要获得 r3 序列才能得到 FLAG，经过测试，只有在 made 代码中进行 shuffle，才能得到与其一样的排列序列，所以我自己设 temp = [0, 1, …, 27917] 共 27918 个元素的序列进行 shuffle，得到的随机序列放进 wp 的代码中，再进行逆 shuffle，并对 r3 进行逆，即可得到 FLAG
import random
from PIL import Image
from hashlib import md5
from Crypto.Util.number import long_to_bytes as n2b

# 随机序列
temp = [19413, 5017, 7689, ...,21804, 2197, 3115]
print(len(temp))

random.seed(793211)

cat = Image.open('1.png')
cat1 = Image.new('L', cat.size)
cat2 = Image.new('L', cat.size)
cat3 = Image.new('L', cat.size)

catt = Image.open('xx.png')
catt1 = Image.new('L', catt.size)
catt2 = Image.new('L', catt.size)
catt3 = Image.new('L', catt.size)

x, y = cat.size
bits = x * y

r3 = [-1] * 27918

for i in range(x):
for j in range(y):
pix1 = cat.getpixel((i, j))
pix2 = catt.getpixel((i, j))
for num in range(256):
if(pix1[2]^num == pix2[2]):
r3[i*y+j] = num
break
# cat3.putpixel((i, j), pix[2] ^ r3[i * y + j])

result = [-1] * 27918
for i in range(27918):
result[temp[i]] = r3[i]

flag = ""
for i in range(28):
flag+=chr(result[i])
print(flag)


##### ③ What’s this
1. 使用在线工具反编译无果，使用 stegosaurus 也无果，于是谷歌搜索针对 pyc 的工具
2. 通过查阅，发现可以使用命令 uncompyle6 flag.pyc 反编译，于是我得到第一份源代码
3. 由于列表元素过大，且众多奇怪变量，怀疑是混淆代码，对第一份源代码运行，并储存二进制文件
4. 查看二进制文本，发现又是混淆代码，重复上一步操作，储存至新的二进制文件
5. 再查看二进制文本，发现又是混淆代码，重复上一步操作，储存至新的二进制文件
6. 最后终于在新的二进制文件中，得到 FLAG
# 储存至二进制文件的代码

with open("flag",'wb') as ff:
ff.write(bytearray(f)

marshal.dumps 的作用是数据序列化到二进制文件中
marshal.loads 的作用是加载二进制文件序列化中的数据



PS：注意混淆时不能替换变量名，容易出错

• 第一份混淆代码
# whatisthis.py

import marshal
import numpy as np
c = [235, 26, 15, ..., 14, 14, 18, 7]
remind = "Don't try to reverse this python script. You will be disappointed about it "
a = '475'
np.random.seed(np.sum([ord(b) for b in a]))
for b in range(len(c)):
c[b] ^= np.random.randint(27)
else:
exec(marshal.loads(bytearray(c)))

• 第二份混淆代码
# next.py

import marshal
a = [225, 217, 139, ..., 210, 108, 12, 14]
def b(key):
c = list(range(256))
d = 0
for e in range(256):
d = (d + c[e] + ord(key[e % len(key)])) % 256
c[e], c[d] = c[d], c[e]
return c
def f(p):
g = b('h0lyduck')
h = []
e = d = 0
for i in p:
e = (e + 1) % 256
d = (d + g[e]) % 256
g[e], g[d] = g[d], g[e]
j = (g[e] + g[d]) % 256
k = g[j]
h.append(i ^ k)
return h
exec(marshal.loads(bytearray(f(a))))

• 第三份混淆代码（太长不展示了）

#### 三、Crypto

##### ① HWS-easyRSA
1. 模板题，参考博客：ctf之lcg算法中的lcg-4
2. 改几个参数即可得到 FLAG
from Crypto.Util.number import long_to_bytes

n =  31893593182018727625473530765941216190921866039118147474754069955393226712079257707838327486268599271803
output =  [
25820280412859586557218124484272275594433027771091486422152141535682739897353623931875432576083022273940,
24295465524789348024814588142969609603624462580932512051939198335014954252359986260009296537423802567677,
14963686422550871447791815183480974143372785034397446416396172429864269108509521776424254168481536292904
]

MMI = lambda A, n,s=1,t=0,N=0: (n < 2 and t%N or MMI(n, A%n, t, s-A//n*t, N or n),-1)[n<1] #逆元计算
a=(output[2]-output[1])*MMI((output[1]-output[0]),n)%n
ani=MMI(a,n)
b=(output[1]-a*output[0])%n
seed = (ani*(output[0]-b))%n
plaintext=seed
print(long_to_bytes(plaintext))


• 0
点赞
• 6
收藏
觉得还不错? 一键收藏
• 2
评论
03-27 334
08-02 1307
01-12
07-17 371
08-13 4706
01-10 231

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。