ログイン
編集不可のページディスカッション情報添付ファイル
"CTF/Writeup/tkbctf4/Cheer of CPU"の差分

MMA
1と2のリビジョン間の差分
2014-11-03 21:45:31時点のリビジョン1
サイズ: 31
編集者: ytoku
コメント:
2014-11-04 02:14:20時点のリビジョン2
サイズ: 2779
編集者: nomeaning
コメント:
削除された箇所はこのように表示されます。 追加された箇所はこのように表示されます。
行 2: 行 2:
Swiftで書かれたバイナリであり、最初はMacOS上でも動作しなかった。
エラーメッセージを見るとXCode6がないとライブラリ不足で動作しないようなので、インストールしたがやはり起動せず。
エラーメッセージで検索すると、Yosemiteなら動くという話があったので、Yosemiteにアップグレードしたら動くようになった。

次に逆アセンブルを試みた。Mach-Oなのでmetasmやobjdump(on linux)で出来るかと思いきや、どちらも失敗し、最終的にMac上のgobjdumpで逆アセンブルすることが出来た。関数名が`__TF Ss7printlnU__FQ_T_$stub`のように分かりにくいため、以下のプログラムを用いてdemangleを行なった。
{{{#!highlight ruby
# need root
require 'shellwords'
hash = {}
puts $<.read.gsub(/<(.+?)>/){
  f = $1
  next '<%s>' % hash[f] if hash[f]
  if f.end_with?('stub')
    '<' + `xcrun swift-demangle #{Shellwords.escape(f[0..-6])}`.split('-->', 2)[1].strip + '>'
  else
    '<%s>' % f
  end
}
}}}

逆アセンブルを読むと、引数が2個より少なかった時の処理でメッセージを表示した後、exitを呼び出していることから、パスワードを間違えた時もexit(1)を呼び出してると推測した。
`lldb`を用いてexitにブレークポイントを仕掛けて実行することにした。

まず、引数に`a`を与えて実行した所、0x10001f73bでexitが呼び出された。直前の分岐にブレークポイントを貼って、rax, rsiの値の変化を確かめて、引数の長さが6かどうか判定している処理であることを特定した。
{{{
   10001f6ec: 48 39 f0 cmp rax,rsi
   10001f6ef: 74 4f je 10001f740 <__mh_execute_header+0x1f740>
(なんらかの処理)
   10001f739: 89 c7 mov edi,eax
   10001f73b: e8 60 25 00 00 call 100021ca0 <_exit>
}}}

次に、引数に`abcdef`を与えて実行したところ、0x10001fbc0でexitが呼び出された。直前の分岐にブレークポイントを仕掛けた所、引数の文字と別の文字を比較している処理だということが分かったので、引数を1文字ずつ確定させていくことが出来た。
{{{
   10001fb71: 45 38 c8 cmp r8b,r9b
   10001fb74: 74 4f je 10001fbc5 <__mh_execute_header+0x1fbc5>
(なんらかの処理)
   10001fbc0: e8 db 20 00 00 call 100021ca0 <_exit> # exit(-1)
}}}

出力結果をSHA256して、フラグを取得した。
{{{
$ ruby -rdigest/sha2 -e 'puts Digest::SHA256.hexdigest(`./cheer kogasa`.strip).downcase'
}}}

Cheer of CPU (binary 300)

Swiftで書かれたバイナリであり、最初はMacOS上でも動作しなかった。 エラーメッセージを見るとXCode6がないとライブラリ不足で動作しないようなので、インストールしたがやはり起動せず。 エラーメッセージで検索すると、Yosemiteなら動くという話があったので、Yosemiteにアップグレードしたら動くようになった。

次に逆アセンブルを試みた。Mach-Oなのでmetasmやobjdump(on linux)で出来るかと思いきや、どちらも失敗し、最終的にMac上のgobjdumpで逆アセンブルすることが出来た。関数名が__TF      Ss7printlnU__FQ_T_$stubのように分かりにくいため、以下のプログラムを用いてdemangleを行なった。

   1 # need root
   2 require 'shellwords'
   3 hash = {}
   4 puts $<.read.gsub(/<(.+?)>/){
   5   f = $1
   6   next '<%s>' % hash[f] if hash[f]
   7   if f.end_with?('stub')
   8     '<' + `xcrun swift-demangle #{Shellwords.escape(f[0..-6])}`.split('-->', 2)[1].strip + '>'
   9   else
  10     '<%s>' % f
  11   end
  12 }

逆アセンブルを読むと、引数が2個より少なかった時の処理でメッセージを表示した後、exitを呼び出していることから、パスワードを間違えた時もexit(1)を呼び出してると推測した。 lldbを用いてexitにブレークポイントを仕掛けて実行することにした。

まず、引数にaを与えて実行した所、0x10001f73bでexitが呼び出された。直前の分岐にブレークポイントを貼って、rax, rsiの値の変化を確かめて、引数の長さが6かどうか判定している処理であることを特定した。

   10001f6ec:   48 39 f0                cmp    rax,rsi
   10001f6ef:   74 4f                   je     10001f740 <__mh_execute_header+0x1f740>
(なんらかの処理)
   10001f739:   89 c7                   mov    edi,eax
   10001f73b:   e8 60 25 00 00          call   100021ca0 <_exit> 

次に、引数にabcdefを与えて実行したところ、0x10001fbc0でexitが呼び出された。直前の分岐にブレークポイントを仕掛けた所、引数の文字と別の文字を比較している処理だということが分かったので、引数を1文字ずつ確定させていくことが出来た。

   10001fb71:   45 38 c8                cmp    r8b,r9b 
   10001fb74:   74 4f                   je     10001fbc5 <__mh_execute_header+0x1fbc5>
(なんらかの処理)
   10001fbc0:   e8 db 20 00 00          call   100021ca0 <_exit> # exit(-1)

出力結果をSHA256して、フラグを取得した。

$ ruby -rdigest/sha2 -e 'puts Digest::SHA256.hexdigest(`./cheer kogasa`.strip).downcase'

CTF/Writeup/tkbctf4/Cheer of CPU (最終更新日時 2014-11-04 02:14:20 更新者 nomeaning)