InterKosenCTF Writeup
はじめに
こんにちは。cute_otterです。
2019/01/18 21:00~2019/01/20 21:00(JST)にかけて開催されたInterKosenCTFに、二人チーム「1n73rn5h1p」で参加しました。
結果は250ptsで34位(点を取った70チーム中)でした。
出題された問題はこちらで公開されているようなので、後で解き直したいと思います。
[Forensics 50pts] attack log
問題文
Someone seems to have tried breaking through our authentication. Find out if he or she made it to the end.
添付ファイル
attack_log.tar.gz
解法
解凍したファイルのファイル形式を確認します。
file attack_log.pcapng attack_log.pcapng: pcap-ng capture file - version 1.0
ファイル形式がpcap-ng capture file - version 1.0
であることが分かりました。
この結果に加えて、問題名や問題文から、attack_log.pcapngには、何者かが認証を突破しようとした際のログが含まれているのだろうと思ったので、Wiresharkを用いてattack_log.pcapngを調査します。
表示されたパケットをザーッと見ていく*1と、レスポンスとして、401 Unauthorized
が何度も現れており、パケットの詳細を見るとBasic認証に失敗していました。
認証に成功した際には、レスポンスとして、200 OK
が返るので、これが存在するか確認するため、以下のように表示フィルタにhttp.response.code == 200
を入力し、フィルタをかけます。
1つだけパケットが表示されるので、このパケットを含むセッションの内容を表示する(右クリック > 追跡 > HTTPストリーム)と、レスポンスにThe flag is KOSENCTF{<the password for the basic auth>}
とあるので、Basic認証のパスワードがフラグの中身になることが分かります。
また、リクエストにAuthorizationヘッダがあり、そこにBasic認証のユーザ名とパスワードの組み合わせ(a29zZW46YlJ1dDNGMHJjM1cwcmszRA==
)が含まれています。
Basic認証のユーザ名とパスワードの組み合わせはBase64でエンコードされているので、以下のコマンドでデコードします。
echo a29zZW46YlJ1dDNGMHJjM1cwcmszRA== | base64 -d kosen:bRut3F0rc3W0rk3D
Basic認証の認証情報はユーザ名:パスワード
となっているので、フラグはKOSENCTF{bRut3F0rc3W0rk3D}
となります。
[Forensics 200pts] conversation
問題文
We seized a smartphone which one of the suspects had used. Find out the conversation they had.
添付ファイル
android_8.1_x86_oreo.tar.gz
解法
解凍したファイルのファイル形式を確認します。
file android_8.1_x86_oreo.tar.gz android_8.1_x86_oreo.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (needs journal recovery) (extents) (large files)
ファイル形式がLinux rev 1.0 ext4 filesystem data
であることが分かりました。
ファイル形式がext4なので、FTK Imagerを用いてandroid_8.1_x86_oreo.imgの内部を調査します。
mkdir /mnt/conversation/
mount android_8.1_x86_oreo.img /mnt/conversation/
中身は以下のようになっているので、rootディレクトリ以下をエクスポートします。
エクスポートしたrootディレクトリ直下で、find -name '*kosen*'
やfind -name '*ctf*'
でフラグに含まれそうな文字列を検索すると、root/app/以下にあるcom.kosenctf.kosencrypto-DQEyRCoLoNfHq4_wVFgoPA==/
ディレクトリがヒットしました。
このディレクトリ内に何かしらのアプリケーションのapkファイル(base.apk)があるので、次の手順で.apkファイルのリバースエンジニアリングをしていきます。
まず、以下のコマンドで、.apkファイルを解凍します。
unzip base.apk
次に、dex2jarで、base.apkを展開した際に作成されたclasses.dexを.jarファイルに変換します。
d2j-dex2jar classes.dex
最後に、JD-GUIで、上記のコマンドを実行した後に作成されたclasses-dex2jar.jarを展開し、.classファイルのソースコードを確認します。
表示された.classファイルを一つずつ見ていくと、MainActivity.classが怪しそうなので、ソースコードを読んでいきます。
内容は文字列をAESで暗号化し、暗号文をBase64でエンコードするといったものでした。
また、ソースコード内に、以下のようなAESの暗号利用モード、初期化ベクトル、鍵が含まれているので、暗号文を見つけることができれば復号できそうです。
private String algorithm = "AES/CBC/PKCS5Padding"; private String iv = "str0ng-s3cr3t-1v"; private String key = "p4ssw0rd-t0-hid3";
次に、問題名と問題文からSMSのメッセージが暗号化されているのかもと思い、SMSのメッセージを探します。
rootディレクトリ直下で、find -name '*mmssms*'
*2で検索すると、./data/com.google.android.gms/databases/icing_mmssms.db
というファイルがヒットします。
ファイル形式を確認するとSQLite3のデータベースであることが分かるので、このデータベースの内部を調査します。
sqlite3 ./data/com.google.android.gms/databases/icing_mmssms.db
SQLite version 3.26.0 2018-12-12 11:57:35 Enter ".help" for usage hints. sqlite> .tables android_metadata mmssms_tag incarnation_appdatasearch sms_seqno_table_appdatasearch mmssms version_appdatasearch sqlite> select * from mmssms; 1|sms|content://sms/1|1|3|00123456789|1545883762451||We need to discuss the plan now.|1545883762|text_plain||0 2|sms|content://sms/2|2|3|00123456789|1545883801463||Make our conversation secret by using our app, ok?|1545883801|text_plain||0 3|sms|content://sms/3|1|3|00123456789|1545883817029||Sure.|1545883817|text_plain||0 4|sms|content://sms/4|1|3|00123456789|1545883914853||pwgh/nXO1tMf6TXUd99mhNH01GcCqVDxDBy1+sDf37s4nnYRuHkS+AOoiH3DmKU3I+ZYHEsllcwlnm6FWjAb5g==|1545883914|text_plain||0 5|sms|content://sms/5|2|3|00123456789|1545883949925||GVuIBG/lSSUNW6jZqR20hw==|1545883949|text_plain||0 6|sms|content://sms/6|1|4|00314159265|1545884118222||Did you forget your umbrella?|1545884118|text_plain||0 7|sms|content://sms/7|2|4|00314159265|1545884165219||No. I have one.|1545884165|text_plain||0 8|sms|content://sms/8|1|4|00314159265|1545884217077||It's raining out there.|1545884217|text_plain||0 9|sms|content://sms/9|2|4|00314159265|1545884248299||yup|1545884248|text_plain||0 10|sms|content://sms/10|1|4|00314159265|1545884348428||Take good care of your health. It's heavy.|1545884348|text_plain||0 11|sms|content://sms/11|2|4|00314159265|1545884371524||Thanks, mom.|1545884371|text_plain||0 sqlite> .exit
データベースの2行目に"アプリケーションを使って会話を秘密にしよう"と提案する文章があります。
また、4行目にはアプリケーションによって暗号化されたと思われる暗号文があります。
この暗号文を復号するため、先ほどリバースエンジニアリングしたアプリケーションの情報(暗号利用モード、初期化ベクトル、鍵)を利用して、以下のようなスクリプトを作ります。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import base64 from Crypto.Cipher import AES def decrypt(string) : # Decode the base64 encoded string base64_decoded_string = base64.b64decode(string) # Decrypt the AES encrypted string algorithm = AES.MODE_CBC iv = 'str0ng-s3cr3t-1v' key = 'p4ssw0rd-t0-hid3' cipher = AES.new(key, algorithm, iv) plaintext = cipher.decrypt(base64_decoded_string).decode('utf-8') return plaintext if __name__ == '__main__' : sms_msg = 'pwgh/nXO1tMf6TXUd99mhNH01GcCqVDxDBy1+sDf37s4nnYRuHkS+AOoiH3DmKU3I+ZYHEsllcwlnm6FWjAb5g==' plaintext = decrypt(sms_msg) print(plaintext)
暗号文を復号するとフラグが表示されました。
フラグはKOSENCTF{7h3_4r7_0f_4ndr01d_f0r3n51c5}
でした。
おわりに
実力不足と時間の都合で、2問しか解けませんでした。
もっと頑張りたいなぁ...
最後に、運営の皆様、お疲れ様でした!!
InterKosenCTFのWriteupは以上です。
*1:パケットをザーッと見ずに、パケットカウンタ(ツールバー > 統計 > HTTP > パケットカウンタ)を見た方が早かったかも。
*2:参考にしたサイト :https://android.stackexchange.com/questions/16915/where-on-the-file-system-are-sms-messages-stored