CODEGATE 2014 予選に参加した。

今回は仕事の都合などもあり、10時間ちょっとの参加。
例年に比べて、問題がやや難しめに感じたけど、
揃えられてる問題はどれも面白い問題ばかり。
CODEGATEの問題って毎年毎年ほんっと面白いの揃えてくるなーって思う。


WeirdShark

pcapファイルっぽいけど、破損していて開けない。
foremost等でファイルを抽出してみても、破損していて見れない。
WireSharkで開こうとすると、こんなメッセージが表示される。


cap_lenが4270407998になってるせいで、うまく開けないらしい。
4270407998の16進 FE89413E でファイル内を検索すると、
先頭付近でヒットする。packet_len が62らしいので、試しに
62 (0x3E)に書き換えてみると、開けるようになる。
File -> Export -> objects で全てのファイルを抽出してやる。
PDFファイルの中にフラッグが書かれている。GET!


FLAG = FORENSICS_WITH_HAXORS


dodoCrackme

実行すると、パスワードの入力を求められる。
アセンブルして見ると、やたら同じ命令が大量に並んでいる。
gdbでステップ実行してみると、値を incb / decb することで
実装していることが分かる。
例えば、Aなら65回incbして、次の文字がEなら、さらに4回incbする感じ。


ユーザの入力を受け取るsyscallからしばらく後を見ると、
おおまかに2ブロックに分かれてsyscallが分布している。
おそらく、成功時と失敗時の出力だと判断できる。
そこで、判定前の適当な個所にブレークポイントを設置。
試しに、x/1000s $rsi とかしてみると、アスキー文字が
散らばっていることが分かる。それを全部繋げてみると、フラッグになる。


[dolphin@iruca]$ ./crackme_d079a0af0b01789c01d5755c885da4f6
root@localhost's password: H4PPY_C0DEGaTE_2014_CU_1N_K0RE4
SUCCESS

Web Proxy

名前の通り、入力したURLの内容を取得して表示するらしい。
しかし、どうやらヘッダと本文含めて10行しか表示してくれないようだ。
また、一部の語句はフィルタリングされており、使えない。(php等)
フィルタリングについては、URLエンコードしてやれば使えた。
HTMLソースには、admin/index.php というコメントが見つかる。


admin/index.php にアクセスしても403になるが、
このProxyを通すと403にならないため、Proxyを通してadmin/index.php
見る問題だと推察がつく。そこで、localhost/***/admin/ などで試す。
ただし、ヘッダ8行の本文2行しか表示されず、肝心の本文が見れない。


どうしても分からず、気分転換に外出しているときに、iPhoneから
リモートでいろいろと試していると、改行が含まれるリクエストの挙動が
おかしいことに気付く。末尾に%0D%0Aをつけると、ヘッダが省略され、
本文が10行表示される。admin/index.phpで試すと、Access Deniedとなり、
100から順番に1行ずつカウントダウンしているHTMLが表示される。
どうやら10行程度では全く足りないらしい。


ここで、%0Aだけでも同様の現象が発生することから、リクエストヘッダを
インジェクションできることに気付く。であれば、Rangeヘッダを使って
必要部分を切り取ればと思いついて試してみると、ビンゴ。
こんな具合で全文見ていった。


localhost/188f6594f694a3ca082f7530b5efc58dedf81b8d/admin/index.%2570hp%20HTTP/1.0%0ARange:%20bytes=372-1000%0A%0A


admin/index.php にアクセスしたときの中身には、やはり100行分の
カウントダウンがあった。末尾に、

という文字があったので、さらに Host: hackme を付け足してみた。
すると、ちゃんとレスポンスが返ってきたので、同様にRangeで見ていく。
今度はちゃんと hello admin となっていて、フラッグをゲットできた。
localhost/188f6594f694a3ca082f7530b5efc58dedf81b8d/admin/index.%2570hp%20HTTP/1.0%0AHost:%20hackme%0ARange:%20bytes=76-1000%0A%0A


Password is WH0_IS_SnUS_bI1G_F4N

120

SQLi問題。
まず、index.php のソースが見れるので、見てみる。
https://gist.github.com/dolphin333/6854177eaf09e816f872
どうやら、password にSQLインジェクションを仕掛ける問題らしい。
フィルタリングが甘いので、インジェクション自体は簡単に成功する。

select * from rms_120_pw where (ip='$_SERVER[REMOTE_ADDR]') and (password='' or %CHECK_STATEMENT% or password='')

上記の %CHECK_STATEMENT% の個所を使ってブラインドインジェクションを行う。
auth.php というファイルもあり、こちらはソースが見れない。
いろいろ試したところ、SQLi もできないようになっている雰囲気。
おそらく、index.php で SQLi して、パスワードを取得した後、auth.php で認証することで
フラッグが取れるのだろうと推測。


ただし、パスワードが120回ページを開くたびにリセットされてしまう。
パスワード長は30文字。ブラインドインジェクションでは、
120回以内にパスワードを入手することは難しい。そこで、セッションをうまく使う。
120回という回数は、セッション依存である。しかし、パスワードはIP依存である。
よって、セッションを複数作っておき、それぞれを使いまわしながら
攻撃すれば、パスワードがリセットされることなく入手できる。


今回はちゃんとスクリプト書いた。
https://gist.github.com/dolphin333/3aa43aa59dd0e2a68981


[dolphin@iruca]$ curl -b cookie3.txt -d password="ateseobiaitsxxpexofoewopoiulue" http://58.229.183.24/5a520b6b783866fd93f9dcdaf753af08/auth.php
Congrats! the key is DontHeartMeBaby*$#@!

感想

Doraemonはcanaryに気付けなかった。。
バイナリ関係の知識が圧倒的に足りないなぁ、と。
もう少しパケットを自在に操りたい。