BUUCTF 每日打卡 2021-8-26

引言

[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中元素的位置代表密文的位置,由于明密文的位置是一一对应的,所以知道其中一个密文就能得到对应的明文
结果为:
在这里插入图片描述

结语

希望继续坚持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值