DES(2)
buuctf上面有一道很有意思的题目,原题的代码很容易理解,记录一下解题思路(以后一定复习),题目代码如下
import sys
from hashlib import sha256
from Crypto.Cipher import DES
SECRET = 0xa########e # remember to erase this later..
seed = b'secret_sauce_#9'
def keygen(s):
keys = []
for i in range(2020):
s = sha256(s).digest()
keys.append(s)
return keys
def scramble(s):
ret = "".join( [format(s & 0xfffff, '020b')]*101 )
ret += "".join( [format(s >> 20, '020b')]*101 )
return int(ret, 2)
def encrypt(keys, msg):
dk = scramble(SECRET)
for v in keys:
idx = dk & 3
dk >>= 2
k = v[idx*8:(idx+1)*8]
cp = DES.new(k, DES.MODE_CBC, bytes(8))
msg = cp.encrypt(msg)
return msg
keys = keygen(seed)
with open("flag.txt", "rb") as f:
msg = f.read()
ctxt = encrypt(keys, msg)
sys.stdout.buffer.write(ctxt)
这里代码比较容易理解我就简单叙述一下加密流程,首先他把seed用sha256加密(32字节)加入列表key里面重复2020次,scramble函数是将secret(为了和加密对应长度应该是40位)后20位重复101次,再把sercet前20位重复101次,返回一个两端加起来的值(4020位).
加密函数,分1020轮进行,每次取dk的后两位(0-3),然后再取相应key数组里的值(8字节)为该轮des的密钥进行加密
这里主要是要求出secret的值而这里给出了a和e(共8位),也就是我们还要猜出32位,2^32 爆破显然不太现实,我一开始的想法就是,这里很明显将secret分为了两半,我们也可以分半来猜测secret的值,这样就变为了,2^16 + 2^16 这样爆破显然可行些,但是不知道如何验证(后续看了原题好像是少给了一个文件,裂开)
ES-MMXX (created by dm)
--------
Why don'7 y0u ju5t... ?
By the way, "Attack at DAWN!!" maps to "\x15\x08\x54\xff\x3c\xf4\xc4\xc0\xd2\x3b\xd6\x8a\x82\x34\x83\xbe".
Users get:
- enc.py
- flag.enc
这里给了一个加密的例子那就可以了当作验证条件进行中间相遇的一个攻击(枚举secert的前20位进行加密形成一个hashmap,枚举secert的后20位进行解密,如果能在hashmap中找到该值那么当前密钥就是我们所要求的)(参考官方wp)
# DES-MX encryptor for meet in the middle
def encHLF(keys, msg, s):
dk = scramble(s)
# use only first half of the keys
for i in range(len(keys) // 2):
v = keys[i]
idx = dk & 3
dk >>= 2
k = v[idx*8:(idx+1)*8]
cp = DES.new(k, DES.MODE_CBC, bytes(8))
msg = cp.encrypt(msg)
return msg
# DES-MX decryptor for meet in the middle
def decHLF(keys, ctxt, s):
dk = scramble(s)
# use only second half of the keys
n = len(keys)
for i in range(n // 2):
v = keys[n - i - 1]
idx = (dk >> 4038) & 3
dk <<= 2
k = v[(idx*8):(idx+1)*8]
cp = DES.new(k, DES.MODE_CBC, bytes(8))
ctxt = cp.decrypt(ctxt)
return ctxt
keys = keygen(seed)
# break SECRET into two 20-bit parts, perform meet in middle
#
msg = b"Attack at DAWN!!"
ctxt = b"\x15\x08\x54\xff\x3c\xf4\xc4\xc0\xd2\x3b\xd6\x8a\x82\x34\x83\xbe"
# generate DES-MX encryption table for known ptxt, store as hashmap
n=0x10000
c2map = {}
for s in range(n):
if (s & 0xfff) == 0: # progress indicator (every 6.25%)
sys.stderr.write(".")
sys.stderr.flush()
s1 = (0xa0000 + s) << 20
c2map[ encHLF(keys, msg, s1) ] = s1
# match against DES-MX decryption of corresponding ctxt
for s in range(n) :
s2 = 0x0000e + (s << 4)
m2 = decHLF(keys, ctxt, s2)
if c2map.get(m2) != None: # if match found
SECRET = c2map[m2] + s2
print(hex(SECRET))
break
这样就可以爆破出secret(爆破时间可能有点长),有了secret再逆向解密flag.enc就可以了