2024长城杯铁人三项, Python代码分析题crypto WP
题目描述
题目为一个 crypto.zip的压缩包,解压后得到 python 文件及加密后的文本文件
problem.py
import sys
key = '------unkonw----'
flag = 'flag{----unkown-----}'
if len(key) % 2 != 0:
print("Error,illegal key length")
sys.exit(1)
ciphertext = ''
for each in flag:
for i in range(0,len(key)/2):
temp = (ord(key[i*2]) * ord(each) + ord(key[i*2+1])) % 251
ciphertext += '%02x' % temp
print ciphertext
代码分析
ciphertext
中的字符串如下,长度为 56
cb20dc31e87acbcbf3e2191aa3f3a99219701a52d11a6adcd12624af
分析 Python 文件的加密算法,找到生成 ciphertext
的代码块
ciphertext = ''
for each in flag:
for i in range(0,len(key)/2):
# ord() 返回一个字符十进制的 ascii 码值
temp = (ord(key[i * 2]) * ord(each) + ord(key[ i*2 + 1])) % 251
ciphertext += '%02x' % temp
分析 ciphertext 的生成过程
ciphertext
通过追加 temp
得到,每次取 temp
的前两位并转换为16进制,并且 ciphertext
赋值的部分没有写在 for i
这个循环中。
所以每遍历到 flag
的一个字符,ciphertext
就追加一次,且每次追加的都是for i
循环最后一次的结果。
所以 temp
的算法可以简化为
temp = (x * flag中的每个字符的十进制ascii码值 + y) % 251
根据 flag
的格式, ciphertext
中 cb
由 f
计算得到,20
由 l
计算得到
flag = ‘flag{----unkown-----}’
获取 flag
由于取余算法不可逆,所以我们采用爆破的方式,爆破得到可能存在的 x
与 y
组合,并保存到文件中,x
与 y
的范围选取 ascii 码表中的字符部分(32~126)
with open ('1.txt', 'w'):
pass
with open ('2.txt', 'w'):
pass
temp1 = int('cb', 16)
for x in range(32,126):
for y in range(32,126):
if (x*102 + y) % 251 == temp1:
with open('1.txt', 'a') as f1:
f1.write(f"{x}\t{y}\n")
temp2 = int('20', 16)
for x in range(32,126):
for y in range(32,126):
if (x*108 + y) % 251 == temp2:
with open('2.txt', 'a') as f2:
f2.write(f"{x}\t{y}\n")
比对两个文件相同的部分, 得到 x
与 y
的值,x=97, y=98
with open('1.txt', 'r') as w1:
line1 = w1.readlines()
with open('2.txt', 'r') as w2:
line2 = w2.readlines()
line = set(line1) & set(line2)
for l in line:
print(l)
将 x
与 y
带入,选取 ascii 码表中的字符部分(32~126)进行 flag
碰撞
ciphertext = "cb20dc31e87acbcbf3e2191aa3f3a99219701a52d11a6adcd12624af"
for i in range(0, len(ciphertext), 2):
fl = ciphertext[i: i+2]
fl = int(fl, 16)
for flag in range(32, 126):
if fl == (97 * flag + 98) % 251:
print(chr(flag), end='')
得到 flag{4ffin3_ciph3r_1s_easy!}