[NCTF2019]Reverse
题目
汮S賳!Ⅳ?Z_l,?漋& hDa莸&5匼?oZ€|U€骸%#}巴
import os
import pyDes
flag = "NCTF{******************************************}"
key = os.urandom(8)
d = pyDes.des(key)
cipher = d.encrypt(flag.encode())
with open('cipher', 'wb') as f:
f.write(cipher)
# Leak: d.Kn[10] == [0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1]
解题
读程序
pyDes模块:
pyDes.des(key, [mode], [IV], [pad], [padmode])
pyDes.triple_des(key, [mode], [IV], [pad], [padmode])
key->包含加密密钥的字节。DES为8字节,16或24字节
三重DES
mode -> 加密类型的可选参数,可以是pyDes.ECB(电子码本)或pyDes.CBC(密码区块链)
IV -> 可选初始值字节,如果使用CBC模式,则必须提供。长度必须为8字节。
pad -> Optional参数,将pad字符(pad\u NORMAL)设置为在使用此实例完成的所有加密/解密操作。
padmode -> 可选参数,设置填充模式(PAD_NORMAL或PAD_PKCS5)在对此实例执行的所有加密/解密操作期间使用。
encrypt(data, [pad], [padmode])
decrypt(data, [pad], [padmode])
data -> 要加密/解密的字节
pad -> 可选参数。仅当使用PAD_NORMAL的padmode时。对于加密时,将此字符添加到数据块的末尾数据不是8字节的倍数。对于解密,将删除最后8个字符中与此填充字符匹配的尾随字符未加密数据块的字节数。
padmode -> 可选参数,设置填充模式,必须是PAD\u NORMAL之一或PAD_PKCS5)。默认为PAD_NORMAL
os.urandom(n)返回一个有n个byte那么长的一个string,然后很适合用于加密。
每轮循环左移的位数不一定相同
泄露的d.Kn[10] 说明已经进行了11轮了(每一轮生成一个子密钥),因此要做sum(movnum[:11])次逆运算
from base64 import b64decode
from itertools import product
from DES import * # https://github.com/soreatu/Cryptography/blob/master/DES.py
guess_8bit = list(product(range(2), repeat=8))
not_in_PC2 = [9,18,22,25,35,38,43,54]
def re_PC2(sbkey):
# 48-bit -> 56-bit
res = [0]*56
for i in range(len(sbkey)):
res[PC_2_table[i]-1] = sbkey[i]
return res # ok
def guess_CiDi10(sbkey, t):
res = re_PC2(sbkey)
for i in range(8):
res[not_in_PC2[i]-1] = guess_8bit[t][i]
return res # ok
def guess_allsbkey(roundkey, r, t):
sbkey = [[]]*16
sbkey[r] = roundkey
CiDi = guess_CiDi10(roundkey, t)
Ci, Di = CiDi[:28], CiDi[28:]
for i in range(r+1,r+16):
Ci, Di = LR(Ci, Di, i%16)
sbkey[i%16] = PC_2(Ci+Di)
return sbkey # ok
def long_des_enc(c, k):
assert len(c) % 8 == 0
res = b''
for i in range(0,len(c),8):
res += DES_enc(c[i:i+8], k)
return res
def try_des(cipher, roundkey):
for t in range(256):
allkey = guess_allsbkey(roundkey, 10, t)
plain = long_des_enc(cipher, allkey[::-1])
if plain.startswith(b'NCTF'):
print(plain)
if __name__ == "__main__":
cipher = b64decode(b'm0pT2YYUIaL0pjdaX2wsxwedViYAaBkZA0Rh3bUmNYVclBlvWoB8VYC6oSUjfbDN')
sbkey10 = [0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1]
try_des(cipher, sbkey10)
# b'NCTF{1t_7urn3d_0u7_7h47_u_2_g00d_@_r3v3rs3_1snt}'
参考
答案
flag{1t_7urn3d_0u7_7h47_u_2_g00d_@_r3v3rs3_1snt}