• 2022天工杯CTF---crypto1 wp


    AES-CBC

    aes-cbc模式加密在加密和解密是需要一个初始化向量(Initialization Vector, IV),在每次加密之前或者解密之后,使用初始化向量与明文或密文异或。

    加密

    加密时,明文首先与IV异或,然后将结果进行块加密,得到的输出就是密文,同时本次的输出密文作为下一个块加密的IV。
    在这里插入图片描述

    解密

    解密时,先将密文的第一个块进行块解密,然后将结果与IV异或,就能得到明文,同时,本次解密的输入密文作为下一个块解密的IV。
    在这里插入图片描述

    题目

    from Crypto.Cipher import AES
    import binascii
    import hashlib
    from secret import flag
    
    assert flag[:5] == "flag{" and flag[-1:] == "}"
    
    key = b"J1fx2g1jDak1c***"
    l = len(key)
    
    message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
    
    iv = flag[5:-1]
    message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = "utf-8")
    aes = AES.new(key, AES.MODE_CBC, iv)
    print(binascii.hexlify(aes.encrypt(message)))
    #******************************************************************************************************************************************************6ece036e495d363b647d7f2749c4c2f3dd78f8637b
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    过程分析

    根据题目我们可以知道如下信息:

    key的前十三字节为b'J1fx2g1jDak1c',后三位未知
    
    明文的前八十四字节为b"I have had my invitation to this world's festival, and thus my life has been blessed"
    中间十字节未知,最后是bytes((l - len(message) % l) * chr(l - len(message) % l), encoding = "utf-8"),也就是bytes((16-94%16)*chr(16-94%16))==>bytes(2*chr(2)),b'\x02\x02'
        
    密文的后21字节为binascii.unhexlify('6ece036e495d363b647d7f2749c4c2f3dd78f8637b')
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    根据上面aes-cbc的加密过程和解密过程
    我们可以通过已知的最后一个密文块进行aes-ecb模式解密再与最后一个明文块异或,即可得到最后一次的iv,也是上次块加密后的密文
    代码逻辑如下:

    from Crypto.Cipher import AES
    #密文
    enc = 'xxxxxx*****'
    #明文
    m = 'yyyyyy******'
    aes_ecb = AES.new(key,AES.MODE_ECB)
    #aes ecb模式解密
    xor_result = aes_ecb.decrypt(enc)
    #解密结果与明文按位异或
    iv = bytes([i^j for i,j in zip(m,xor_result)])
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ps:因为最终的message与key的值相关,所以我们需要确定key的值才能确定message的值,再依次往回推进而解出初始iv(即flag)

    因此我们需要先生成key的字典,然后去爆破Key

    import string
    
    dic = string.printable[:62]
    with open('key_table.txt','wb') as file:
        for i in dic:
            for j in dic:
                for k in dic:
                    key = b"J1fx2g1jDak1c"+i.encode()+j.encode()+k.encode()
                    file.write(key+b'\n')
    
    file.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    在aes-ecb模式中每一个块的大小是16byte,而已知的密文为后21byte,也就是说倒数第二个密文块已知5byte.由此我们可以根据最后一个块解密的值与最后一个明文块异或的结果的后5byte做比对,得到的值相同的话,该key即为所求key

    from Crypto.Cipher import AES
    from tqdm import tqdm
    import binascii
    import hashlib
    
    def xor(m: bytes, c: bytes):
        return bytes([i ^ j for i, j in zip(m, c)])
    
    enc = binascii.unhexlify('5d363b647d7f2749c4c2f3dd78f8637b')
    five_part = binascii.unhexlify(b"6ece036e49")
    f = open("key_table.txt","rb+")
    pbar = tqdm(range(238328))
    for i in f:
        key = i[:16]
        aes = AES.new(key, AES.MODE_ECB)
        dec = aes.decrypt(enc)
        m = b"ssed" +binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]+b'\x02\x02'
        xor_result = xor(m,dec)
        pbar.update(1)
        if five_part in xor_result:
            print(key)
            break
    file.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    爆破得到Key:

    b'J1fx2g1jDak1c7s4'
    
    • 1

    在这里插入图片描述

    ok,确定key之后我们的明文也就确定下来了

    key = 'J1fx2g1jDak1c7s4'
    message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
    message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding="utf-8")
    
    #b'I have had my invitation to this world\'s festival, and thus my life has been blessed\xedVG\xfd"\xe6\x9d\xd5\xb9\xe2\x02\x02'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    之后将明文分组(16byte一组),然后将上一组解得enc用key去解密,得到xor_result,再将xor_result与同组明文异或即可得到本组iv和上一组enc。以此反复,一步步往前推即可计算出初始iv,即flag。

    接下来是愉快的搓脚本时间(bushi
    在这里插入图片描述

    l = len(key)
    message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
    message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding="utf-8")
    for i in range(0,len(message),16):
        aes_ecb = AES.new(key,AES.MODE_ECB)
        dec_c = aes_ecb.decrypt(enc)
        enc = xor(message[len(message)-i-16:len(message)-i],dec_c)
        print(enc)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    解题脚本

    import binascii
    import hashlib
    import string
    from Crypto.Cipher import AES
    from tqdm import tqdm
    
    def xor(m: bytes, c: bytes):
        return bytes([i ^ j for i, j in zip(m, c)])
    dic = string.printable[:62]
    with open('key_table.txt','wb') as file:
        for i in dic:
            for j in dic:
                for k in dic:
                    key = b"J1fx2g1jDak1c"+i.encode()+j.encode()+k.encode()
                    file.write(key+b'\n')
    
    file.close()
    
    
    enc = binascii.unhexlify('5d363b647d7f2749c4c2f3dd78f8637b')
    five_part = binascii.unhexlify(b"6ece036e49")
    f = open("key_table.txt","rb+")
    pbar = tqdm(range(238328))
    for i in f:
        key = i[:16]
        aes = AES.new(key, AES.MODE_ECB)
        dec = aes.decrypt(enc)
        m = b"ssed" +binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]+b'\x02\x02'
        xor_result = xor(m,dec)
        pbar.update(1)
        if five_part in xor_result:
            print(key)
            break
    file.close()
    l = len(key)
    message = b"I have had my invitation to this world's festival, and thus my life has been blessed" + binascii.unhexlify(hashlib.sha256(key).hexdigest())[:10]
    message = message + bytes((l - len(message) % l) * chr(l - len(message) % l), encoding="utf-8")
    for i in range(0,len(message),16):
        aes_ecb = AES.new(key,AES.MODE_ECB)
        dec_c = aes_ecb.decrypt(enc)
        enc = xor(message[len(message)-i-16:len(message)-i],dec_c)
        print(enc)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    flag

    flag{welcome_1234_igd}
    
    • 1

    【大概世间有一种自讨苦吃,叫做设身处地,处处为他人着想。】

  • 相关阅读:
    k8s--基础--27.2--企业级devops平台--安装jenkins
    (207)Verilog HDL:边缘捕捉寄存器
    美发店微信小程序怎么制作
    JVM 虚拟机 ---->垃圾收集算法
    JS深拷贝处理日期、正则以及循环引用问题
    为什么说新一代BI是“面向业务的可视化分析工具”?
    PY32F003F18之输入捕获
    [JAVAee]Spring的基础介绍
    python单行注释标识符和多行注释符,及用法
    Databend 开源周报第 108 期
  • 原文地址:https://blog.csdn.net/luochen2436/article/details/125884846