###### tags: `InterKosenCTF` `Forensics`
# [InterKosenCTF|Forensics 200]Conversation
「犯罪者のAndroid端末を押収した。何やら通信を行っていたらしい。」みたいな問題分とともに 800Mほどのimgファイルが配られる。これはAndroidのファイルシステムになっている。
## imgファイルの扱い方
`file` コマンドでみるとext-4ファイルシステムなのでどうにかしてマウントしたかったが失敗するので諦めた。
ファイルシステム内のファイルを一覧したり取り出したりするだけなら `The Sleuth Kit`が使える。例えば `fls android.img`として`ls`したり`icat android.img n`としてファイルを取り出したりする。
## apkの抽出
とりあえず気になるのは `app`ディレクトリなのでこちらを見に行く。`fls`を使うと次のようにルートディレクトリが見える。appディレクトリのinode id((ほんまか?))は11なのでappディレクトリ内を見たければ `fls android.img 11`とする。
```
$ fls android_8.1_x86_oreo.img
d/d 11: app
d/d 18: benchmarktest
d/d 29: misc
d/d 35: nativetest
d/d 64: lost+found
d/d 29313: bootchart
```
```
$ fls android_8.1_x86_oreo.img 11
d/d * 433(realloc): vmdl94770257.tmp
d/d 433: com.kosenctf.kosencrypto-DQEyRCoLoNfHq4_wVFgoPA==
```
明らかにそれっぽいファイルがある。この中に `base.apk`というファイルが見つかるので`icat`コマンドで抽出する。
```
$ fls android_8.1_x86_oreo.img 433
r/r 434: base.apk
d/d 435: lib
d/d 436: oat
$ icat android_8.1_x86_oreo.img 434 > base.apk
```
これがapkなので`apktools d base.apk`とするとか`unzip`とかで解凍する。`classes.dex`があるので`dex2jar`で解凍する。dex2jarは[ここ](https://github.com/pxb1988/dex2jar/releases)からnightlyのを手に入れた。
```
$ unzip base.apk -d base
```
今度はjarができるのでこれもまた開く。これは `jar xf`で開ける。`com/kosenctf/kosencrypto`に大量にclassファイルができるが明らかに本体は`MainActivity.class`。classをjavaに変換するのには[CFR](http://www.benf.org/other/cfr/)を使った。
変換されたjavaファイルはこう
```java=
public class MainActivity
extends Activity {
private String algorithm = "AES/CBC/PKCS5Padding";
private String iv = "str0ng-s3cr3t-1v";
private String key = "p4ssw0rd-t0-hid3";
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
this.setContentView(2131296284);
((Button)this.findViewById(2131165218)).setOnClickListener(new View.OnClickListener(){
public void onClick(View object) {
String string = ((EditText)MainActivity.this.findViewById(2131165277)).getText().toString();
try {
object = Cipher.getInstance(MainActivity.this.algorithm);
SecretKeySpec secretKeySpec = new SecretKeySpec(MainActivity.this.key.getBytes(), MainActivity.this.algorithm);
Object object2 = new Object(MainActivity.this.iv.getBytes());
((Cipher)object).init(1, (Key)secretKeySpec, (AlgorithmParameterSpec)object2);
secretKeySpec = (EditText)MainActivity.this.findViewById(2131165226);
object2 = new Object(Base64.getEncoder().encode(((Cipher)object).doFinal(string.getBytes())));
secretKeySpec.setText((CharSequence)object2);
}
catch (Exception exception) {
((EditText)MainActivity.this.findViewById(2131165226)).setText((CharSequence)"Failed in encrypting the plaintext.");
}
}
});
}
}
```
ソースコードを見ると入力された文字列をAESで暗号化していることがわかる。入出力を雑に見るとこう。
```java=
void onCreate() {
String algorithm = "AES/CBC/PKCS5Padding";
String iv = "str0ng-s3cr3t-1v";
String key = "p4ssw0rd-t0-hid3";
String input; // 入力文字列
// 暗号化処理の初期化
Cipher cipher = Cipher.getInstance(algorithm);
SecretKeySpec spec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
// 暗号化
byte[] c = cipher.doFinal(input.getBytes());
String output = new Object(Base64.getEncoder().encode(c)); // 出力文字列
}
```
見ると暗号化処理があって入出力はあるが、おそらくどちらもTextInputで特にメッセージの送受信などの機能はない。また、どんんな文字列を暗号化したのか、暗号化前後の文字列もここにはない。おそらくこれは暗号化のみのアプリケーションで、他のメッセンジャーで送信する前にこれで暗号化を行っているのでそちらを見に行く。鍵も暗号化方式もIVもソースコード中にあるので、暗号化されたメッセージを見つければ勝ち。
## メッセージの探索
もともとのファイルシステムに立ち返って`/data`ディレクトリをみると`com.google.android.apps.messaging`というディレクトリがある。これがAndroid標準のメッセンジャーっぽいので見に行く。`databases`というディレクトリがあって中には`bugle_db`というファイルと`subscribers.db`というファイルがある。どちらもSQLite3のデータベースファイルで、結論から言うと`bugle_db`がビンゴ。これもicatで抽出する。
```
$ fls android_8.1_x86_oreo.img 15456
r/r 15461: bugle_db
r/r 15462: bugle_db-journal
r/r 15563: subscribers.db
r/r 15566: subscribers.db-journal
$ icat android_8.1_x86_oreo.img 15461 > bugle_db
```
`bugle_db`の中身は`sqlite3`コマンドでCLIで見てもいいが、テーブル数・カラム数が多いのでDB BrowserなどGUIのアプリケーションを使うと見やすい。
`conversation_search_list_view`というviewがあってこれを見に行くと`snippet_text`というカラムがこんな感じになっている。おそらく送受信したデータで、平文のものもあるがあきらかにBase64されているメッセージがある。これはおそらく先程のアプリケーションで暗号化されているので復号するコードを書く。ところで会話の内容がよくわからない。
```
"We need to discuss the plan now."
"Make our conversation secret by using our app, ok?"
"Sure."
"pwgh/nXO1tMf6TXUd99mhNH01GcCqVDxDBy1+sDf37s4nnYRuHkS+AOoiH3DmKU3I+ZYHEsllcwlnm6FWjAb5g=="
"GVuIBG/lSSUNW6jZqR20hw=="
"Did you forget your umbrella?"
"No. I have one."
"It's raining out there."
"yup"
"Take good care of your health. It's heavy."
"Thanks, mom."
```
雑に書くとこうなった。
```java=
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
class Dec {
public static String dec(String i) throws Exception {
String algorithm = "AES/CBC/PKCS5Padding";
String iv = "str0ng-s3cr3t-1v";
String key = "p4ssw0rd-t0-hid3";
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] source = Base64.getDecoder().decode(i);
byte[] plaintext = cipher.doFinal(source);
return new String(plaintext, "UTF-8");
}
public static void main(String[] args) throws Exception{
System.out.println(dec("pwgh/nXO1tMf6TXUd99mhNH01GcCqVDxDBy1+sDf37s4nnYRuHkS+AOoiH3DmKU3I+ZYHEsllcwlnm6FWjAb5g=="));
System.out.println(dec("GVuIBG/lSSUNW6jZqR20hw=="));
}
}
```
実行結果は次の通り。
```
$ java Dec
The flag is KOSENCTF{7h3_4r7_0f_4ndr01d_f0r3n51c5}
I got it.
```
というわけでフラグは`KOSENCTF{7h3_4r7_0f_4ndr01d_f0r3n51c5}`でした。楽しいね。