本次网鼎杯的Crypto部分其实还是比较简单的,解出的人数也较多。感觉405题略难一些,花了比较多的时间,恰巧最后几小时给出的162所用到的求解方式之前遇到过,有幸作为一个CTF新手把这次的比赛密码学部分AK掉,值得纪念!
crypto091
搜索问题描述里面USENIX Security 2021的论文得知,苹果使用的是sha256加密。结合170号段首批放号的联通号码开头是1709,加上国家代码86,用下面exp爆破得到flag。
import hashlib
table = '1234567890'
start = '861709'
len = len(table)
m = 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc'
for a in range(len):
for b in range(len):
for c in range(len):
for d in range(len):
for e in range(len):
for f in range(len):
for g in range(len):
phone = start + \
table[a] + table[b] + table[c] + \
table[d] + table[e] + table[f] + table[g]
phone_hash = hashlib.sha256(
phone.encode('utf-8')).hexdigest()
if phone_hash == m:
print("flag{"+phone+"}")
# flag{8617091733716}
得到flag{8617091733716}
crypto405
这道题写完之后看了一些其它的解答过程,大部分都是将初始的k数组通过前五个字符列方程的形式求出(至于解法可能不大相同),应该是一种更加直接的想法。不过本人在做题的时候使用的方法感觉有点是找数学规律了,适用性应该不强。
查看py脚本,使用一组5个未知数的初始向量,对每一个字符在模p的有限域下,进行乘法运算加密,并且将结果保留用于下一轮计算。其中未知量有模数p和初始向量。不妨将42轮加密所用的一维数组
k
[
i
]
k[i]
k[i]变为二维数组
k
[
i
]
[
j
]
k[i][j]
k[i][j],其意义为,第
i
i
i 轮加密(从0开始)时,第
j
j
j 个乘法运算。
从flag前5个字符即"flag{"的加密来推导解题思路,下列为了方便起见将
k
[
i
]
[
j
]
k[i][j]
k[i][j]简写为kij,省略左右模p,同时其中的data0,data1…意为output中的参数:
{
k
11
=
f
∗
k
01
,
k
12
=
f
∗
k
01
∗
k
02
,
.
.
.
k
21
=
l
∗
k
11
,
k
22
=
l
∗
k
11
∗
k
12
,
.
.
.
k
31
=
a
∗
k
21
,
k
32
=
a
∗
k
21
∗
k
22
,
.
.
.
\begin{cases}k11=f*k01,k12=f*k01*k02,...\\ k21=l*k11,k22=l*k11*k12,...\\ k31=a*k21,k32=a*k21*k22,...\\ \end{cases}
⎩
⎨
⎧k11=f∗k01,k12=f∗k01∗k02,...k21=l∗k11,k22=l∗k11∗k12,...k31=a∗k21,k32=a∗k21∗k22,...
进一步得:
{
d
a
t
a
0
=
f
∗
k
01
∗
k
02
∗
k
03
∗
k
04
∗
k
05
=
k
15
d
a
t
a
1
=
l
∗
k
11
∗
k
12
∗
k
13
∗
k
14
∗
k
15
=
k
25
=
k
24
∗
k
15
d
a
t
a
2
=
a
∗
k
21
∗
k
22
∗
k
23
∗
k
24
∗
k
25
=
k
35
=
k
34
∗
k
25
=
k
33
∗
k
24
∗
k
25
\begin{cases} data0=f*k01*k02*k03*k04*k05=k15\\ data1=l*k11*k12*k13*k14*k15=k25=k24*k15\\ data2=a*k21*k22*k23*k24*k25=k35=k34*k25=k33*k24*k25 \end{cases}
⎩
⎨
⎧data0=f∗k01∗k02∗k03∗k04∗k05=k15data1=l∗k11∗k12∗k13∗k14∗k15=k25=k24∗k15data2=a∗k21∗k22∗k23∗k24∗k25=k35=k34∗k25=k33∗k24∗k25
最后得:
{
k
15
=
d
a
t
a
0
(
m
o
d
p
)
k
24
=
d
a
t
a
1
∗
k
1
5
−
1
(
m
o
d
p
)
k
33
=
d
a
t
a
2
∗
(
k
24
∗
k
25
)
−
1
(
m
o
d
p
)
.
.
.
\begin{cases} k15 = data0~~(mod~p)\\ k24=data1*k15^{-1}~~(mod~p)\\ k33=data2*(k24*k25)^{-1}~~(mod~p)\\ ... \end{cases}
⎩
⎨
⎧k15=data0 (mod p)k24=data1∗k15−1 (mod p)k33=data2∗(k24∗k25)−1 (mod p)...
那么可以看出,由42条
d
a
t
a
data
data 可以推出所有的
k
[
i
]
[
5
]
k[i][5]
k[i][5],从
i
=
2
i = 2
i=2开始的
k
[
i
]
[
4
]
k[i][4]
k[i][4],从
i
=
3
i = 3
i=3开始的
k
[
i
]
[
3
]
k[i][3]
k[i][3],从
i
=
4
i = 4
i=4开始的
k
[
i
]
[
2
]
k[i][2]
k[i][2],从
i
=
5
i = 5
i=5开始的
k
[
i
]
[
1
]
k[i][1]
k[i][1],即从"flag{“开始所有的字符都能够通过output中的数据求得。
但上述求解的条件是一个确定的模数p,而题目所给了p是一个16位的素数,从output中最大数开始,到
2
17
2^{17}
217 结束,逐一爆破其中素数,只需要最后一位的ASCII码与”}"的相同即可。
解题exp如下:
from Crypto.Util.number import *
import gmpy2
data = [0x2066, 0xa222, 0xcbb1, 0xdbb4, 0xdeb4, 0xb1c5, 0x33a4, 0xc051, 0x3b79, 0x6bf8, 0x2131, 0x2c40, 0x91ba, 0x7b44, 0x5f25, 0x0208, 0x7edb, 0x62b5, 0xcec5, 0x5ab3, 0x3c46,
0xc272, 0x714b, 0x9e0b, 0x48ee, 0x44cc, 0x05a0, 0x3da3, 0x11b1, 0x259f, 0x899d, 0xa130, 0xe58f, 0x23f3, 0x5829, 0x6beb, 0x3681, 0x0054, 0xa189, 0x2765, 0xc63d, 0xbc68]
max = max(data)
# 为k开出二维数组空间
k = [0]*(50*5)
# 计算区间内所有素数
db = []
for i in range(max, pow(2, 17)):
if gmpy2.is_prime(i):
db.append(i)
# 求解出k51,k52,k53,k54,k55后即可推出所有内容
def decrypt(p):
for i in range(0, 42):
k[(i+1)*5+5] = data[i]
for i in range(1, 42):
k[(i+1)*5+4] = data[i] * gmpy2.invert(k[i*5+5], p) % p
for i in range(2, 42):
k[(i+1)*5+3] = data[i] * gmpy2.invert(k[i*5+4]*k[i*5+5], p) % p
for i in range(3, 42):
k[(i+1)*5+2] = data[i] * gmpy2.invert(k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
for i in range(4, 42):
k[(i+1)*5+1] = data[i] * gmpy2.invert(k[i*5+2]
* k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
# 逐一爆破素数库
for p in db:
decrypt(p)
# 循环求解至最后一个字符,判断是否为"}"
for i in range(5, 42):
x = data[i] * gmpy2.invert(k[i*5+1]*k[i*5+2]
* k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
if x == 125:
flag = 'flag{'
# 重新遍历一次,并将结果转换为字符
for i in range(5, 42):
x = data[i] * gmpy2.invert(k[i*5+1]*k[i*5+2]
* k[i*5+3]*k[i*5+4]*k[i*5+5], p) % p
flag = flag + chr(x)
print(flag)
# flag{749d39d4-78db-4c55-b4ff-bca873d0f18e}
得到flag{749d39d4-78db-4c55-b4ff-bca873d0f18e}
crypto162
恰巧在picoCTF2022中做过一个很相似的题Sequences,个人当时给出的wp在这:(picoCTF2022_wp@fgps_fly1ng_pengu1ns的博客-CSDN博客
用到了这篇文章Solving Linear Recurrence Relation | HackerEarth中提到的矩阵法求解递推数列。
将给的cal函数稍微整理一下得到下式方程:
f
(
x
)
=
{
1
,
x
=
0
2
,
x
=
1
3
,
x
=
2
c
o
f
(
0
)
∗
f
(
x
−
1
)
+
c
o
f
(
1
)
∗
f
(
x
−
2
)
+
c
o
f
(
2
)
∗
f
(
x
−
3
)
,
x
⩾
4
f(x) = \begin{cases} 1,\,\,x = 0\\ 2,\,\,x=1\\ 3,\,\,x=2\\ cof(0)*f(x-1) + cof(1)*f(x-2) + cof(2)*f(x-3),\,\,x\geqslant4\\ \end{cases}
f(x)=⎩
⎨
⎧1,x=02,x=13,x=2cof(0)∗f(x−1)+cof(1)∗f(x−2)+cof(2)∗f(x−3),x⩾4
那么可以有初始矩阵
a
0
a_0
a0:
[
1
2
3
]
\begin{bmatrix} {1}\\ {2}\\ {3}\\ \end{bmatrix}
⎣
⎡123⎦
⎤
和变换矩阵
T
T
T:
[
0
1
0
0
0
1
c
o
f
[
2
]
c
o
f
[
1
]
c
o
f
[
0
]
]
\begin{bmatrix} {0}&{1}&{0}\\ {0}&{0}&{1}\\ {cof[2]}&{cof[1]}&{cof[0]}\\ \end{bmatrix}
⎣
⎡00cof[2]10cof[1]01cof[0]⎦
⎤
想要求得
f
(
x
)
f(x)
f(x)只需要计算
T
x
−
1
∗
a
0
T^{x-1}*a_0
Tx−1∗a0的第一项即可。此后直接照搬后续加密代码,改写为解密形式即可。
使用sage解决矩阵方便一点,解题exp如下:
from hashlib import md5,sha256
from Crypto.Cipher import AES
import sys
cof_t = [[353, -1162, 32767], [206, -8021, 42110], [262, -7088, 31882], [388, -6394, 21225], [295, -9469, 44468], [749, -3501, 40559], [528, -2690, 10210], [354, -5383, 18437], [491, -8467, 26892], [932, -6984, 20447], [731, -6281, 11340], [420, -5392, 44071], [685, -6555, 40938], [408, -8070, 47959], [182, -9857, 49477], [593, -3584, 49243], [929, -7410, 31929], [970, -4549, 17160], [141, -2435, 36408], [344, -3814, 18949], [291, -7457, 40587], [765, -7011, 32097], [700, -8534, 18013], [267, -2541, 33488], [249, -8934, 12321], [589, -9617, 41998], [840, -1166, 22814], [947, -5660, 41003], [206, -7195, 46261], [784, -9270, 28410], [338, -3690, 19608], [559, -2078, 44397], [534, -3438, 47830], [515, -2139, 39546], [603, -6460, 49953], [234, -6824, 12579], [805, -8793, 36465], [245, -5886, 21077], [190, -7658, 20396], [392, -7053, 19739], [609, -5399, 39959], [479, -8172, 45734], [321, -7102, 41224], [720, -4487, 11055], [208, -1897, 15237], [890, -4427, 35168], [513, -5106, 45849], [666, -1137, 23725], [755, -6732, 39995], [589, -6421, 43716], [866, -3265, 30017], [416, -6540, 34979], [840, -1305, 18242], [731, -6844, 13781], [561, -2728, 10298], [863, -5953, 23132], [204, -4208, 27492], [158, -8701, 12720], [802, -4740, 16628], [491, -6874, 29057], [531, -4829, 29205], [363, -4775, 41711], [319, -9206, 46164], [317, -9270, 18290], [680, -5136, 12009], [880, -2940, 34900], [162, -2587, 49881], [997, -5265, 20890], [485, -9395, 23048], [867, -1652, 18926], [691, -7844, 11180], [355, -5990, 13172], [923, -2018, 23110], [214, -4719, 23005], [921, -9528, 29351], [349, -7957, 20161], [470, -1889, 46170], [244, -6106, 23879], [419, -5440, 43576], [930, -1123, 29859], [151, -5759, 23405], [843, -6770, 36558], [574, -6171, 33778], [772, -1073, 44718], [932, -4037, 40088], [848, -5813, 27304], [194, -6016, 39770], [966, -6789, 14217], [219, -6849, 40922], [352, -6046, 18558], [794, -8254, 29748], [618, -5887, 15535], [202, -9288, 26590], [611, -4341, 46682], [155, -7909, 16654], [935, -5739, 39342], [998, -6538, 24363], [125, -5679, 36725], [507, -7074, 15475], [699, -5836, 47549]]
# 构造初始矩阵和变换矩阵
a0 = matrix([1, 2, 3]).transpose()
T = matrix(ZZ, 3, 3)
T[0] = [0, 1, 0]
T[1] = [0, 0, 1]
T[2] = [3, 2, 1]
# 类似于快速幂加速处理过程
def cnt_Ti(i):
if i == 1:
return T
elif i % 2:
return T*cnt_Ti(i-1)
else:
return cnt_Ti(i//2) ^ 2
# 计算数列第i项的值
def m_func(i):
tmp = cnt_Ti(i)*a0
return tmp[0][0]
if __name__ == "__main__":
s = 0
for i in range(100):
T[2] = list(reversed(cof_t[i]))
s += m_func(200000)
# 直接照搬解密流程
s = str(s)[-2000:-1000]
key = md5(s.encode()).digest()
check = sha256(key).hexdigest()
verify = '2cf44ec396e3bb9ed0f2f3bdbe4fab6325ae9d9ec3107881308156069452a6d5'
data = "4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87"
assert(check == verify)
aes = AES.new(key, AES.MODE_ECB)
print(aes.decrypt(bytes.fromhex(data)))
# flag{519427b3-d104-4c34-a29d-5a7c128031ff}
得到结果,将末尾多余的\x00去掉后得到flag{519427b3-d104-4c34-a29d-5a7c128031ff}