引言
无
[AFCTF2018]一道有趣的题目
加密代码如下:
#加密代码
def encrypt(plainText):
space = 10
cipherText = ""
for i in range(len(plainText)):
if i + space < len(plainText) - 1:
cipherText += chr(ord(plainText[i]) ^ ord(plainText[i + space]))
else:
cipherText += chr(ord(plainText[i]) ^ ord(plainText[space]))
if ord(plainText[i]) % 2 == 0:
space += 1
else:
space -= 1
return cipherText
# 密码
# 15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206
观察代码,不难发现,明文和密文是一一对应的
由于已知flag格式为"afctf{}",可以尝试还原部分明文
但由于后续space是未知的,无法继续还原,所以还原space是很关键的
参考了大佬的博客,可以通过爆破的手段得到明文的ascii码的奇偶性,从而还原明密文对应的未知,进而还原明文
需要注意的是,代码种给的密码是密文的16进制,需要进行转换
爆破ascii码的奇偶性代码如下:
from tqdm import tqdm
from Crypto.Util.number import *
cipher = long_to_bytes(int('15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206', 16))
print(cipher)
print(len(cipher))
for j in tqdm(range(2 ** (len(cipher)))):
space = 10
temp = bin(j)[2:].zfill(len(cipher))
for i in range(len(cipher)):
if i + space < len(cipher) - 1:
t = int(temp[i]) ^ int(temp[i + space])
else:
t = int(temp[i]) ^ int(temp[space])
if (cipher[i] % 2) != t:
break
if int(temp[i]) % 2 == 0:
space += 1
else:
space -= 1
if i == len(cipher) - 1:
print(temp)
break
由于异或运算是逐位运算,而二进制表示的最左边一位也反映了十进制的奇偶性,所以对加密代码进行一些修改即可
跑了几分钟。结果为:
(这里的结果与大佬博客的结果最后一位不同,但最后结果没有影响)
接下来就能得到明密文每个字符互相对应的位置
代码如下:
space = 10
list_space = []
temp = '1010011010010101111111101000'
for i in range(len(temp)):
if i + space < len(cipher) - 1:
t = int(temp[i]) ^ int(temp[i + space])
list_space.append((i, i + space))
else:
t = int(temp[i]) ^ int(temp[space])
list_space.append((i, space))
if int(temp[i]) % 2 == 0:
space += 1
else:
space -= 1
print(list_space)
然后利用相对位置还原明文,完整代码如下:
from Crypto.Util.number import *
cipher = long_to_bytes(int('15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206', 16))
plain = [s for s in 'afctf{'] + ['']*21 + ['}']
space = 10
list_space = []
temp = '1010011010010101111111101000'
for i in range(len(temp)):
if i + space < len(cipher) - 1:
t = int(temp[i]) ^ int(temp[i + space])
list_space.append((i, i + space))
else:
t = int(temp[i]) ^ int(temp[space])
list_space.append((i, space))
if int(temp[i]) % 2 == 0:
space += 1
else:
space -= 1
while '' in plain:
for i in range(len(plain)):
if plain[i] != '':
for j in range(len(list_space)):
if list_space[j][0] == i:
plain[list_space[j][1]] = chr(cipher[j] ^ ord(plain[i]))
if list_space[j][1] == i:
plain[list_space[j][0]] = chr(cipher[j] ^ ord(plain[i]))
print(plain)
print(''.join(plain))
list_space
中元素的位置代表密文的位置,由于明密文的位置是一一对应的,所以知道其中一个密文就能得到对应的明文
结果为:
结语
希望继续坚持