CSAW CTF 2016 Writeup
9/17早朝から9/19早朝までの2日間開催されたCSAW CTF 2016に「wabisabi」で参加しました。結果はチームで8問解いて576pt、1274チーム中252位。にこにー(矢澤にこ)が好きな自分にとってはラッキーな数字でした。自分は4問解いて300pt入れました。今回はその4問について簡単にwriteupを残したいと思います。
Writeup
Forensics 100: Clams Don't Dance
最近、諸事情でforensicsを勉強することになり、今回は何問か解きたいなと思っていたため最初にこれに取り掛かりました。
問題は、まず out.img というファイルを渡されます。
お決まりのfileコマンド
boot sector らしい。
そういえばksnctfでも同じような問題あったなと、とりあえずFTK Imagerで開いてみる。
削除されたものである、clam.pptxというファイルが見つかる。
その他にも怪しげなdance.mp4というファイルがあったが、問題名のClams Don't Danceからこれは違うと予想してスルー。
clam.pptxを取り出して、自分はubuntuなのでLibreOfficeで開こうとするも開けない。(修復を試みますか?とか聞かれるけど無理だった)
どうしようかと思ったが、とりあえずbinwalkに投げてみればいくつか取り出せるんじゃないかと思い、投げてみる。
すると大量のファイルを取り出すことができ、怪しそうなものはないか見ていく。
ppt/mediaにimage0.gifというファイル名で、なにやらQRコードらしきものが見つかる。
なにこれ・・・となったが、困った時のGoogle先生。
画像検索してみるとどうやら「MaxiCode」というものらしい。
これを読み取るフリーのツールを探すもなかなか見つからなかったが、最終的に「ByteScout BarCode Reader」というソフトに辿り着く。
読み取ってみたところ綺麗にflagが出てきた。
flag{TH1NK ABOUT 1T B1LL. 1F U D13D, WOULD ANY1 CARE??}
Reversing 50: Gametime
チームでは一応binary担当ということになっている(辛い)ので何問かは解こうと思い、最初に一番簡単なやつをやってみる。
gametime.exeというファイルを渡され、問題文にはflagの形式は↑のようなものじゃないよと書かれていた。
最近Ollydbgを使っていたのでidaではなくOllydbgを使ってみる。
実行してみると、「sが見えたらspace bar押してね」や「xが見えたらxを押す」、「mが見えたらmを押す」というゲーム。(説明が下手)
とりあえず、分岐命令辺りでブレークポイントを設定してみてゲームが終わらないように上手く回避していく。
すると、TURBO TIME!とか始まって、flagがゲットできた。
no5c30416d6cf52638460377995c6a8cf5
Reversing 125: Key
key.exeというファイルが渡されるので、またOllydbgで実行してみる。
What happen?(だったかな?)、まぁそんな英文が表示されて終了するだけのプログラム。
また、分岐命令辺りにブレークポイント設定しながら進めていくが最終的に
=W=r=o=n=g=K=e=y=
とか表示されて、終わってしまう。
ここで、スタック上に積まれた文字列に注目してみた。
まさかな?と思い、とりあえずsubmit(これ大事)してみると通った。
idg_cni~bjbfi|gsxb
(この問題に関してはwriteupになっていない気がするが、許してほしい)
Misc 25: Coinslot
Recon 200 の Fuzyllという問題が途中で詰まってしまい、なにか他の解いたほうが良さそうと思って始めた問題。
につないでみると、紙幣などの枚数を求める的な問題。途中でミスるとアウト。
手動で10回ぐらいまでやってみたが、もっともっと回数が必要そう。
今まで、スクリプトを書けば簡単に終わりそうな問題も「面倒くさい」という理由から逃げてきたため、いつもの自分だったら解かなかったと思う。
だけど、今回は何かしら成長したいと思ったのかどうか知らないが、早朝4時過ぎからコードを書き始めた。
結果、くそコードを生み出してしまった。反省はして(ry
以下のスクリプトを回した結果、20分くらい?(400回目)で解けた。
(一応999回で書いたが、途中で1000回までいかないよな・・・?とか思って、少し不安だった)
#!/usr/bin/env python import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('misc.chal.csaw.io', 8000)) for i in range(1, 1000): data = s.recv(256) print data all_data = data.split('\n') num_s = all_data[0].replace('$', '') num = num_s.split('.') big_num_s = num[0] sml_num_s = num[1] big_num = int(big_num_s) if big_num / 10000 > 0: s.sendall(str(big_num/10000) + '\n') big_num = big_num % 10000 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 5000 > 0: s.sendall(str(big_num/5000) + '\n') big_num = big_num % 5000 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 1000 > 0: s.sendall(str(big_num/1000) + '\n') big_num = big_num % 1000 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 500 > 0: s.sendall(str(big_num/500) + '\n') big_num = big_num % 500 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 100 > 0: s.sendall(str(big_num/100) + '\n') big_num = big_num % 100 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 50 > 0: s.sendall(str(big_num/50) + '\n') big_num = big_num % 50 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 20 > 0: s.sendall(str(big_num/20) + '\n') big_num = big_num % 20 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 10 > 0: s.sendall(str(big_num/10) + '\n') big_num = big_num % 10 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 5 > 0: s.sendall(str(big_num/5) + '\n') big_num = big_num % 5 else: s.sendall('0\n') data = s.recv(256) print data if big_num / 1 > 0: s.sendall(str(big_num/1) + '\n') big_num = big_num % 1 else: s.sendall('0\n') data = s.recv(256) print data check = sml_num_s[:1] if check == '0': sml_num = int(sml_num_s[1:]) for i in range(0, 3): s.sendall('0\n') s.recv(256) print data if sml_num / 5 > 0: s.sendall(str(sml_num/5) + '\n') sml_num = sml_num % 5 else: s.sendall('0\n') data = s.recv(256) print data if sml_num / 1 > 0: s.sendall(str(sml_num/1) + '\n') sml_num = sml_num % 1 else: s.sendall('0\n') else: sml_num = int(sml_num_s) if sml_num / 50 > 0: s.sendall(str(sml_num/50) + '\n') sml_num = sml_num % 50 else: s.sendall('0\n') data = s.recv(256) print data if sml_num / 25 > 0: s.sendall(str(sml_num/25) + '\n') sml_num = sml_num % 25 else: s.sendall('0\n') data = s.recv(256) print data if sml_num / 10 > 0: s.sendall(str(sml_num/10) + '\n') sml_num = sml_num % 10 else: s.sendall('0\n') data = s.recv(256) print data if sml_num / 5 > 0: s.sendall(str(sml_num/5) + '\n') sml_num = sml_num % 5 else: s.sendall('0\n') data = s.recv(256) print data if sml_num / 1 > 0: s.sendall(str(sml_num/1) + '\n') sml_num = sml_num % 1 else: s.sendall('0\n') print "Now,",i, " wait...\n" data = s.recv(9) print data
flag{started-from-the-bottom-now-my-whole-team-fucking-here}
まとめ
Misc 25のCoinslotを解いたのが9/19の早朝5時半頃。
このあと、なぜかあと1日あると思い込んでいて、明日頑張ろうと思い寝てしまった。
起きたら11時半でCTF終わってるし、9時からバイトあったのに思いっきり遅刻したし、散々だった。。。
でも、今回のCTFは割と楽しかった。
pwnが弱すぎるので勉強します・・・
おまけ
Recon 200: Fuzyll
解けなかったが、解けたところまでメモ。
問題文で与えられた、http://fuzyll.com/files/csaw2016/startにアクセスしてみる。
すると、次のような文章。
色盲の種類について調べてみて、いくつか試したところ、「deuteranomaly」で正解。
http://fuzyll.com/files/csaw2016/deuteranomaly
にアクセスしてみたら、赤ではないいちごの画像が表示された。保存しようとしたところなぜか拡張子がtxt。
とりあえず保存して、先頭4バイト辺りのバイナリを見てみるもやっぱりpngなので拡張子をpngに変えて、開く。
プロパティとか見てみると、
こんな感じで次のhintが見つかる。
とりあえず、Fuzyllさんについて調べる。
どうやら過去のCSAW CTFでも出されている問題らしく、彼のプロフィールも簡単に見つけることができた。
https://ctf.csaw.io/static/archives/2013/judges/index.html
そこにはCTFにどのチームで出場していたか、などが記されていた。さらに、DEF CON finalに出場したチームなどを
CTFtime.org / All about CTF (Capture The Flag)
あたりで調べて絞っていった。
するとDEF CON 19(2011)にて、Fuzyllが所属していたHates Ironyが3位に入賞していた。(すごい)
よって、ctf timeに載っていたDEF CON 19の問題をかたっぱしから試していく。
すると、「tomato」で正解。
http://fuzyll.com/files/csaw2016/tomato
にアクセスしたところ、文字化けした文章が表示された。
で持ってきて、nkfで調べると「CP932」というやつらしい。
いろいろ調べて、utf-8に直すために
とかしてみるも無理。
ここで諦めた。
他の人のwriteupを読ませて頂きます・・・。