CTFの過去問を解いてOllyDbgの使い方を覚える。
はじめに
デバッガの使い方が全然わからなかったので、Hack.lu CTF 2013のRoboAuthという問題で練習しました。
この問題は、パスワードを探すというとてもシンプル内容なので練習にはちょうどいいかなと思います。
問題の概要
問題文は以下の通り
RoboAuth (Category: Reversing) Author(s): cutz
Oh boy, those crazy robots can't catch a break! Now they're even stealing our
liquid gold from one of our beer tents! And on top of that they lock it behind
some authentication system. Quick! Access it before they consume all of our
precious beverage!Download: https://ctf.fluxfingers.net/static/downloads/roboauth/RoboAuth.exe
Flag: password1_password2
問題ファイルのリンクが切れていた場合は下記のアーカイブにある問題データを利用できる。
http://shell-storm.org/repo/CTF/Hacklu-2013/Reversing/RoboAuth-150/
手順
exeファイルなのでDOSから実行してどんな挙動をするのか確かめる。
コンソールからパスワードを入力するタイプの非常にシンプルなプログラムだと分かる。
次にOllyDbgを起動。(右クリックして管理者として実行)
RoboAuth.exeをOllyDbgで開く。
- OllyDbgの画面構成
左上:逆アセンブルコード 左下:メモリダンプデータ 右上:レジスタ(CPUが内部にもつ記憶領域。変数みたいなもん) 右下:現在のスタック(一時的にデータを格納するメモリ領域。スタック内のデータはESPレジスタに格納される。)
- よく使うショートカット
F2:ブレークポイント設定/解除 F7:詳細ステップ実行(ステップイン:関数内部まで入り実行) F8:ステップ実行(ステップオーバー:関数呼び出しを1命令として実行) F9:デバッギー実行 Ctrl+F2:再スタート F12:デバッギー実行一時停止 Ctrl+F9:リターンまで実行 Alt+F9:ユーザーコードまで実行(システムDLL内から抜ける際等に使用) Space:アセンブル Ctrl+E:バイナリデータの編集 Ctrl+G:アドレスを指定して移動 ESC:詳細自動ステップ実行の停止
同時にIDA Proも起動しRoboAuth.exeを開く。
Strings windowのYou passed level1!というところをダブルクリック
DATA XREF: sub_401627+54Eというところをダブルクリック(DATA XREFは外部参照という意味)
一度目の認証でputsやscanfがcallされているアドレス値がわかったので次はOllyDbgで最初にputsが使われているアドレス値に移動する。
具体的にはCtrl+Gしてアドレスのところで00401B3Eを指定する。
F2キーで00401B3Eをブレークポイントに設定しF9でデバッギー実行する。
その後、F8でステップ実行していきscanfがcallされているところでパスワードに"AAAAAAAAAA"と入力してみる。
さらにF8でステップ実行を進めていくとEAXレジスタに"r0b0RUlez!"という文字列が格納されているのが見つかる。
その後もF8でステップ実行を続けるとプログラムは終了する。
ここで"r0b0RUlez!"という文字列が正しいパスワードかどうかDOSから実行し確かめるてみる。
一つ目のパスワードは"r0b0RUlez!"であると確認できた。
またIDAに戻り、二度目の認証が行われているアドレス値を探す。
scanf関数を目印にして探した。
もう一度OllyDbgに戻りCtrl+F2で再スタートする。
このときOllyDbgの本体があるフォルダ内に"filename.bak"や"filename.udd"のようなファイルがあれば削除する。(今回はRoboAuth.bakやRoboAuth.uddなどがあれば削除する。)
さっきと同じようにCtrl+Gで00401B3Eに移動しF2でブレークポイントを設定。
もう1回Ctrl+Gしてアドレスは004015B2を指定して移動。F2で004015B2にもブレークポイントを設定。
その後004015B2以降の逆アセンブルコードを読んでいくと0040161F番地にCC INT3というコードがある。
これはint 3hを使ったアンチデバッグらしい。(詳しいことは知らない)
これを無視させるためにOllyDbgのオプション>>解析詳細設定>>例外項目へと移動し、
以下の(プログラムに渡す)例外項目を無視する:
というところのINT3ブレークにチェックを入れる。
少し戻って004015B2番地(2度目の認証の部分)の逆アセンブルコードをもう一度読んでみる。
004015B2 E8 D1640000 CALL <JMP.&msvcrt.scanf> 004015B7 A1 98AD4000 MOV EAX,DWORD PTR DS:[40AD98] 004015BC 894424 04 MOV DWORD PTR SS:[ESP+4],EAX 004015C0 8D45 E0 LEA EAX,DWORD PTR SS:[EBP-20] 004015C3 890424 MOV DWORD PTR SS:[ESP],EAX 004015C6 E8 7CFFFFFF CALL RoboAuth.00401547 004015CB 85C0 TEST EAX,EAX 004015CD 75 0D JNZ SHORT RoboAuth.004015DC 004015CF A1 A4AD4000 MOV EAX,DWORD PTR DS:[40ADA4] 004015D4 890424 MOV DWORD PTR SS:[ESP],EAX 004015D7 E8 B4640000 CALL <JMP.&msvcrt.puts>
004015C6番地のCALL RoboAuth.00401547の部分が怪しいので、Ctrl+Gで00401547へ移動しブレークポイントに設定。
00401547 55 PUSH EBP 00401548 89E5 MOV EBP,ESP 0040154A EB 22 JMP SHORT RoboAuth.0040156E 0040154C 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 0040154F 0FB610 MOVZX EDX,BYTE PTR DS:[EAX] 00401552 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] 00401555 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] 00401558 83F0 02 XOR EAX,2 0040155B 38C2 CMP DL,AL 0040155D 74 07 JE SHORT RoboAuth.00401566 0040155F B8 01000000 MOV EAX,1 00401564 EB 17 JMP SHORT RoboAuth.0040157D 00401566 8345 08 01 ADD DWORD PTR SS:[EBP+8],1 0040156A 8345 0C 01 ADD DWORD PTR SS:[EBP+C],1 0040156E 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] 00401571 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] 00401574 3C 02 CMP AL,2 00401576 ^75 D4 JNZ SHORT RoboAuth.0040154C 00401578 B8 00000000 MOV EAX,0 0040157D 5D POP EBP 0040157E C3 RETN
F9でデバッギー実行し、一度目の認証で正しいパスワードを入力しもう一度F9。
二度目の認証で"AAAAAAAAAA"と入力し、そこからはサブルーチン内の処理も追いたいのでF7で詳細ステップ実行していく。
00401555 0FB600 MOVZX EAX,BYTE PTR DS:[EAX]
でのEAXレジスタが002BFDCC番地の値となっているので、そこを右クリックしダンプ画面へというところをクリックする。
すると左下のダンプデータのところに"u1nnf2lg"という文字列が見つかった。
00401558 83F0 02 XOR EAX,2 0040155B 38C2 CMP DL,AL
はEAXレジスタの値(u1nnf2lg)を2とXORした値とDLの値を比べている。
したがってパスワードはu1nnf2lgのそれぞれの文字について2とXORして出てきた文字列になる。
s = 'u1nnf2lg' Flag = '' for i in s: Flag += chr(ord(i)^2) print Flag
print "".join(chr(ord(i)^2) for i in 'u1nnf2lg')
#include <stdio.h> int main() { char *s = "u1nnf2lg"; while (*s) { printf("%c", *s^2); s++; } printf("\n"); return 0; }
- 実行結果
w3lld0ne
確かめる。
Flagは"r0b0RUlez_w3lld0ne"であることが分った。
終わりに
アセンブリ言語もデバッガの使い方もまだまだ全然分からないのでこれから勉強していきたいです。
参考にした書籍

- 作者: 愛甲健二
- 出版社/メーカー: 技術評論社
- 発売日: 2013/08/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (12件) を見る

いまどきのアセンブラプログラミング―Windowsプログラム解析・開発の独習
- 作者: 橋本和明,山本洋介山,leye,イシサキ
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2003/10
- メディア: 単行本
- クリック: 12回
- この商品を含むブログ (19件) を見る
参考にしたサイト
- http://blog.intm.org/2013/10/roboauth-write-up-reversing-150-hacklu.html
- http://blog.pentest.kz/blog/2013/11/11/hack-dot-lu-ctf-2013-roboauth/
- Nops"R"Us - Home to Doraemon.Sk8ers: hack.lu 2013 CTF :: Reversing: RoboAuth (150 points)
- X86アセンブラ/x86アーキテクチャ - Wikibooks
- OllyDbg Q&A (Digital Travesia)
- Capture the Flag