NotSoSecure CTF参戦記〜問題を解く側から見えてきたものWrite Up(1/3 ページ)

イギリス時間の2013年10月25日16時から27日21時まで、オンラインで開催された「NotSoSecure CTF」に挑戦した筆者によるWrite Upです。

» 2013年12月06日 18時00分 公開

この記事は、ラックの「NotSoSecure CTF参戦記」を、一部修正、加筆して転載したものです。


 「NotSoSecure CTF」は、NotSoSecure Labsがイギリス時間の2013年10月25日16時から27日21時まで開催したCTFで、競技はオンラインで行われました。

 公式の発表によると、約1500人が登録し、25を超える国からの挑戦があり、最終的に2問とも正解をした参加者が25人いたとのことです。http://ctf.notsosecure.com/leaderboard/にてスコアボードが公開されています。

 今回、私もこのCTFに挑戦しました。ここでは、各問の正解に至った道筋について解説をしたいと思います。

情報収集と経験値アップを目的に

 私は、ラックという情報セキュリティサービスを提供する企業で、Webアプリケーションのセキュリティ診断や、Webアプリケーションファイアウォールのシグネチャ開発などの業務を担当しています。

 国内最大のセキュリティコンテスト「SECCON 2013」では、Webアプリケーションの問題を中心に、CTF出題者側として運営に参加しています。また、優秀な若手セキュリティ人材の発掘を目指す「セキュリティ・キャンプ2013」にも、CTFオーガナイザーとして参加しました。

 そんな私ですが、実は自身がCTFに参加した経験はほとんどありません。「CTFチャレンジジャパン」や「Stripe CTF」など数えるほどです。それゆえに「他のCTFとは違う、日本ならではの問題を出題できるのではないか」と自負していたのですが、今回は情報収集のために「NotSoSecure CTF」に参加してみることとしました。

登録から挑戦開始まで

 CTFの開催案内ページに名前とメールアドレスを登録しておくと、折り返し案内が届く仕組みとなっていました。届いたメールには、ルールとして「他の参加者に迷惑となるようなブルートフォース攻撃を禁止する」などの案内や、全問正解後の連絡先、そして競技サイトのURLが記載されていました。

 早速URLにアクセスして、競技開始です。

 私は普段、Webアプリケーションのセキュリティ診断を業務としていますので、本当であれば、使い慣れた自社製のツールを活用したいところなのですが、今回は土日の開催で、かつオンラインCTFのため自宅からの参戦となり、それらが使えません。このため、フリーのProxyツールである「Fiddler」と己の腕一本で立ち向かうこととなりました。

 さて、URLにアクセスしたところ、以下のログインページが表示されました。

 何しろ、「SQLiLab CTF」という別名も付いていましたので、まずはSQLインジェクションだろうと目星をつけ、UsernameやPasswordの入力欄その他に、「'」などの文字列を送信して、脆弱性が存在する個所の特定を試みました。ところが、どう見てもSQLインジェクションの反応は出てきませんでした。

 これは困った……ということで、SQLインジェクション以外の手法にも視野を広げて挑戦を続けました。

行き詰まりを感じ始めた時、運営からヒントが

 いろいろな手法を試し尽くして行き詰まり、ダメ元でスタイルシートなどをのぞき始めた頃、運営からヒントがツイートされていることに気付きました。

 そ、そういうことか……! ログイン画面にパラメータを送った後、error.phpに転送されることには気付いていたのですが、そのメッセージ部分はすっかり見逃していました。CTF慣れしていないせいだ、と言ってしまえばそうですし、宝探しゲーム的なものではなく、もっと実践的なものだと勝手に思い込んでいたために、見逃してしまっていたようです。

 あらためてレスポンスを眺めてみると、何やら怪しい「7365637265745f72656769737465722e68746d6c」というメッセージが表示されていました。16進数の羅列と見てデコードしてみたところ、「secret_register.html」という文字列が得られました。早速これを用いてアクセスすると、秘密の(?)ユーザー登録画面が表示されました!

ログイン後の画面は見られたものの……

 しめしめ、とユーザー登録画面でユーザーを登録して、その会員でログインをしてみたところ、ようやくログイン後のページが表示されました。しかし……

「You are not Admin!」

 このアカウントではダメなようです。試しに、ユーザー名を「Admin」として登録を試みてみましたが、「User Already Exist」と怒られてしまいました。

 とりあえず、これはやはりSQLインジェクションの出番ではないか? と思い、ユーザー登録画面に対して、Adminを意味する文字列を作る「Ad'||'min」「Ad'+'min」をはじめとして、その他いろいろとSQLインジェクションの攻撃文字列を雨あられと降らせました(大げさ)が、芳しい成果が得られません。

 その時、ふと、“このユーザー登録画面でSQLインジェクションに対する反応がないということは、ユーザー登録自体は成功している。その成功したユーザーでログインをしたらどうなるのだろう?”と思いつきました。実際、ユーザー登録からログインまでの流れを試してみると、ログイン成功後の画面の内容に変わりはありませんでしたが、その際に発行されるCookieの値が変化していることに気付きました。

 私が登録したユーザーでログインすると、

Set-Cookie: session_id=a2VpZ29AZXhhbXBsZS5qcA%3D%3D
(base64でデコードすると、「keigo@example.jp」)

というCookieが発行されますが、SQL文として正しくない文字列をユーザー名に入れた場合、

Set-Cookie: session_id=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT

という反応となりました。

 また、全件一致するような文字列(「' or 'a'='a」に類するもの)を送信した場合は、

Set-Cookie: session_id=YWRtaW5Ac3FsaWxhYnMuY29t
(base64でデコードすると、「admin@sqlilabs.com」)

というように、他人のメールアドレス(恐らく「Admin」の)が表示されました。

 この応答から、この部分にいわゆる「セカンドオーダーSQLインジェクション」の問題が存在していることが分かりました。

そうと分かれば、あとは地道に……

 あとは地道にデータを取得していきます。詳しい手法は省きますが、SQLインジェクションの常道に沿って、まず「order by」を使ってカラム数を特定して、次に「union select」を使って、テーブル内の情報を1つずつ抜き出して表示させました。

 この手法で、システムテーブルからテーブルの一覧を抜き出したところ、「users」といういかにもなテーブルが存在していることが分かり、次に、「users」テーブルに、「id」「name」「password」「email」というカラムが存在していることが分かりました。

 そして、最後に、「union select password,1 from users where name='admin'」を実行したところ

Set-Cookie: session_id=c3FsaWxhYlJvY0tzISE%3D
(base64でデコードすると、「sqlilabRocKs!!」)

と、ユーザー「admin」のパスワードが「sqlilabRocKs!!」であることが分かりました。これを用いてログインしてみたところ……無事に1つ目の問題の正解が表示されました!

       1|2|3 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。