supereggが送るBeginners CTF 2019[warmup]Ramen(Web)の解説
どうもこんにちは、supereggです。今回がBeginnersCTF2019にWebの問題である「Ramen」の解説をしたいと思います。
まずは問題のサイトにアクセスします。
https://ramen.quals.beginners.seccon.jp/
めちゃめちゃ美味しそうですね。私はラーメンが大好きなので嬉しいです。
まず以下の入力フォームとそのしたの表に注目します
名前を検索できる入力フォームがあり、その下にラーメン屋の店員の名前と一言が書いてあります。
入力フォームがあるので、まずはSQLインジェクションが使えないかチェックみようと思います。
SQLインジェクションとは・・・アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。 また、その攻撃を可能とする脆弱性のことである。(あ(引用:wikipedia)>>https://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3>>
SQLインジェクションが使えるかどうか判断する方法として典型的なものとして「'(シングルクォーテーション)を1つ入力するとエラーメッセージが表示されるというものがあります。
何故判断できるのかを簡単に説明すると入力フォームで入力されてきた値は普通すべて、特殊な意味を持たない文字列として扱うようにしなければなりません。そのため、「'」などのメタキャラクタ(特殊な意味を持つ文字)はエスケープして「'」を特殊な意味を持たない文字列として扱うようにしなければなりません。(PHPの場合は\')もし「'」をエスケープしていなかった場合、入力フォームから入力されてきた値で予期しないSQL文が実行されることになるのです。
それでは実際に入力フォームに「'」を入れてみましょう。
次にSEARCHボタンをクリック」すると・・・
何やらエラー文が出てきました。index.phpの11行目のエラーだそうです。(本来ならリリースの段階では画面にエラー表示はさせないようになっているのが常識なのですがCTFではこのようにエラーが画面に表示するように設定している場合があるそうです。エラーメッセージが画面に表示しない設定の場合は、開発者ツールでHTTPステータスコードを確認すれば内部エラーが起きたかどうか判断できます。(エラーコードは500))
何故エラーになるのかというと、
SLECT * FROM users WHERE name=''';
となり、シングルクォーテーションが1つ余計になり、SQLのシンタックスエラーになり、それがPHP側で表示されます。
これでSQLインジェクションを使えばいいというのがほぼ確定になりました。
次にどのRDBMS(データベースソフトのこと)が使われているのか判別します。
代表的なRDBMSの中には「MySQL」、「PostgreSQL」、「SQLite」があります。
この3つの書式の違いでまずあるのがコメントアウトです。
- MySQL 「#」
- PostgreSQL 「--」
- SQLite 「--」
となります。
この3つなら「#」コメントをつけることが出来たらMySQLだと決めつけることができます。
早速判断するために試してみましょう。
なんとエラーが出ませんでした。MySQLが使われているということが分かりましたね。
エラーが出ない理由は以下のように最後の「'」が#でコメントアウトされているからです
''#'
これにより、好きなSQL文を実行できるようになります。なんと恐ろしい( ゚Д゚)
RDBMSではユーザが定義する領域の他に、そのデータ領域のメタ情報(テーブルやカラムの情報)を保持する領域が作られます。
MySQLの場合はINFORMATION_SCHEMAとして定義されていて、データベースの形態をとっていて、SQL文により中身の情報を取り出すことが可能です。
次の文字列を検索フォームに入力すると、データベース名とカラム名を表示させることができます。
'union select table_name, column_name from information_schema.columns#
入力してSEARCHボタンを押すと、データベースが結合されて、たくさん値が表示されますが、下の方までスクロールすると怪しげなデータベース名とカラム名が表示されています。
これによってflagというテーブルのfragというカラムに求めるものがあると考えられます。これでなかったら逆にヤバイですよね。
上のコードの意味は、information_schemaの中のculumnsテーブルの中のtable_nameとcolumn_nameとう名前(これはinformation_schemaの中で定義されている)のカラムを画面に表示されているデータベースのにunionを使って結合させています。そして内部プログラムは以下のようになっています。
select * from users where name='' union select table_name, column_name from information_schema.columns#'
このように「'」をエスケープしていなければSQL文を実行できます。今回はunionを使っていますが、ANDやORを使って好き勝手にSQLをぶっ放すことが出来ます。例えば
select * from users where name=''OR 1=1#'
ですべて真にしたり・・・
次に
'union select flag,"hello" from flag#
を入力すると("hello"の部分はデータベースを結合させるときにカラムの数合わせにてきとうに入れた値なのでなんでもいいです)
すると・・・