Cata1yst's blog

祇今尚有清流月,曾照高王万马过

0%

New👴CTF Crypto wp

AES

我不好说什么,披着 $aes$ 外皮的梅森。反正就是,很离谱。

话不多说,直接上wp

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from Crypto.Cipher import AES
from binascii import *
from libnum import s2n
from random import *
ciphertext=b'c82dc20b7512d03f1a0982eb8a6e855db20f6fe3ff8d202a6fb74c6522fa6e623c6abe6725cafe78f9624ad59f3e90af6f985f38f75ec4d62ff7e02bd7c2f051'
ciphertext=a2b_hex(ciphertext)
old_key = b'73E5602B54FE63A5'
old_iv = b'B435AE462FBAA662'
def add_to_16(text):
if len(text.encode('utf-8')) % 16:
add = 16 - (len(text.encode('utf-8')) % 16)
else:
add = 0
text = text + ('\0' * add)
return text.encode('utf-8')

def init():
r1 = getrandbits(64)
r2 = getrandbits(32)
m = "{:X}".format(r1).encode('utf-8')
salt = "{:X}".format(r2).encode('utf-8')
m += salt
return add_to_16(m.decode())

def encrypt(m, key, iv):
mode = AES.MODE_CBC
cryptos = AES.new(key, mode, iv)
cipher_text = cryptos.encrypt(m)
return cipher_text

def chall(key, iv):
old_m = init()
c = encrypt(old_m, key, iv)
return b2a_hex(c)
def decrypt(c, key, iv):
mode = AES.MODE_CBC
cryptos = AES.new(key, mode, iv)
plaintext= cryptos.decrypt(c)
return plaintext
f = open('msg.txt', 'r')
m=[]
prng=[]
c = a2b_hex(f.readline().strip('\n').encode())
while (c):
m.append(decrypt(c, old_key, old_iv).strip(b'\00'))
c = a2b_hex(f.readline().strip('\n').encode())
#highlight here
if(len(m[396//3])<24):
m[396//3]=m[396//3].decode().zfill(24).encode()
for i in m:
x = i.strip(b'\x00')
if len(x) == 24:
prng.append(int(i[8:16], 16))
prng.append(int(i[:8], 16))
prng.append(int(i[16:], 16))
else:
for _ in range(3):
prng.append(0)
print(prng)
'''
sage
#state的比特数
d=32
n=624
o=397
mask=0x9908b0df
b=2636928640
c=4022730752
#n个随机数比特向量构成的列表
x=[]
#获得d*d的单位矩阵
def get_I(d):
I=[]
for i in range(d):
temp=[0 for _ in range(d)]
temp[i]=1
I.append(temp)
return matrix(GF(2),I)
#获得>>l的变换矩阵
def get_right(l):
temp=[]
for i in range(l):
temp.append([0 for _ in range(d)])
for i in range(d-l):
k=[0 for _ in range(d)]
k[i]=1
temp.append(k)
return matrix(GF(2),temp).transpose()
#获得<<l的变换矩阵
def get_left(l):
temp=[]
for i in range(l):
temp.append([0 for _ in range(d)])
for i in range(d-l):
k=[0 for _ in range(d)]
k[i]=1
temp.append(k)
return matrix(GF(2),temp)
#获得&的变换矩阵
def get_and(a):
a=bin(a)[2:].zfill(d)
m=[]
for i in range(d):
k=[0 for _ in range(d)]
k[i]=int(a[i])
m.append(k)
return matrix(GF(2),m)
#将十进制数列表转化为二进制数矩阵列表
def bin_state(state):
new_state=[]
for i in state:
tmp=bin(i)[2:].zfill(32)
new_state.append([int(tmp[_]) for _ in range(len(tmp))])
return new_state
#将二进制数矩阵列表转化为十进制数列表
def dec_state(state):
new_state=[]
for i in state:
tmp='0b'
for j in i:
tmp+=str(j)
new_state.append((int(tmp,2)))
return new_state
def last(tmp,i):
a=1812433253
n=2**32
tmp-=i
a=inverse_mod(a,n)
tmp=(tmp*a)%n
return (tmp>>30)^^tmp
#生成变换矩阵
U=get_right(11)
S=get_left(7)
T=get_left(15)
L=get_right(18)
B=get_and(b)
C=get_and(c)
I=get_I(d)
F=(I+U)*(I+S*B)*(I+T*C)*(I+L)
rand=[]
rand=bin_state(rand)
for i in range(len(rand)):
X=matrix(GF(2),rand[i])
O=F.solve_left(X)
rand[i]=O[0]
state=dec_state(rand)
print(state)
'''
cur_state=[]
setstate((3, tuple(cur_state + [624]), None))
salt = "{:X}".format(getrandbits(32)).encode('utf-8')
key = "{:X}".format(getrandbits(64)).encode('utf-8')
iv = "{:X}".format(getrandbits(64)).encode('utf-8')
plaintext=decrypt(ciphertext, key, iv).strip(b'\x00').decode()
for i in plaintext:
if i not in salt.decode():
print(i,end='')


注意一下并不是每个密文解密都是96位的,所以不能直接把明文三段分当成三个连续随机数。也不能单纯前面补0凑96位,因为这个96比特数的本质是32+64位比特数,我们不知道是32位少0还是64位少0,这个需要尝试。

还有一点是虽然解密出来很多数都不是96比特,但是我们没必要复原全部,根据后来的情况,它只是又生成了32+64+64位比特也就是5个输出,所以我们只需要复原 $state$ 的 $0、1、2、3、4、397、398、399、400、401$ 位就可以了。

算法原理之前写过不多说了。

keyExchange

$Diffle-Hellman$ 密钥交换,所有参数都给了,直接解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import md5
from base64 import b64decode
c=b'w8OCrexPPqnv2hR+xKeHhXIp0Blp1DYCV4LeZeeLpv5MzUL71raTOeOs4SQBySHH'
p=
g=
b=
c=b64decode(c)
key=(pow(b,a,p))
key = md5(str(key).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
print(cipher.decrypt(c))

Prof. Shamir’s Secret

四个四元方程这不有手就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#sage
from Crypto.Util.number import *
x=
f=
n=
print(len(x),len(f))
X=[]
for i in range(3,-1,-1):
tmp=[pow(_,i,n) for _ in x]
X.append(tmp)
F=matrix(GF(n),f)
M=matrix(GF(n),X)
print('matrix prepared')
print( long_to_bytes(M.solve_left(F)[0][3]))

One Time Pad

没写,应该是用 $kasiski$ 测试法确定密钥长度然后爆破。