20210527-美团CTF-CryptoSecPartWriteUp

 

easy_RSA

考点

  • MTP 多次一密

第一层套了一个padding,比较常规不再赘述

第二层是多次一加密(Many Time Pad),大致的加密思路就是每次都用相同的key去加密明文

输入第一层的密码,压缩包文件里的内容是这样的,有十二个十六进制的数字

easy_RSA-a8cb1b59.png

参考Many-Time-Pad 攻击,原理主要就是两个密文异或,可以把相同的key去掉,这样就相当于两个明文异或了

因为密文不等长,所以要先把第六和第十二个密文填充和其他密文等长的长度(末尾填充0

第一次运行结果是这样的(下面这个[u]表示utf-8表示不了的字符,任由其在这里导致xml报错博客不能本地搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
N=w -ou need to u}e the k3
o%n 2lag as the kky of On8
[u]im1 Pad Encryptgn. Now )
h3t -ou have passkd the p/
e$io!s RSA test, zhis cha1
l7ng1 is not partgcularly
p>ea'e get the tr{e messa:
d;ff=cult for you It is 7
u!t 'imple encrypzion.I h2
p7 y;u can solve zhis pro?
l7m %uickly and gkt the c2
r ec answer succksslyp@d
b'f>ag/it_1s_P@dd1nQ@nd_p@d '

而接下来要做的就是猜字母,将很明显错地方的字母给替换成对的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def know(p_index, p_pos, ch):
msg[p_index, p_pos] = ord(ch)
for x in range(len(c)):
if x != p_index:
msg[x][p_pos] = xo.strxor(c[x], c[p_index])[p_pos] ^ ord(ch)


# 需要手动更改的就是这个地方,按照意思,替换你确定的字母
know(0, 1, 'o')
know(0, 4, 'y')
know(0, 12, ' ')
know(0, 13, 't')
know(0, 17, 's')
know(0, 19, ' ')
know(1, 25, 'e')

完整的exp

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
import Crypto.Util.strxor as xo
import codecs
import numpy as np


def ischr(x):
if ord('a') <= x <= ord('z'):
return True
if ord('A') <= x <= ord('Z'):
return True
return False


def infer(p_index, p_pos):
if msg[p_index, p_pos] != 0:
return
msg[p_index, p_pos] = ord(' ')
for x in range(len(c)):
if x != p_index:
msg[x][p_pos] = xo.strxor(c[x], c[p_index])[p_pos] ^ ord(' ')


dat = []


def get_space():
for t_index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x != y]
f = lambda t_pos: len(list(filter(ischr, [s[t_pos] for s in res])))
cnt = [f(t_pos) for t_pos in range(len(x))]
for t_pos in range(len(x)):
dat.append((f(t_pos), t_index, t_pos))


# 第十二行和第六行长度不一,末尾填充0就好了
c = [codecs.decode(x.strip().encode(), 'hex') for x in open('t3mpt.txt', 'r').readlines()]

msg = np.zeros([len(c), len(c[0])], dtype=int)

get_space()

dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)


def know(p_index, p_pos, ch):
msg[p_index, p_pos] = ord(ch)
for x in range(len(c)):
if x != p_index:
msg[x][p_pos] = xo.strxor(c[x], c[p_index])[p_pos] ^ ord(ch)


# 需要手动更改的就是这个地方,按照意思,替换你确定的字母
know(0, 1, 'o')
know(0, 4, 'y')
know(0, 12, ' ')
know(0, 13, 't')
know(0, 17, 's')
know(0, 19, ' ')
know(1, 25, 'e')

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))

# 其实只需要知道一条正确的明文就够了,key=C1^M1
key = xo.strxor(c[0], ''.join([chr(c) for c in msg[0]]).encode())
print(key)

something else

另外找到一个Python2的脚本,看上去密文似乎不需要等长,流密码-多次一密(Many-Time-Pad-Attack)