第2回tkbctf 問題「The Net」「Police」を作ってみた
EDIT
コード全体を公開しました。ご参考までに。 https://github.com/chris-x86-64/tkbctf2-Police
くりすです。
第2回tkbctfにて、問題「The Net」と、「Police」を担当しました。
- The Net
-
トップ画面右下に「π」の文字がうっすら浮かんでいたのですが、この文字を出現させるCSSは
bootstrap.css
中に定義されていました。そのCSS中に、コメントの形式でフラグの文字列を設置しておりました。通信データを逐一フィルタしていれば、何も知らなくても発見できていたでしょう。
- Police
- 吉村くん(@_yyu_)が原案のJavaScriptを制作し、わたしがその検査器をPythonで書きました。解き方は彼のブログに載せられる予定になっている[要出典]ので、わたしは裏方のタネ明かしをしたいと思います。問題自体の解法は、彼のブログに記事が上がるのを待ちましょう。用語や関数名なども彼のブログで解説されることを願いたい。
問題「Police」に挑戦してくださったみなさんはきっとお気づきかと思いますが、「validation.py
」というPython CGIが、XSS成功時にそのフォームの内容をPOSTで受け取っていました。
これは、バックエンドでユーザが入力したJavaScriptを評価するために、PyV8を用いていたからです。
では、validation.py
の内容(理解を簡単にするために一部簡単にしてあります)を見てみましょう。
#!/usr/bin/env python import PyV8 import cgi, cgitb # check JavaScript class Global(PyV8.JSClass): def isYoshimuraYuu(self): print "That was great!! The key is ... \"hatsuneMiku39\"" def notQuiteDone(self): print "You need to set the `proceedable` to true!" def evalJavaScript(post_data): try: ctxt = PyV8.JSContext(Global()) ctxt.enter() ctxt.eval(open('../public/check.js').read()) ctxt.eval(open('../private/foo.js').read()) ctxt.eval('checkSum(' + repr(post_data) + ')') ctxt.leave() except Exception, e: print "Perhaps syntax error? Try again!" # end JavaScript # CGI form = cgi.FieldStorage() print 'Content-type: text/html' print evalJavaScript(form.getvalue('solution')) # end CGI
ざっくらばんにいうと、皆さんのブラウザにも現れたcheck.js
とfoo.js
(※サーバ上で動かすための多少の改変あり)をロードし、そのJavaScriptに対して、checkSum(ユーザの入力)
を評価するということをしています。
その結果isYoshimuraYuu()
が実行されれば勝ちというわけです。isYoshimuraYuu()
はPythonで定義されていますが、PyV8を使うことでevalしたJavaScriptから呼び出せるので、こういうことができるのです。
こんな変な名前なのは、参加者のブラウザにロードされる諸JavaScriptと名前の衝突を起こさないようにするためです。
つまるところ、foo.js
で定義されたgiveMeTheFlag()
がproceedable == true
の状態のときに実行されると、PythonのisYoshimuraYuu()
が実行される仕組みになっているわけです。
こんな裏方を作っていました。結局、半数の正解者が別解で解いたため、何度か手動検査をやるはめになったのですが。
軽くメモ
PythonでJavaScriptを評価するのにPyV8
を使おうとするも、インストールに苦労した。
- easy_install
- 503を吐いてたので使えなかった
- pip
- setup.pyがうんこだったので使えなかった
- setup.py
-
setup.pyの
extra_link_args = []
をextra_link_args = ['-lrt']
に置き換えることで、 C++のclock_gettime()
を呼び出せない問題を解決。リンキングのオプションがタコだった。
ZIPファイルに対するKnown Plaintext Attackについて
あやふみ.zipとかいうアレなものができた
— あやふみ (@ayafmy) September 19, 2013
あ、ayafmy.zipはパス付きzipふぁいるデス
— あやふみ (@ayafmy) September 20, 2013
@ayafmy コスプレあやふみ画像集かとおもった
— 大黒PAでバッテリあがらせたマヌケbot (@x86_64) September 20, 2013
@x86_64 だいたいあってないこともない
— あやふみ (@ayafmy) September 20, 2013
あやふみ女史(※男の娘)のコスプレ画像zipがパスワード付きでうpされたらしいです。
さらに、
どうでも良いですが、ayafmy.zipにはこの画像がはいってます http://t.co/iqsuIbHkLA
— あやふみ (@ayafmy) September 20, 2013
ここでピンときた。
"Known Plaintext Attack" だ。
- Known Plaintext Attack
- パスワードを設定して暗号化したPKZIPファイルの中身をある程度知っていると、それをもとにストリームキーを推測してアーカイブ全体を解読できるというもの。
そして、
まあヒントというかそういう事やる人にはつかえる情報かと
— あやふみ (@ayafmy) September 20, 2013
具体的にはふぁぼってきてるくりすさんに飛ばしたつもりです
— あやふみ (@ayafmy) September 20, 2013
名指しで腕を試されている。
やるしかないね。
やってみました。
やっぱ記事書くのめんどくさい。やめた。なお解読はできた模様。