ksnctf q38 Canned Can Opener
以下の2ファイルがダウンロードできる。
flag.jpg.enc
flag_canned.jpg
問題文を見ると、flag.jpg.encは以下のコマンドで暗号化されている。
$ openssl enc -e -aes-256-cbc -iter 10000 -in flag.jpg -pass file:flag.jpg -out flag.jpg.enc
ここで-pass file:flag.jpgは、flag.jpgの1行目をパスワードとして使用するという意味のようだ。
flag_canned.jpgを使って同様に暗号化復号化すると、どうもパスワードに使われるのは最初のNull文字までのようで、flag_canned.jpgをバイナリエディタで開くと、「FF D8 FF E1 2A 48 45 78 69 66」までの10バイトがパスワードとして使われるようであった。
ということはflag.jpgの1行目も同じデータかもと思い、試して見ることに。
5バイト目と6バイト目の2A48はAPP1アプリケーションセグメントのデータ長らしいので、ここを変えて探索すれば良いのでは?
下記のようなpythonコードを書き、試してみるとセグメントデータ長が0x3950で当たりとなり、decodeした画像にFLAGが表示された。
import os
import subprocess
from sys import byteorder
for n in range(8192, 4096*16):
print(n)
nlist = [0xFF, 0xD8, 0xFF, 0xE1, 0x2A, 0x48, 0x45, 0x78, 0x69, 0x66]
nlist[4] = n // 256
nlist[5] = n % 256
with open('dummy.bin', 'wb') as fp:
blist = [n.to_bytes(1, byteorder) for n in nlist]
fp.writelines(blist)
cmdline = '/usr/bin/openssl enc -d -aes-256-cbc -iter 10000 -in flag.jpg.enc -pass file:dummy.bin -out fout.jpg'
proc = subprocess.Popen(cmdline, shell=True, cwd=os.getcwd(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
res = proc.communicate()
rstr = res[0].decode('utf-8')
if 'bad decrypt' not in rstr:
with open ('fout.jpg', 'rb') as fpi:
data = fpi.read()
if data[0] == 255 and data[1] == 216:
print('found', n, rstr)
break