picoctf2017で解いたWeb問の話

はじめに

どうも、EAnbai『Web』担当(自称)です。もうしばらく前の話になってしまいましたが、picoctf2017にいつも通りEAnbaiで参加していました。Web問題メインで取り組んだので、解くことができたWeb問をメモしておきます。

解いたWeb問たち

What Is Web (level1, 20pt)

問題のサイトを見ると、良い感じのサイトが出てきます。ソースコードを見ると下の方にコメントで

1
<!-- The first part of the flag (there are 3 parts) is 72b28b258d2 -->

と書かれているので、他のファイル(cssやjs)も探索すると同じようにパーツが出てきてそれらをつなげるとフラグになります。

My First SQL (level1, 50pt)

ログインフォームが出てくるのでインジェクションするとフラグがもらえます。

TW_GR_E1_ART(level2, 100pt)

Oh, sweet, they made a spinoff game to Toaster Wars! That last room has a lot of flags in it though. I wonder which is the right one...? Check it out here.

こんな感じの問題文で、リンクを叩くとゲームが始まりました(図1)。クライアント側からは特に有用な情報を見つけられず、問題に付されているヒントを見ると

I think this game is running on a Node.js server. If it's configured poorly, you may be able to access the server's source.

とあり、なるほどpackage.jsonとかが見えるのか、というあたりを付けることができました。実際に「/package.json」としてみるとサーバー側のソースコードがserverディレクトリで管理されており、起動時はserv.jsが実行されていることがわかりました。

1
2
3
4
"scripts": {
"prestart": "node server/init.js",
"start": "node server/serv.js"
}

ここからはサーバー側のソースコードを読む作業で、serv.jsから辿っていくと複数のソースコードが見えました。
ところでこのゲームは1F~4Fのフロア構成になっており、4Fに行くと沢山の旗がキャラクターが取得・使用可能なアイテムとして置いてあります。問題文でも「正しいフラグはどれ?」と聞いているので、それがわかりそうな情報を探すという方針で間違いなさそうです。

さて、ソースコードを少し読むと、このゲームの実装にはsocket.ioが使われており、いくつかあるメッセージの中に「revealFlag」と言うものを見つけることができました。そしてどうやら何らかのアクションを起こせばこのイベントが発生して、PICO_CTF_FLAGという名前の環境変数に書き込まれているフラグを読めるようだ、ということがわかりました。

1
outcome.flag = process.env["PICO_CTF_FLAG"];

さらにソースコードを見ていくとステージ情報が定義されたファイルが含まれており、その中でも特に例の4Fの旗アイテムを使用すると全アイテムロストもしくはrevealFlag effectが発生する、つまり正しいフラグを取得・使用すれば正解を見ることができ、間違えればその機会が潰えるということがわかりました。使用されたフラグアイテムが正しいフラグであるかはrevealFlagメッセージを処理するコード部

1
if (entity.items[action.item].effects[i].check == 64)

で確認していることがわかるので、あとは普通にゲームを進めて正しいフラグを取得し、使用するとフラグを見ることができます。

図1.Toaster Wars

Biscuit (level3, 75pt)

開くと「Access Denied」と言われるのでソースコードを見るとコメントでcookies.sqliteというファイルにクッキーを隠してるから安全だぜと言った趣旨の文章が書かれていて、/private/cookies.sqliteにアクセスするとダウンロードすることができます。この中身をsqliteを使って見てみるとそれっぽい文字列が入っているのが見えるのでこれを問題サイトのIDというクッキーを書き換えて設定、再アクセスするとフラグがもらえます。

A Happy Union (level3, 110pt)

開くとLogin/Registerボタンが出てきて、流石にlevel1の問題のようには行きません。とりあえずhogeみたいな適当なアカウントをRegisterしてLoginすると何かポストできるページが出てきます(図2)。

図2.ログイン後のページ

問題文からSQLのunionを使ったSQLiであることが推察でき、色々試しているうちにユーザー登録時にSQL命令を混入させることでログイン後のページに情報を表示させることができそう、ということがわかりました。ということでまとめると

  1. SQL(union selectでadminのpassを取得するようなものを作る)を混入させたユーザー名でユーザーを新規登録する
  2. 1で作成したユーザーでログインする
  3. ログイン後画面にadminのpass(フラグ)が表示されて優勝

という手順で解けます。
しかしまだどのtableにユーザー情報が格納されているかわからないので、unionを使って情報収集します。ここで問題文のI like lite sql:)という部分からデータベースにsqliteが採用されていることが窺えるので、sqlite_masterテーブルから情報を抜き出します(図3)。これでusersテーブルと言うものが存在することがわかりました(ユーザー登録時のSQLによってエラー情報を表示(サーバー側でエラーを吐くようになっている)させ、ポスト部分のtable名「posts」をリークし、そこからusersテーブルの存在をエスパーする方法もある)。あとは前述の手順に従ってusersテーブルから情報を抜き出すSQLを混入したユーザーでログインすればフラグが貰えそうです。

図3.usersテーブルから情報を抜き出せば良さそう

詰まったところとしてはユーザー名部分でSQLを組み立てる時にシングルクォーテーションを意識しなければならない点、カラム数を合わせる必要がある点でした。前者はコメントでは回避できなかったので、pass取得のための命令の後に

1
where user='admin

を付け加えて回避しました。後者は最終的にnullをselectのリストに加えることで回避しました。この手順を踏むと無事フラグを取得することができました(図3)。unionベースSQLiの内容把握にあたり、このあたりなどを参考にしました。

図4.フラグがもらえた

おわりに

気合いを入れて解いたのはTW_GR_E1_ARTとHappy Unionで、それ以外の問題は割りとサクっといきました(というかTWはゲームを進めてフロア4まで行くのが普通に楽しかったので遊んでしまった)。特にHappy Unionが解けた時はEAnbai『Web』担当を自称しておきながら今まであまりちゃんとWeb問を解けなかったので、嬉しかったです。ただLevel3の残り2問と4のWeb問などまだまだ解けていないものがあるので、精進します。

あとpwnもそろそろちゃんとできるようになりたいので、チーム内でpwnable.krの問題を解いたりしていますがpicoctfの問題も難易度が良い感じなのでwriteupを適宜見ながらやっていきたいです。

以上です。