[security]SECCON 2013 北海道大会(CTF札幌予選) writeup
SECCON 2013の北海道大会に参加した。初めてのCTFだった。結果は10チーム中4位だった。
問題は全部で10問(図は9問だけどあとで問題14が追加された)。1位のチーム (dodododo) はうち7問を正解しているので、総合力が重要だよなぁ。
得意分野であるWebの「スロットマシーン」は最初に解けたので、WriteUpを書くよ。
スロットマシーン
お題はスロットマシーンで$10,000,000をゲットすること。所持金は$100からスタート。アクセスするとスロットマシーンが表示される。
掛け金 (bet) を入力して start をクリックするとスロットが回り出す。stopをクリックするとスロットが止まる。2つの数字が揃うと掛け金の2倍が返ってくる。3つの数字が揃うと5倍、777だと10倍になる。
最初の関門は掛け金の上限。 bet は最大 $9 までしか入力できない。 maxlength="1" が指定されている。HTMLを書き換えると bet の上限を無制限にできた。
次に攻撃できる箇所を調べる。Firefoxの Web 開発 → ネットワークを有効にしてスロットを回して、リクエストとレスポンスを解析する。
startをクリックした時の通信。Ajaxでリクエストが飛んでいる。レスポンスはJSON。
リクエスト:
http://10.0.2.4/slot.cgi?action=spin&bet=1&hash=2757ed8a5789b272bf36707bcebb30c2ea5a01391ccda4ab67ad4feeeb444eb1
レスポンス:
{ status: OK,
result: 481,
return: 0
}
次にstopをクリックする。スロットの結果は 481 。この時の通信。
リクエスト:
http://10.0.2.4/slot.cgi?action=finish&hash=2757ed8a5789b272bf36707bcebb30c2ea5a01391ccda4ab67ad4feeeb444eb1
レスポンス:
{ amount: 99,
status: OK
}
ここまでで分かったこと。
- startとstopで同じhashが使われている。hashの値は毎回変わる。
- startの時点で結果が決まっている
- stopをクリックすると、持ち金が返ってくる ($1賭けて外れたので持ち金は$99)
start の時点で結果が決まっているので、 start だけ実行して結果が外れだったら stop せずにリロードしてみる。その結果、 stop をクリックしなかったら掛け金が減らないことが分かった。ここまで分かると、攻略法が見えてくる。
- 全額 bet する
- スロットを回して、結果が外れだったらブラウザをリロード (掛け金は減らない)
- 結果が当たりだったら stop をクリックして勝ちを確定
ここで、スクリプト化できるかを試す。でも、課題が2つ。
- リクエストに付与される hash の生成ルールが分からない
- 毎回同じハッシュを付与すると、勝ちが確定しても持ち金が増えない
- ハッシュは JavaScript で生成しているっぽいが、難読化されているのでロジックが分からない
- stopのリクエストをWebブラウザから直接送るとエラー (status: NG) が返ってくる
- HTTPヘッダに
X-Requested-With: XMLHttpRequest
を付与すれば回避できる
- HTTPヘッダに
1つ目の課題(hashの生成ルール)が分からなかったので、スマートな解法を諦めてWebブラウザを使って力技で持ち金を増やすことにした。
- bet の maxlength を書き換えて持ち金全額を賭けられるようにする
- start をクリック。レスポンスを見て勝ち負けを判定。
- 負けだったらWebブラウザをリロードしてなかったことに。
- 勝ちだったらstopボタンをクリックして勝ちを確定。
1/10の確率で勝てて、勝つと持ち金が倍になる。$100からはじめて$10,000,000になるまで、ひたすら手動で繰り返す。ここで自動化できないところで、自分の力の無さを実感するも、結果を重視。途中で1回、ハズレなのにstopボタンをクリックしてしまい持ち金が0になってしまうも、30分くらいで目標金額を達成。flagが表示された。
力技なのが釈然としない(他チームはJavaScriptの難読化を解除して、hashの生成ロジックを解析していた)けど、1問でも解けたからいいや。
出身地チャート (エラーコードを探せ)
最後に追加された問題14。これもWeb問題。アクセスすると、質問が表示される。6問回答すると、「あなたの出身地は○○です」と表示される。こちらもリクエストは2つ。
最初のリクエスト:
http://10.0.2.5/calc.php
ここから設問に答える。
設問終了後のリクエスト:
http://10.0.2.5/calc.php
name=%E3%81%BE%E3%81%A1%E3%82%85&q1=10&q2=no&q3=1&q4=yes&q5=other&q6=yes
普通に遊んでいても、キーワードが返ってこない。問題文が「エラーコードを探せ」。
ふと存在しないファイルを指定してみると、 404 エラーとともにこんなリクエストが返ってきた。
______kfou6s______
これで答えを投入しても、結果は外れ。でも、問題の方向性が分かってきた。他のステータスコードを返せばいいのか。ncコマンドを使って試す。
root@kali:~# nc 10.0.2.5 80
GET /404 HTTP/1.0
HTTP/1.1 404 Not Found
Date: Sat, 30 Nov 2013 13:01:25 GMT
Server: Apache/2.4.7 (Unix) PHP/5.5.6
Content-Length: 18
Connection: close
Content-Type: text/html; charset=iso-8859-1
______kfou6s______
root@kali:~# nc 10.0.2.5 80
PUT / HTTP/1.0
HTTP/1.1 405 Method Not Allowed
Date: Sat, 30 Nov 2013 13:12:34 GMT
Server: Apache/2.4.7 (Unix) PHP/5.5.6
Allow: TRACE
Content-Length: 18
Connection: close
Content-Type: text/html; charset=iso-8859-1
____________f0nor6
404エラーと405エラーで flag の一部が返ってきた。あと1つのエラーを見つけられずにタイムアップ。答え合わせによると、 .htaccess や .htpasswd へリクエストすると 403 とともに flag が返ってきたらしい。
まとめ
はじめてのCTFだったけど、ちょうどいい手応えと、ちょうどいい悔しさだった。セキュリティといっても、マクロの視点(Webシステムのセキュリティ)とミクロの視点(バイナリ解析、ネットワークキャプチャ)の両方が必要。Web以外は手も足もでなかったので、次に向けて幅を広げたい。
運営の皆様、ありがとうございました。