2013年2月7日木曜日

CTF Challenge Japan(Final) Write Ups - Service Attack 200

以下が問題文で、実際には特定のサーバに設けられているtest.cgiから解答を得てくることになる。
[タイトル]
Email のログを盗み出せ!

[問題]
サーバ管理者のA君は、どこからでもSMTPのログを確認したかったため、一見なんの変哲もないプログラムtest.cgiにEmailのログを出力する仕組みを実装した。たまたまtest.cgiを手に入れたB君はあなたにそのプログラムの解析を依頼してきた。test.cgiを解析し、サーバにあるEmailのログを得よ。
ただし、test.cgiはバイナリ形式で提供されていて、リバースエンジニアリングを行うことが可能な状態だった。
まずは test.cgiをバイナリエディタで開いてみる。


Linux用のELFバイナリのようだ。

とりあえず動かしてみる。


"Hello World!"と表示するプログラムのようだ。問題文には「Emailのログを出力するしくみを実装」とあるので、ディスアセンブラを起動して、文字列抽出結果の相互参照などから、関連しそうな箇所を調査してみる。



すると、Emailログの読み出しをしている関数が特定できた。
次に、この関数を参照している箇所を特定すると、2ヶ所存在した。ひとつは、環境変数REMOTE_ADDRを確認する関数。もう一つはQUERY_STRINGを確認するものだった。


通常、REMOTE_ADDRは、アクセス元のIPアドレスを得るための環境変数として使われており、このプログラムにおいても同様であった。しかも、ローカルのループバックアドレスからのアクセスということは、このCGIプログラムの設置されているサーバに何らかの方法で侵入した上で、このプログラムにアクセスすることが、電子メールアドレスの中身を見る方法となる。

でも、この方法を使えるチャンスはなさそうだ。

そこで、QUERY_STRINGを確認するコードを確認する。password.txtを開いて、その中の文字列を読み出してパラメータとして入力した文字列とのマッチングを行う、いわばパスワード認証を行うようだ。


パスワードを辞書攻撃したり、総当たりするのもいいが、それでは時間が足りなくなってしまう。
この関数に渡される、パラメータの受け渡し部分を確認してみる。


ここに脆弱性があるようだ。このプログラムはパラメータとして16文字までのデータを処理するようにコーディングされている。ESPレジスタの値を起点にして、パラメータとして受け取った文字列をローカル変数として確保した領域にコピーするが、その際の計算ミスで1バイトだけ、スタックのリターンアドレスを書き換えることができる。


上書きできるリターンアドレスは1バイトだけなので、このプログラムの場合0x08048600~0x080486ffの範囲でジャンプ先を指定できることになる。


Emailのログデータを読み出す関数のエントリポイントは0x08048651なので、リターンアドレスを1バイトだけ書き換える値を0x51にしてあれば、ここにジャンプできることになり、パスワード認証を迂回できることになる。


どうやらこれが解答のようだ。

2013年2月4日月曜日

CTF Challenge Japan(Final) Write Ups - Binary 100

ファイルをバイナリエディタで開くと、ELFファイルでFreeBSD用っぽいので環境を用意してとりあえず走らせます。


パスワードを入力する必要があるようです。

stringsコマンドで文字列を抽出してみます。

「nijimasu」という文字列が、他の文字列と比較してやけに具体的なので、これをパスワードに使ってみます。

 「パスワードは12文字だよ」という返事が返ってきました。なので、とりあえず「nijimasu」に「1234」を付け加えて12文字として入力してどんな反応があるかみてみます。

コアダンプしてしまったようなので、gdbを起動してcoreファイルの中身を確認します。すると、EIPレジスタが0x34333231であることがわかります。この値はASCIIキャラクタにして「4321」、リトルエンディアンにすると「1234」になります。つまり、この4バイトの値でリターンアドレスを書き換えた結果、Segmentation faultでプログラムが終了したことになります。

runmeを動作させるだけだとここで手詰まりになってくるので、ディスアセンブラを起動してrunmeを解析します。



すると「OK! Answer is 」という文字列が使われているpublic_answer_wordというシンボル名の関数が存在することがわかります。この関数は存在するだけでプログラム本体からは参照されていない奇妙な存在であることが、ディスアセンブラの相互参照の出力状況などからわかります。この関数の開始アドレスは0x69727574です。




 0x69727574は、ASCIIでリトルエンディアンに格納すると「turi」になります。これを先ほどのパスワード入力の際、最後の4バイトの値として使うことでこの関数の先頭にEIPレジスタの値をセットすることが可能になります。


どうやらこれが回答のようです。