CTF for Beginners のバイナリ問題を見てみた
SECCON2014 オンライン予選もひと段落した。
前回のエントリ書いたときにreversing力が欲しいとか思ったので、手始めにCTF for Beginnersのバイナリを見てみた。
といってもそこまでちゃんと見たわけではないけど…。
問題名とかは忘れてしまったので、バイナリファイル5つをファイル名順に見ていく。
第1回に参加したため、第2回とは問題ファイルが違っているかもしれない。
なお、IDAはデモ版でなくてFree版を使っている。
なぜデモ版を使わないの?
と言われると特に理由はないです。しいて言えばデモ版のメリット/デメリットを評価できてないからかな。
今度調べてみよう。てか有償版ほしい。
ctf_bin1
ctf_bin1 ファイルが与えられるため、fileコマンドで確認する。
[root@kali] # file ctf_bin1 ctf_bin1: Microsoft Word 2007+
Word2007のようなので、ファイル名を"ctf_bin1.docx" にすればWordやWordpadでファイルを開ける。
ctf_bin2
同じように ctf_bin2 ファイルが与えられる。まずはfileコマンドで確認。[root@kali] # file ctf_bin2
ctf_bin2: data
バイナリデータっぽい。
サイズは、
[root@kali] # ls -lh ctf_bin2 -rw-r--r-- 1 root root 11M 6月 28 12:36 ctf_bin2
めっちゃでかいw
ASCIIもめっちゃありそうだなぁ…と思いつつstringsコマンドを打ってみると、
[root@kali] # strings ctf_bin2
Beginning_of_The_History
FLAG出てきました。
ctf_bin3
ctf_bin3. ここからアセンブラを見ていく。[root@kali] # file ctf_bin3 ctf_bin3: PE32 executable (console) Intel 80386, for MS Windows [root@kali] # mv ctf_bin3 ctf_bin3.exe
実行してみると、誰だか聞かれる。
正しい名前を入力する必要がある模様。
C:\>.\ctf_bin3.exe Who are you? > hoge Authorization failed...
stringsコマンドを打ってもFLAGっぽい文字列は見つからないため、IDAで逆アセンブルする。
見る場所は、"Who are you?" あたりの文字列から探せばすぐに見つかった。
"Alt + t" で検索窓を出して "Who are you" で検索すると、.textセクションで文字列をpushしているところが見つかるので、この付近から見ていく。
検索結果
赤四角の直前で al が0かどうか確認し、0の場合に右側の失敗ルートに入っているようだ。
てことは、ここでalが0以外の状態か、ここの命令を書き換えると左側(赤矢印)の成功ルートに入れる。
まずは手っ取り早く命令を書き換えてみることにする。
上図の青四角がアドレスである。"0000048E" の部分を書き換える。jmp命令2バイト分をNOP(何もしない命令:0x90)に書き換えると、条件判断をせずに無条件で左のルートに入ることができる。
IDAがFree版で書き換え機能がないので、他のバイナリエディタを使って書き換えを行った。使ったのはStirling.
これで実行してみるとFLAGが表示されるかと思ったら…
C:\>.\ctf_bin3_edit.exe Who are you? > hoge Authorization succeeded! Here is the secret flag: zD^REnEwLZY (←実際は文字化け)
ですよね。でないとstrings打った時点でFLAG出てますよね。
先ほどのアセンブラの中に、"compareStr" という関数へのCall命令がある(赤四角の少し上の部分)ので、その中を見てみる。
あ、ちなみに画像に出てくる関数名や変数名はリネーム済み。コメントアウトも追記したものです。
ざっくり言うと、
①で入力した文字列長が13かどうか確認して、
②で文字テーブルから取り出した値を0x39とXOR, その後3bit右ローテーションする
処理を繰り返し、入力値の正否を判断する文字列を生成している。
3B 1A 52 B0 4A B0 90 80 AA 3B 80 B8 AA ↓ 02 23 6b 89 73 89 a9 b9 93 02 b9 81 93 ↓ 40 64 6d 31 6e 31 35 37 72 40 37 30 72 ← これと入力値を比較 @ d m 1 n 1 5 7 r @ 7 0 r
というわけで、正しい入力値は "@dm1n157r@70r".
C:\>.\ctf_bin3.exe Who are you? > @dm1n157r@70r Authorization succeeded! Here is the secret flag: ROTATION_AND_XOR
どうせなので、flag生成のところも見てみる。
最初に見ていたところの左側(赤矢印)ルートの真下に、親切にもFlagを生成するロジックがある。
# コメントとかリネームいれているので、これだけでわかると思うけど
簡単に言ってしまうと、
①で文字数をカウントし、
②で、バイナリ内に存在するテーブル値と入力値をXORする
ことでFlagを生成している模様。
このとおりにトレースしてみると、確かにFlagが生成されている。
src = [0x12,0x2b,0x39,0x70,0x3a,0x78,0x7a,0x79,0x2d,0x01,0x79,0x74,0x2d,0x18,0x2b,0x3f] inputstr = '@dm1n157r@70r' l = len(inputstr) dst = '' for i in range(16): dst += str(unichr(ord(inputstr[i%l])^src[i])) print dst
[root@kali] # python ctf_bin3.py
ROTATION_AND_XOR
ctf_bin4
ctf_bin4. これもアセンブラだった。[root@kali] # file ctf_bin4 ctf_bin4: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows [root@kali] # mv ctf_bin4 ctf_bin4.exe
実行してみると、Debugモードでないと動かんと言われる。
IDAで開いてみる。"Ctrl + F12" で関数をチャート化してみた。
memcpyとかも怪しいけど、ぱっと見、startから右下に下がっていったところ(赤四角部分)が怪しいかなと思い、見てみるとビンゴ。
loc_40143Aから左下に下りたところらへんでFlagとかセットしてそう。
OllyDbgで開いてみて、このへんにBreakPointつけたら、Flag出てきました。
Flag{Flag_is_always_with_debugger}
というわけで、詳しく見てみる。
上図のグラフの右側 "loc_40140F" が、文字列を取ってきてdecode処理をしている箇所になる。
ここのループを抜けるとFlag文字列が出来上がっている。その後に、左側のルートに入り、"call dispFirstMSG" 処理をしている。この関数の中身は以下のような処理が走っている。
①で、1msのタイマーをセット
②でFlag文字列をセットして
③でメッセージボックスを表示
でも、1ms後にメッセージボックス消失。
という流れ。つまり、この1msのタイマーを消してやれば、Flagが消滅せずに表示される。
上図の青四角部分は、SetTimerを呼んでいるところのアドレス。"000009EC"のCall命令(000009EFまで)をNOPに書き換えてやる。
また、呼び出し元関数にデバッガモードかどうかの判断ロジックがあるため、ここも改竄してあげる。
"jz loc_40151A" 命令を削除(000007EA~000007EF をNOPに書き換え)。
すると、通常起動でも動作してFlagが表示される。
なお、この後の動作は、最初のFlag生成と同じdecode処理がもう一回走っている(赤枠部分)。
その上で、
①2回decodeが走った後の文字列をメッセージボックスで出し、
②「2回decodeしちゃったテヘペロ (・ω<)」というメッセージボックスをもっかい出している
という流れだった。
というわけで、出てくるMessageBoxは全部で3つ。
という流れのプログラムなのであった。
ctf_bin5
はたまたこれもWindowsの実行ファイル。Windows縛り。[root@kali] # file ctf_bin5 ctf_bin5: PE32 executable (console) Intel 80386, for MS Windows [root@kali] # mv ctf_bin5 ctf_bin5.exe
実行してみると、"INVALID KEY!!" と表示されて終了。
C:\>.\ctf_bin5.exe INVALID KEY!!
IDAで処理フローを確認して、"INVALID KEY!!" 付近を見てみると、またもや条件分岐でFlagを表示させるルートが。
今回は、IDAのデモ版を使って書き換えてみる(深い意味はない。でもStirlingでやるより楽だった)。
書き換えたい"jz"命令を選択した状態で、
[Edit] > [Patch program] > [Change byte...]
"jz"命令(0x74)を "jnz"命令(0x75)に書き換える。もちろんNOP(0x90)にしてもOK.
書き換えたファイルを実行すると、Flagが表示される。
C:\>.\ctf_bin5_flag.exe FLAG IS : "Salamander"
入力値をどうにかしているのか、と思ったらそうでもなさそうなので、ここを書き換えるのが解法なんかなーと思った。
# 単純にreversing力不足で見つけられていないだけかもしれないけど。
せっかくなのでFlag生成部分を見てみる。
この処理をしている関数"sub_401000"が呼ばれた際に、値を格納しまくっている。
1byteなのでchar型と推測したけど、たまにバイナリも入ってるな…。
これが答えの種。
この宣言したやつが、どんどんスタックに積まれていく。
ここで宣言しまくった値を、
①1byteおきに参照して、
②0x20とxor(アルファベットの大文字/小文字逆転)して、
③変数(byte*)に入れる
処理をしているようだ。
つまり、
①で"sALAMANDER"を参照し、
②"Salamander"に変換して、
③答えの変数に入れてる。
以下はOllyDbgで追ってみたもの。文字列がSalamanderの16進数(リトルエンディアン)になってる。
ということで、CTF for Beginners のバイナリファイルをひととおり見てみた。
バイナリ力まだまだ足りないけど、IDAとOllyDBGは少しずつ使えるようになってきた感触がある。
strcpyだったりmemcpyだったり、はたまたprintfだったり、見ていく箇所は慣れてくると決まってくるのかもしれないけど、
実際にアセンブラから脆弱性を探してPwnできるようになるのは、まだ先かもしれない。