読者です 読者をやめる 読者になる 読者になる

かたはらいたし。

個人的な技術的な活動をまとめていきたい。

ksnctf #11 Riddle

さぁついにやってきましたバイナリ解析。
こればっかりは普通に生活しててやったことあるって人は稀なんじゃないでしょうか・・・。

ksnctf - 11 Riddle

Problem

http://ksnctf.sweetduet.info/q/11/Riddle.exe

Riddle.exeという実行ファイルがおいてありました。

Analyze

とりあえずfileコマンドで中身を確認してみる。

$ file Riddle.exe
Riddle.exe: PE32 executable for MS Windows (GUI) Intel 80386 32-bit

Windows 32bit用のexeファイルであることがわかりました。

とりあえず起動してみる

Windowsマシンで実行してみるとクイズが出てきます。

Which creature in the morning goes on four feet, at noon on two, and in the evening upon three?

うーん?朝は4本足で昼は2本、夕方は3本と・・・。
ぐぐってみると有名ななぞなぞだということがわかりました。(参考:なぞなぞ - Wikipedia
答えは人間、つまりHumanです。

2問目。

What is the largest island in the world?

世界で一番大きな島、これはもうGreenlandですね。

3問目。

Answer to the Ultimate Question of Life, The Universe, and Everything.

全く意味が分からなかったのでぐぐってみると"生命、宇宙、そして万物についての究極の疑問の答え"だそうです。(参考:生命、宇宙、そして万物についての究極の疑問の答え - Wikipedia
なんかよくわからないですが、42が答えみたいです。詳しくは参考を見てください。

4問目。

What is the flag?

・・・はい。分かるわけ無いですよね。

ここまででわかったことは、問題文とその答え(4問目を除く)の他に正解したときは"Correct!"、間違えた時は"Wrong..."が表示されることです。

アセンブル

今回はIDA Proを使って逆アセンブルをしてみたいと思います。
String Windowの中に、上記で述べた問題文や出力されるダイアログの文字列があったので呼び出し元を参照してみます。
そこを起点として周りのコードを読んで見ると、(多分)以下の手順で実行されていることがわかりました。

  1. 入力された文字列の長さを取得する
  2. 取得した文字列長が解答の長さと同じかどうかを判定し、異なっていた場合"Wrong..."を出力して1.に戻る
  3. 入力した文字列を取得する
  4. 入力文字列と予め用意された数列とのXORを計算する
  5. XORの結果を予め用意された解答(XORの計算結果)と一致するかを判定し、異なっていた場合"Wrong..."を出力して1.に戻る
  6. "Correct!"を表示して次の問題へ

ここでポイントになるのが、入力文字列と予め用意された数列のXORを計算しているところです。
XORは逆計算が可能であるため、答えを計算することが可能です。
つまり、入力文字列 XOR 予め用意された数列 = 予め用意された解答のXOR値となるので、
予め用意された数列 XOR 予め用意された解答のXOR値 = 解答となります。

Answer

例えば1問目の"Human"が答えになる問題だと、
予め用意された数列 = 0xF9 0xB3 0x5A 0x4A 0x18であり、
予め用意された解答のXOR値 = 0xB1 0xC6 0x37 0x2B 0x76となるため、
上記2つのXOR値は0x48 0x75 0x6D 0x61 0x6Eとなり、これを文字に変換してやると"Human"となります。

2問目以降も同様にこの方法で解答を計算することによってFLAGをゲットできます。

感想とか

はじめてのバイナリ解析で中々戸惑うことも多かった(特にツールの使い方)けど、この問題を通じて少しコツをつかめた気がする。
特にデバッグをしながらやることが大切だなって思った。