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

过程分析

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

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')


根据上面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)])

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()

在这里插入图片描述
在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()

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

b'J1fx2g1jDak1c7s4'

在这里插入图片描述

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'

之后将明文分组(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)

解题脚本

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)

flag

flag{welcome_1234_igd}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值