1001001

73。CTFのWrite-upや技術的な備忘録を書きとめたいです。

今更Trend Micro CTF 2016のWrite-upを書く(Analysis - defensive 100)

遅ればせながら,Trend Micro CTF 2016で解いた問題のwrite-upを書いてみます.

手を付けた問題

手を付けた問題は3つです.

  • Analysis - defensive 100
  • Forensic 100
  • Scada 100

どれも100点問題です...

その内フラグ獲得までいけたのは,Analysis-defensive 100のみでした.ですので,この問題についてwrite-upを書いてみようと思います.

Analysis - defensive 100

問題文

Decode me!

file5.enc(渡される問題ファイル)

アプローチ

TMCTFでは問題ファイルが暗号化されて渡されるので,以下のコマンドで復号します.

$ openssl enc -d -aes-256-cbc -k xUiKT4GX6QyZQ23xYtBA -in files5.enc -out files5.zip
$ unzip file5.zip

すると,decodeme_decodeme.php というphpファイルが出てきます.

難読化解除

中身を見ると,難読化されたphpコードが出てきます.とりあえずそのままで読み取れる部分を読むと,eval(gzinflate(base64_decode($x)))という部分があります.$xが難読化されたphpコードで,base64_decode -> gzinflate で難読化を解除していることが分かります.つまりこれを実行してやれば良いです.evalprintに書き換えて,実際にphpを動かすのが良いと思います.(なお私は,本番中は何故かツールでデコードしました -> eval gzinflate base64_decode PHP Decoder

整形&画像データデコード

難読化を解除すると,以下のようなphpファイルになります.見にくかったのと,長すぎて載せにくかったのでちょっと見やすくしてます.本来はもっとぐちゃってます.

また,見やすくする前はbase64エンコードされたデータがありましたが,それは画像データでした.このphpファイルには7つの画像データが含まれていました.base64のままだと見づらいので画像データに戻してあります.

 

コードを読む

実はこの問題,あまりちゃんとコードを読まなくても答えは分かります.そのため,ここでは解読に関係ありそうな部分だけを説明します.

コードを読む:github

どんな挙動をするphpなのか確認するためにコードを読みます.

まず気になるのが,2行目の

// reference: https://github.com/b374k/b374k/blob/master/LICENSE.md

の部分なので,github のサイトを見に行きます.どうやら,sshなどを使わず,webベースで認証を行いシェルが使えるようにするためのライブラリのようです.認証には初期パスワードが設定されています.これは運用時に自由に変更します.認証では,sha1(md5(password))の値を保持しておいて,ユーザの入力したpasswordが正しいか比較する,という処理を行うようです.

(ちなみに,これが一般的なライブラリなのかTMCTF用に作られたのかという議論があったのですが,old versionやラストコミットを見る限りそれは無いだろうとなりました.参照されているのがLICENSE.mdだし.)

コードを読む:一つ目の画面

肝心の部分を読んでいきます.htmlコードも含まれているので,単体で動作しそうです.私はxamppで動作させて確認しました.どうやら大きく分けて二つの画面が存在するようです.一つ目は認証の画面,二つ目は認証後成功後の画面です.まずは一つ目の認証画面について見てみます.

38行目で呼び出しているchk_passwordで認証処理を行っているようです.本体は5行目からですね.ここで行っていることを簡単に説明すると,

  • passwordを入力して認証を行う
  • sha1(md5(password))の値が$GLOBALS['key']に入っている文字列($globと同じ)
  • $postがフォームから送信した値で,その値のmd5sha1ハッシュが$globと等しければ認証成功
  • 認証後はcookieに$globの値を入れる.cookieに$globの値がセットされていれば認証を飛ばせる

というような感じです.このパスワードのハッシュは使いそうです.

コードを読む:二つ目の画面

二つ目の画面は認証が完了した後の画面なのですが,色んなコマンドを実行できる以外にできることが無いです.デフォルトのシェルコマンド以外に任意のコマンドを作ったりもできるみたいです.どこかでこのサービスが動いているならいざ知らず,ローカルの環境しかないので特に意味が無いと思うのでスルーします.

画像のexifに気付く

実は,phpに含まれていた7つの画像にはexifが含まれていました.exif (Exchangeable image file format) とは,画像ファイルに付加できる情報です.その画像の撮影日時や撮影機種名などを付加できます.exifを見る方法としては,exifを確認するツールを利用する方法があります.

ただ,ツールによって情報が見えたり見えなかったりすることが稀にあるようです .そのため,一つのexif確認ツールで7枚の画像を確認したが,exifは確認できなかったということがあったようです.しかし,base64コードの時点で,lock.pngだけ他の画像のbase64とは異なる部分があり,こいつにだけはexif情報が含まれているのではないかという予想が付きます (それとstrings コマンドで見るとRaw profile type exifと出てきます).

lock.pngexif情報を見るために,私はexiftoolというものを用いました(exeにパスを通してます).こちらでlock.pngexifを確認すると,撮影機器の部分に付加情報が確認できます.

$ exiftool lock.png
ExifTool Version Number         : 10.24
File Name                       : lock.png
Directory                       : .
File Size                       : 2.3 kB
File Modification Date/Time     : 2016:07:30 06:27:16+01:00
File Access Date/Time           : 2016:07:30 06:27:16+01:00
File Creation Date/Time         : 2016:07:30 06:27:16+01:00
File Permissions                : rw-rw-rw-
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 71
Image Height                    : 114
Bit Depth                       : 8
Color Type                      : Palette
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Adam7 Interlace
Exif Byte Order                 : Little-endian (Intel, II)
Make                            : /.*/e
Camera Model Name               : eval(base64_decode("ZWNobyAnZmxhZyBpcyBzaGExKHBhc3N3b3JkKSc7"));
SRGB Rendering                  : Perceptual
Gamma                           : 2.2
Palette                         : (Binary data 585 bytes, use -b option to extract)
Transparency                    : (Binary data 195 bytes, use -b option to extract)
Pixels Per Unit X               : 5905
Pixels Per Unit Y               : 5905
Pixel Units                     : meters
Warning                         : [minor] Trailer data after PNG IEND chunk
Image Size                      : 71x114
Megapixels                      : 0.008

Camera Model Nameの部分ですね.eval(base64_decode("ZWNobyAnZmxhZyBpcyBzaGExKHBhc3N3b3JkKSc7")); とあるので,デコードしてみます.

$ python
Python 2.7.10 (default, Jun  1 2015, 18:17:45)
[GCC 4.9.2] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "ZWNobyAnZmxhZyBpcyBzaGExKHBhc3N3b3JkKSc7".decode("base64")
"echo 'flag is sha1(password)';"
>>>

これを見ると,パスワードのsha1がフラグだぜって書いてあります.このパスワードというのがおそらく,先ほどのphpの認証処理の部分に使われるパスワードのことです.そしてそのパスワードそのものについては分かっておらず,sha1(md5(password))の値のみ分かっています.

パスワード総当たり

フラグを求めるにはpasswordを知る必要があります.しかしsha1md5はハッシュ(一方向性関数)であるため,逆算は不可能です.不可能なので,Brute Force(総当たり)します.

 

pythonでコードを書いても現実的な時間で求められます.結果的にはパスワードは4文字でした .

(気付いていませんでしたがログイン画面にて,enter **** のようにパスワードがアスタリスク4文字で表されていますので,文字数は分かっていたようです.)

$ python solver.py
rep 1 is nothing.
rep 2 is nothing.
rep 3 is nothing.
h4ck

 

パスワードはh4ckです.このsha1の値がフラグです.

>>> import hashlib
>>> hashlib.sha1("h4ck").hexdigest()
'e17e98788d6b4ac922b2df100ef9398ae0f229ad'
>>>

 

TMCTF{e17e98788d6b4ac922b2df100ef9398ae0f229ad}

まとめ

手順は以下になります.

  • 難読化解除
  • $globの値はsha1(md5(password))であることに気付く
  • phpファイル内の画像データのexifからsha1(password)であることに気付く
  • passwordをBrute forceで求める

未だにとりあえず総当たりするという癖がつかず,解くまでに時間がかかりました.低得点の問題に時間をかけないよう心掛けたいです.

余談

For100はメールからzip抽出までは行きましたが,Fall caesarの意味に気づきませんでした.頭が固いです(辞書試せば良かったという説もある...).

Scada100は最近答えを知って先輩と一緒に何とも言えない気持ちになりました.