この大会は2019/3/4 2:00(JST)~2019/3/5 10:00(JST)に開催されました。
今回もチームで参戦。結果は763点で1092チーム中21位でした。
自分で解けた問題をWriteupとして書いておきます。
futurella (Web 1)
Webページにはalien cipherの文字で書かれているが、ソースを見るとフラグがわかった。フォントでそのように操作されていたようだ。
CTF{bring_it_back}
Trivia 1 (101 2)
問題は「My voice is my ________. Verify me.」。穴埋め問題。インターネットで調べるとすぐわかる。
passport
kookie (101, Web 10)
cookie / monsterでログインすると、Cookieのusernameにcookieがセットされている。adminに変更すると、フラグが表示された。
CTF{kookie_cookies}
zippy (Forensics 50)
TCP Streamを見ると、以下のコマンドが実行されていることがわかる。
nc -l -p 4445 > flag.zip unzip -P supercomplexpassword flag.zip Archive: flag.zip inflating: flag.txt
No.9のパケットにflag.zipのデータがあるので、エクスポートする。それから上記と同じようにコマンドを実施する。
$ unzip -P supercomplexpassword flag.zip Archive: flag.zip inflating: flag.txt $ cat flag.txt CTF{this_flag_is_your_flag}
CTF{this_flag_is_your_flag}
table-tennis (Forensics 50)
ICMPパケットが流れている。問題タイトルからもこのデータにフラグが隠されていそう。各パケットからデータ部分を抜き出す。
e0p1c3RB UzBuZ0Fi MHV0UDFu Z1Awbmd9
全部結合して、Base64デコードしてみる。
$ echo e0p1c3RBUzBuZ0FiMHV0UDFuZ1Awbmd9 | base64 -d {JustAS0ngAb0utP1ngP0ng}
CTF{JustAS0ngAb0utP1ngP0ng}
decrypto (Crypto, Web 300)
何もしないと以下のように表示される。
Welcome to the mainframe! ... It looks like you want to access the flag! Please present user object ... ... ... ...scanning ... ...scanning ... Scanning user object... ...your UID value is set to 56 ... ... ...your NAME value is set to baseuser ...your SKILLS value is set to n/a ... ERROR: ACCESS DENIED ... ... UID MUST BE '0'
クッキーの状態は以下の通りで、リセットするとパラメータが変わるようだ。
signature 809f6357940b81340fc147830f56f344fe1999316d4b34d8908d784a170869b6 user e79b54a46aae832c6cb5e9c5cf3903d18046172a49d243198560272d397af792ab7d683425445e75666f3a6b2086d83c7197c9cff3a5c1f9df64c28714fb3a4d rack.session BAh7CEkiD3Nlc3Npb25faWQGOgZFVEkiRWYyZWVlMzljZDBjMjg2ZDE2MWFm%0AZDI2OTdiODkwOTE2M2RkYmJlOTVkYjU5YzgzNmY5NDcwOWEyZGZlMmU5OGYG%0AOwBGSSILc2VjcmV0BjsARiINJmUAQX1%2BsONJIghrZXkGOwBGIiUFvW1HPcr3%0AaB%2ByY2RPWz%2BprqfdSaqNNT%2BfZCfk1obFOQ%3D%3D%0A--1bc34de559dc8cfd69cf2d8a117e1c7f6bec6eaf
UIDを0にする必要があるが、文章に書かれている内容から、signatureについてはHash Length Extension Attackで何とかなりそう。
問題はuserだが、文字列長からAESの暗号と思われる。rack.sessionの%0Aの前までをBase64デコードしてみると、最後の32バイトが鍵だと推測できる。それを鍵として、復号してみる。
from Crypto.Cipher import AES def unpad(s): return s[:-ord(s[-1])] enc = 'e79b54a46aae832c6cb5e9c5cf3903d18046172a49d243198560272d397af792ab7d683425445e75666f3a6b2086d83c7197c9cff3a5c1f9df64c28714fb3a4d'.decode('hex') with open('session', 'rb') as f: data = f.read() key = data[-32:] iv = enc[:16] enc = enc[16:] aes = AES.new(key, AES.MODE_CBC, iv) dec = unpad(aes.decrypt(enc)) print dec
実行した結果は以下のとおり。
UID 56 NAME baseuser SKILLS n/a
このデータ形式でHash Length Extension Attackを行い、得られたデータで暗号化したものをクッキーのuserに設定すればよい。
from Crypto.Cipher import AES import hashpumpy def pad(s): n = 16 - len(s) % 16 return s + chr(n) * n def encrypt(key, s): iv = '0123456789abcdef' aes = AES.new(key, AES.MODE_CBC, iv) enc = aes.encrypt(pad(s)) return (iv + enc).encode('hex') sign = '809f6357940b81340fc147830f56f344fe1999316d4b34d8908d784a170869b6' base = 'UID 56\nNAME baseuser\nSKILLS n/a\n' h, d = hashpumpy.hashpump(sign, base, '\nUID 0\n', 8) print 'signature:', h with open('session', 'rb') as f: data = f.read() key = data[-32:] user = encrypt(key, d) print 'user :', user
実行結果は以下の通り。
signature: d94e43b063c5e9e4334e2080f7207986792276cf34a260d8ec0c40eff4e03dc0 user : 303132333435363738396162636465661da120fecc4dfcd79b5fe6efb58b8a43054dac681fb99dfe53abd775bf2d1bcede42992c655039ef77071b396fede73ff33b551a9226ac4949b19860e253a23f
それぞれクッキーに設定して画面を更新すると、以下の通りフラグが表示された。
Welcome to the mainframe! It looks like you want to access the flag! ... Please present user object ... ...scanning ... ...scanning ... ... ... ... Scanning user object... ...your UID value is set to 0 ...your NAME value is set to baseuser ... ... ... ...your SKILLS value is set to n/a ...your ����������������������@ value is set to FLAG VALUE: CTF{parse_order_matters}
CTF{parse_order_matters}