##概要
SECCON CTF 2019のうち、crypt問題のcoffee_breakのwrite-upを記載します。
##問題
The program "encrypt.py" gets one string argument and outputs ciphertext.
Example:
$ python encrypt.py "test_text"
gYYpbhlXwuM59PtV1qctnQ==
The following text is ciphertext with "encrypt.py".
FyRyZNBO2MG6ncd3hEkC/yeYKUseI/CxYoZiIeV2fe/Jmtwx+WbWmU1gtMX9m905
Please download "encrypt.py" from the following url.
encrypt.pyは以下のとおり。
import sys
from Crypto.Cipher import AES
import base64
def encrypt(key, text):
s = ''
for i in range(len(text)):
s += chr((((ord(text[i]) - 0x20) + (ord(key[i % len(key)]) - 0x20)) % (0x7e - 0x20 + 1)) + 0x20)
return s
key1 = "SECCON"
key2 = "seccon2019"
text = sys.argv[1]
enc1 = encrypt(key1, text)
cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB)
p = 16 - (len(enc1) % 16)
enc2 = cipher.encrypt(enc1 + chr(p) * p)
print(base64.b64encode(enc2).decode('ascii'))
##解法
"encrypt.py"はテキスト文を暗号化するプログラムのようです。
暗号化されたテキストを復号すればflagが手に入りそうです。
まずはencrypt関数を復号する関数(decrypt関数)を作成することにしました。
encrypt関数は、引数で与えられたテキスト(text)を文字ごとに、文字コードへ変換→計算→文字へ
変換しています。
なので、足されたものを引いて、引かれたものを足せば元に戻りそうです。
encrypt関数とdecrypt関数のみを含んだプログラムで動作確認をしつつ作成した関数が以下になります。
def decrypt(key, encTxt):
t= ''
for j in range(len(encTxt)):
t += chr((((ord(encTxt[j]) -0x20) - (ord(key[j % len(key)]) - 0x20)) % (0x7e - 0x20 + 1)) + 0x20)
return t
"encrypt.py"の後半部分ですが、AESで暗号化しています。
AESは共通鍵暗号方式(暗号化と復号が同じ鍵を使用)なので、key2をそのまま流用可能です。
なお、pはブロックの端数を埋めるためのもの(パディング)です。
復号用の関数は以下のようになります。
import sys
from Crypto.Cipher import AES
import base64
def decrypt(key, encTxt):
t= ''
for j in range(len(encTxt)):
t += chr((((ord(encTxt[j]) -0x20) - (ord(key[j % len(key)]) - 0x20)) % (0x7e - 0x20 + 1)) + 0x20)
return t
key1 = "SECCON"
key2 = "seccon2019"
text = sys.argv[1]
dec1 = base64.b64decode(text)
cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB)
dec2 = cipher.decrypt(dec1).decode("ascii")
print(decrypt(key1, dec2))
これを実行すると以下のようになります。
$ python decrypt.py FyRyZNBO2MG6ncd3hEkC/yeYKUseI/CxYoZiIeV2fe/Jmtwx+WbWmU1gtMX9m905
SECCON{Success_Decryption_Yeah_Yeah_SECCON}?AA56
flagが得られました。"}"以降の文字列はAES復号の際に付与されたパディングなので無視します。