真·guessguess

看到帖子上的一个题,看WP样子说是暴力的,程序很长没仔细看,感觉可以不用暴力。

from random import shuffle
from secret import secret_msg

ALPHABET = '0123456789abcdef'

class Cipher:
    def __init__(self, key):
        self.key = key
        self.n = len(self.key)
        self.s = 7

    def add(self, num1, num2):
        res = 0
        for i in range(4):
            res += (((num1 & 1) + (num2 & 1)) % 2) << i
            num1 >>= 1
            num2 >>= 1
        return res

    def encrypt(self, msg):
        key = self.key
        s = self.s
        ciphertext = ''
        for m_i in msg:
            c_i = key[self.add(key.index(m_i), s)]
            ciphertext += c_i
            s = key.index(m_i)
        return ciphertext

plaintext = b'The secret message is:'.hex() + secret_msg.hex()

key = list(ALPHABET)
shuffle(key)

cipher = Cipher(key)
ciphertext = cipher.encrypt(plaintext)
print(ciphertext)
#85677bc8302bb20f3be728f99be0002ee88bc8fdc045b80e1dd22bc8fcc0034dd809e8f77023fbc83cd02ec8fbb11cc02cdbb62837677bc8f2277eeaaaabb1188bc998087bef3bcf40683cd02eef48f44aaee805b8045453a546815639e6592c173e4994e044a9084ea4000049e1e7e9873fc90ab9e1d4437fc9836aa80423cc2198882a

加密过程比较简单(虽然写得比较复杂),先把明文转16进制,然后从key里找对应的索引,用索引异或s后得到密文的索引。key是shuffle生成的。明文的头部已经给出,可以通过这些明密对应关系求key

这里密文第3个和明文第3个都是6也就是明文密文索引相同则前一个字符4的索引是0,如果量够大就可以计算出全部的key 。所以这里用z3来一把梭

先把第个字符(0-f)每个给一个索引变量,然后根据明文密文计算 a[i]^seed == a[j] (比如第1个字符5的索引与seed 7异或后得到8的索引,a[5]^7 == a[8])

求出key以后,密文的索引异或seed得到的就是明文的索引

c = '85677bc8302bb20f3be728f99be0002ee88bc8fdc045b80e1dd22bc8fcc0034dd809e8f77023fbc83cd02ec8fbb11cc02cdbb62837677bc8f2277eeaaaabb1188bc998087bef3bcf40683cd02eef48f44aaee805b8045453a546815639e6592c173e4994e044a9084ea4000049e1e7e9873fc90ab9e1d4437fc9836aa80423cc2198882a'

#m = b'The secret message is:'.hex() + secret_msg.hex()
#key = '0123456789abcdef' shuffle(key)
#c_i = key[self.add(key.index(m_i), s)] 
#s = key.index(m_i)
key = [0 for i in range(16)]
m1 = b'The secret message is:'.hex()
s = 7
keystr = '0123456789abcdef'

from z3 import *

#给16个字符每个分配一个索引变量,根据明文密文列公式计算索引值
a = [BitVec(f'a_{i}', 4) for i in range(16)]
s = Solver()
for i in range(1,16):
    for j in range(i):
        s.add(a[i] != a[j])

seed = 7
for i,v in enumerate(m1):
    m_i = int(v,16) 
    c_i = int(c[i], 16)
    s.add( (a[m_i]^seed) == a[c_i])
    seed = a[m_i]

print(s.check())
d = s.model()
print(d) 
for i in range(16):
    key[d[a[i]].as_long()] = keystr[i]
print(key)


seed = 7
m = ''
for v in c:
    seed ^=key.index(v)
    m += key[seed]

print(bytes.fromhex(m))
#b"The secret message is: Nice job! I hope you enjoyed the challenge. Here's your flag: DUCTF{d1d_y0u_Us3_gu3ss1nG_0r_l1n34r_4lg3bRA??}"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值