SECCON 2018 Online CTF Writeup - QRChecker
概要
SECCON 2018 Online CTF の Writeup 2問目です。
QR コードチェッカーのコードを読み解き、画像を作り出す問題です。
開催時間中には解けませんでしたが、記録として残します。
QRChecker
問題は以下のサイトで公開されています。
http://qrchecker.pwn.seccon.jp/
まずは公開されている Python のソースコードを確認。
HTML 出力部分は無視して、QR コードの処理周りを抜粋しました。
codes = set() sizes = [500, 250, 100, 50] data = form["uploadFile"].file.read(1024 * 256) image= Image.open(io.BytesIO(data)) for sz in sizes: image = image.resize((sz, sz)) result= zbarlight.scan_codes('qrcode', image) if result == None: break if 1 < len(result): break codes.add(result[0]) for c in sorted(list(codes)): print(c.decode()) if 1 < len(codes): print("SECCON{" + open("flag").read().rstrip() + "}")
フラグの出力処理を確認
たどり着きたいのはこの部分のコードです。
if 1 < len(codes): print("SECCON{" + open("flag").read().rstrip() + "}")
codes
には QR コードの読み取り結果を格納しているため、どうにかして2件以上の QR コードを認識させる必要があります。
1回で1つの QR コードしか認識しない
QR コードの読み取り部分を見てみます。
result
に2件以上の結果が格納されると、break
で処理が終わってしまいます。
for (略): result= zbarlight.scan_codes('qrcode', image) if result == None: break if 1 < len(result): break codes.add(result[0])
アップロードできる画像は1つだけですが、2つ以上の QR が認識されるとアウトです。
でも、フラグを得るためには2つ以上の QR を認識させたいのです。
リサイズ処理で QR コードを変化させる
ここで、QR 判定の直前に行われているリサイズ処理に注目します。
500x500
, 250x250
, 100x100
, 50x50
の4サイズが定義されており、リサイズ後に QR コードの読み取りを行うところがポイントです。
codes = set() sizes = [500, 250, 100, 50] for sz in sizes: image = image.resize((sz, sz)) result= zbarlight.scan_codes('qrcode', image) if result == None: break if 1 < len(result): break codes.add(result[0]) for c in sorted(list(codes)): print(c.decode())
例えば、500x500
と 100x100
で読み取り結果の変わる QR コードが用意できれば、最終的に2件の QR を codes
に格納できるはずです。
2種類の QR コードを用意して入れ子に
QR コードの誤り訂正を逆手に取れば何とかなりそうです。
a
と b
の文字を入れた QR コードを用意。QR のススメ などで生成できます。
b
の画像を大きめに拡大して、その中に a
の QR コードを埋めたのがこちら。
この QR コードでは、内側の a
が認識されます。
同じ画像を 100x100
にリサイズすると、
内側が潰れて読めなくなるため、今度は外側の b
が認識されます。
フラグ獲得
SECCON の回答サーバに画像をアップロードするとフラグが出力されました。
SECCON{50d7bc7542b5837a7c5b94cf2446b848}