#!/usr/bin/env python3 from Crypto.Util import number from Crypto.Cipher import AES import os import sys import random from flag import flag def keygen(): iv, key = [os.urandom(16) for _ in '01'] return iv, key def encrypt(msg, iv, key): aes = AES.new(key, AES.MODE_CBC, iv) return aes.encrypt(msg) def decrypt(enc, iv, key): aes = AES.new(key, AES.MODE_CBC, iv) return aes.decrypt(enc) def die(*args): pr(*args) quit() def pr(*args): s = " ".join(map(str, args)) sys.stdout.write(s + "\n") sys.stdout.flush() def sc(): return sys.stdin.readline().strip() def main(): border = "+" pr(border*72) pr(border, " hi all, welcome to the simple KEYBASE cryptography task, try to ", border) pr(border, " decrypt the encrypted message and get the flag as a nice prize! ", border) pr(border*72) iv, key = keygen() flag_enc = encrypt(flag, iv, key).hex() while True: pr("| Options: \n|\t[G]et the encrypted flag \n|\t[T]est the encryption \n|\t[Q]uit") ans = sc().lower() if ans == 'g': pr("| encrypt(flag) =", flag_enc) elif ans == 't': pr("| Please send your 32 bytes message to encrypt: ") msg_inp = sc() if len(msg_inp) == 32: enc = encrypt(msg_inp, iv, key).hex() r = random.randint(0, 4) s = 4 - r mask_key = key[:-2].hex() + '*' * 4 mask_enc = enc[:r] + '*' * 28 + enc[32-s:] pr("| enc =", mask_enc) pr("| key =", mask_key) else: die("| SEND 32 BYTES MESSAGE :X") elif ans == 'q': die("Quitting ...") else: die("Bye ...") if __name__ == '__main__': main()
鍵全探索してiv
みつけるだけっぽい。
flagの後ろのパートCBCモードで復号してみて成功したら鍵で、その鍵をつかってCBCモードの性質をつかって、後ろのブロックの平文と暗号文のペアから前のブロックの暗号文を順に復元していける
from itertools import product from Crypto.Cipher import AES from ptrlib import Socket, xor def cbc_decrypt(key, iv, ciphertext): return AES.new(key, mode=AES.MODE_CBC, iv=iv).decrypt(ciphertext) def ecb_encrypt(key, plaintext): return AES.new(key, mode=AES.MODE_ECB).encrypt(plaintext) def ecb_decrypt(key, ciphertext): return AES.new(key, mode=AES.MODE_ECB).decrypt(ciphertext) sock = Socket("nc 01.cr.yp.toc.tf 17010") sock.sendlineafter("[Q]uit\n", "G") flag = bytes.fromhex(sock.recvlineafter("(flag) = ").decode()) payload = b"A" * 32 sock.sendlineafter("[Q]uit\n", "T") sock.sendlineafter("encrypt:", payload) ciphertext = sock.recvlineafter("enc = ").decode() # iv | AA... | AA... key_prefix = sock.recvlineafter("key = ").decode() for post in product("012356789abcdef", repeat=4): key = bytes.fromhex(key_prefix[:-4] + "".join(post)) plaintext = cbc_decrypt(key, flag[:16], flag[16:]) if all([0x20 <= b < 0x7f for b in plaintext]): break else: assert False cdar_block = bytes.fromhex(ciphertext[-32:]) car_block = xor(payload[-16:], ecb_decrypt(key, cdar_block)) iv = xor(payload[:16], ecb_decrypt(key, car_block)) print(cbc_decrypt(key, iv, flag))