cute_otter’s blog

ハニーポットの観察日記を付けています

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ディレクトリ以下のディレクトリ(一部)
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