2014年4月18日から20日にかけて、第2回 NotSoSecure CTFが開催されました。前回に続き、その謎解きの模様をお届けします。
皆さん、こんにちは。NotSoSecure CTFのWrite Up以外では表に出てこないと評判の、ラックの山崎です。
2014年4月18日から20日にかけて、第2回NotSoSecure CTFがオンラインで開催されました。私も挑戦しましたので、正答に至るまでの道筋を解説したいと思います(なお、2013年10月に行われた前回のCTFの解説については、下記をご覧ください)。
NotSoSecure CTF参戦記〜問題を解く側から見えてきたもの
http://www.atmarkit.co.jp/ait/articles/1311/28/news005.html
第2回 NotSoSecure CTFは、「2nd SQLiLab CTF」とも呼ばれ、SQLiLabチームが主催したオンラインCTFです。2014年4月18日(金)の英国時間9時(日本時間の17時)から開始され、4月20日(日)の15時(日本時間23時)+αまで開催されました。「+α」というのは、開催中にサイトがDDoS攻撃を受けてダウンするトラブルがあったため、若干のロスタイムが提供されたからです。
サイトがダウンするというトラブルにもかかわらず、全世界から3000人を超える事前登録があり、7000近いIPアドレスから挑戦が行われたという盛況ぶりでした。
最終的に2問のフラグを全て取ることができた参加者は32名いて、私はそのうちの15番目という結果になりました。リーダーボードがhttp://ctf.notsosecure.com/leaderboard/にて公開されています。
競技の開始は、メールとTwitterで案内されました。案内文には「ブルートフォース攻撃やDoS攻撃が禁止されていること」「CTF競技はログイン画面の突破の時点から開始されているため、ユーザーID/パスワードを主催者側に聞かないでほしいこと」などの注意事項が書かれていました。
早速、競技用URLにアクセスしてみます。
表示されたのは、ユーザーIDとパスワードの入力が求められる、単純なログイン画面でした。
まずは、ユーザーIDとパスワードの入力欄、そして次に「loginkeeping」という隠されていたパラメーターに対してSQLインジェクションの存在確認を行いましたが、脆弱性は見つかりません。
ここで前回の教訓を踏まえて、SQLインジェクション以外の脆弱性の存在も念頭に置いて、JavaScriptやスタイルシートの記述内容を確認しました。すると、スタイルシートの中に、登録画面の存在を示唆する「register」という文字列を発見しました。また、HTMLページの下方部分に、一見しただけでは意味の分からない「<!--H4sIAAAAAAAAAAsyTs80LTEu0ssoyc0BACMzGYUNAAAA -->」というコメントも見つけました。
このコメントが次への道筋を示していると見て、解読を開始しました。
解読には、「Burp Suite」というセキュリティツールを使用しました。このツールは、Webサイトとの通信内容を表示したり変更したりできる「Proxy」ツールを中心に、複数のさまざまな有用なツールが含まれています。今回はその中の「Decoder」ツールを活用しました。
Decoderツールでは、コメント内の文字列を1つ目のテキストボックスに入力して、「Decode as」の部分をいろいろと変更することで文字列を変換できます。まず、「Base64」形式でデコードし、続けて「Gzip」形式でデコードすることで、文字列を解読すると、「R3gi5t3r.html」という文字列が得られました。
「R3gi5t3r」は「Register」の意味。このファイルにアクセスすることで、隠されていたユーザー登録画面を表示することができました。
早速ユーザー登録画面で「keigo」というユーザーを登録して、ログインを試してみました。
すると……ログインは成功したものの、左にあるように「You are not Admin!」という画面が表示されます。どうやら、一般ユーザーではなく、管理者権限でのログインが求められているようです。
ここからはユーザー登録画面で、「admin」と解釈されるであろうさまざまなパターンのユーザーを登録しました。例えば、
admin → 「User Already Exists!」
Admin → 「User Already Exists!」
……
という具合です。他に「admin%00」「adm'+'in」「adm'||'in」なども試しましたが、そのままの文字列のユーザーが登録されるだけで、「admin」の登録には至りませんでした。
次に、INSERT文に挿入されることを想定して、「admin','mail@example.jp','password',true)--」に類する文字列を、カラムの順番や個数を変えながら送りました。しかし、そもそもSQLインジェクションが存在する兆候が得られず、ダメ元で送った文字列も全て失敗となりました。
そのように、ユーザー登録をして、そのユーザーでログインをして……という作業を繰り返しているうちに、ふと、ユーザー登録は成功するもののログインできないケースがあることに気付きました。
その条件を注意深く確かめてみると、「20文字を超える場合」に発生することが分かりました。
その後、運営側がヒントを出してくれて気付いたのですが、これは「Column SQL Truncation」の脆弱性が存在する兆候でした。この脆弱性は、実際に2008年にWordPressのログイン画面に存在していたものと同種のものです。会員登録画面で「admin」や「admin 」(最後にスペースが入っています)については既に存在するユーザーであると判断される状況において、カラムの最大文字数(今回の場合は20文字)を超える文字列を送ることで、その判断を回避して登録が行われてしまう問題です。
今回、私は「admin」と判断されるユーザーとして、「admin keigo」(間に15個の半角スペースが入っています)というユーザーを登録しました。これは、データベースに存在するユーザーではないため登録処理に進みますが、カラムの最大文字数を超えているので、結果として後半部分が切られて、「admin 」(最後に15個のスペースが入っています)というユーザーが登録されます。ログイン時のSELECT文では文字列の後半のスペースは削除されて比較が行われるため、私が指定したパスワードで「admin」ユーザーとしてログインできるようになりました。
こうして「admin」としてログインしたところ、1つ目のフラグが表示されました。
そして、2つ目のフラグの奪取に取り掛かったのですが、どこから攻めればいいのか迷ってしまいました。前回のCTFでは、1つ目のクリア後に「2nd flag is in file secret.txt」のように次への道筋が示されたのですが、今回は何も指示がなかったためです。
新しく出現したのは右のような「FEEDBACK」フォームへのリンクでしたが、これがターゲットなのか、はたまた実際にフィードバックを運営側に送るためのフォームなのか確信が持てませんでした。とりあえず、無難なメッセージを送信して、しばらく待って何らかのアクションが返ってこないか確認することにしました。
その後、しばらく待ってもメールの返信などがなかったため、「FEEDBACK」フォームに対して脆弱性の確認リクエストを、それも次第に大胆に送り始めることとなりました。
まず、「名前」「メールアドレス」「内容」の各パラメーターや、「submit」パラメーター、「Host:ヘッダー」「Origin:ヘッダー」「User-Agent:ヘッダー」「Referer:ヘッダー」などにSQLインジェクションが存在していないかを確認しましたが、見つけることができませんでした。
次に、メール送信部分でOSコマンドインジェクションが存在しているかもしれないと思い、「メールアドレス」部分を中心に確認しましたが、こちらも空振り。
その後も、送信内容がテキストファイルやCSVファイル、DBファイルなどに出力されるのではないかと推測してファイルの存在確認を行ったり、管理者がメッセージを閲覧する画面でクロスサイトスクリプティング(XSS)が発生することを期待してスクリプト文字列を送信したりしましたが、どれも効果を出すことができませんでした。
ただし、いろいろと試しているうちに、「css/」「images/」というディレクトリを表示すると、1つ目のフラグを得た環境と違って、ファイルの一覧が表示されることを確認しました。さらに、ここにはバックアップと思われるファイルが存在することや、どこからもリンクされていない画像ファイルがあることなどが分かりました。
そこで、画像の内部に何か隠されていないか、同じ命名規則のバックアップファイルでPHPソースコードが閲覧できないかを確認しているうちに、この日は時間切れとなりました。
Copyright © ITmedia, Inc. All Rights Reserved.