Insomni'hack teaser 2022 - AndroNotes Writeup

Our Forensic experts dumped the mobile device of a criminal, can you identify what the thugs are up to...
This challenge can be solved offline.

附件下载链接 提取码:HACK

Basic analysis:

根据题目标签和描述分析是对内存数据文件等进行分析,再根据题目AndroNotes可以确定是分析一个Notes软件,查到有AndroNotes同名软件,但是过于古老没有找到相关数据文件。foremost分析镜像文件可以看到很多图片,其中有一张软件logo和一张关于Note软件的介绍图片

传统艺能网上冲浪得知appsafe notes

Autopsy加载镜像文件,查看数据库文件。(也可以用mount挂载,方法不唯一)

看到一段信息

SEND:
Hi James, I've configured the server please keep the password in a safe place mate! The website contains sensitive information about mrna-1273!

Best

RECV:
Hi H, it is in my Safe Note app. One of the most secure with military grade encryption mechanisms.\\U0001f4af\\U0001f4af

SEND:
Nice, Funds are Safu !

RECV:
\\U0001f61c\\U0001f637\\U0001f911\\U0001f468\\u200d\\U0001f52c

更加确定是Safe Note app 提取码:Note

恢复数据之前要确认该app的数据文件是怎么存储的,用Android Studio创建一个虚拟机,安装一个safe note app,可以看到其数据文件夹为com.protectedtext.android

方法一:分析Note数据文件

比对添加Note前后的数据文件,不难发现,com.protectedtext.n2.xml这个文件存储了加密后的Note

然后很自然想到,将密文替换掉,替换掉com.protectedtext.n2.xml,关闭软件后台,再打开软件即可看见flag

方法一:整体替换数据文件夹

替换后会显示要输入PIN码,也可以爆破,但是效率低,且作用不显著,这里不再演示

方法三:逆向程序分析数据加密方式

首先google发现该软件的加密方式,然后jadx打开网上下载到的apk

看到这段盲猜是AES/DES之类的对称加密方式,在代码中搜索

com.protectedtext.other.e类里有相关加解密函数

public static String a(String str, String str2) {
    try {
        byte[] decode = Base64.decode(str, 0);
        byte[] bArr = new byte[8];
        byte[] bArr2 = new byte[(decode.length - 16)];
        System.arraycopy(decode, 8, bArr, 0, 8);
        System.arraycopy(decode, 16, bArr2, 0, bArr2.length);
        MessageDigest instance = MessageDigest.getInstance("MD5");
        byte[] a2 = a(str2.getBytes(), bArr);
        byte[] digest = instance.digest(a2);
        byte[] digest2 = instance.digest(a(digest, a2));
        byte[] digest3 = instance.digest(a(digest2, a2));
        SecretKeySpec secretKeySpec = new SecretKeySpec(a(digest, digest2), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(digest3);
        Cipher instance2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        instance2.init(2, secretKeySpec, ivParameterSpec);
        return new String(instance2.doFinal(bArr2), "UTF-8");
    } catch (Exception) {
        ...
    }
}

public static String b(String str, String str2) {
    try {
        byte[] bArr = new byte[8];
        new SecureRandom().nextBytes(bArr);
        MessageDigest instance = MessageDigest.getInstance("MD5");
        byte[] a2 = a(str2.getBytes("UTF-8"), bArr);
        byte[] digest = instance.digest(a2);
        byte[] digest2 = instance.digest(a(digest, a2));
        byte[] digest3 = instance.digest(a(digest2, a2));
        SecretKeySpec secretKeySpec = new SecretKeySpec(a(digest, digest2), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(digest3);
        Cipher instance2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        instance2.init(1, secretKeySpec, ivParameterSpec);
        return Base64.encodeToString(a(a(f3233b, bArr), instance2.doFinal(str.getBytes("UTF-8"))), 2).toString();
    } catch (Exception) {
        ...
    }
}

能看到加密方式是AES-CBC-PKCS5Padding,在解密之前要找到keyiv,其中代码使用的是SecretKeySpecIvParameterSpec以及Cipher类。

整体加密规则代码写的很清楚,根据代码调用关系可以在com.protectedtext.a.c中找到key

private static final String f3127b;

static {
    StringBuilder sb = new StringBuilder();
    sb.append("7igb2h048io6fyv");
    sb.append(Math.random() > -1.0d ? "8h92q3ruag" : "98hasdfil");
    sb.append("09g8h");
    f3127b = sb.toString();
}

根据代码逆写解密,得到flag

from Crypto.Cipher import AES
from base64 import b64decode

blob = b64decode("U2FsdGVkX19c/zcgG/UScI+1bKvOvunZUy6Ck1FB/dxMD+BGQLAAkEVufV1+skdK5cyCFqnw2WTY546XgOGnD11WLjg1N0RbbeotynkRGGKFZ3XAMQQUk7v08mBs8IYVISRxSzktd9HgT4cCAjtvWgpYytz9y7Tb4hF1x8plEb114yaWfNspk4XmLqUyssVnyIhqBXDmmIEFVudV+EQsOkYcBW5S1GINEBLqV6lxLKHSTlwWej2Y+TpC1mOAScmIs6NAyquw7ow2oYpqDBC6SB5dslgHYeV9YoCv+evP+lQdmCTf+88VvT001MnUHtgTFnsRcZR1rCmZp2EXNQArCH/onRSAE2ehGPv2NIfsnljeSfg7jO12zkRqf1q22SLtFpHL8OLKjrfvpcY5yRIm1H1vkYRDewYlku6r/WoESpBfAvl8/VKmkrsPfp1JjKLuO3mDOuv5CmE7HBmT3etR5b1WEL78nizxtkj4wFKyY2I4SuHmsNFANZdxMsdpZImYpB6pG0i5ifMGiesjThvTQU8pblQ2XQSrNuqpTtjwXvk=".encode())

rand = blob[8:16]
data = blob[16:]
key = b"7igb2h048io6fyv8h92q3ruag09g8h2"

a2 = key + rand
digest = hashlib.md5(a2).digest()
digest2 = hashlib.md5(digest + a2).digest()
digest3 = hashlib.md5(digest2 + a2).digest()

cipher = AES.new(digest+digest2, AES.MODE_CBC, digest3)
plain = cipher.decrypt(data)
print(plain)
# b'{"id":2,"content":"Operation Secret:\\nINS{P1n_L0c4l_AuTh3nT1c4t10N_1s_4asY}\\nf47c13a09bfcad9eb1f81fbf12c04516e0d900e409a74c660f933e69cf93914e16bc9facc7d379a036fe71468bd4504f2a388a0a28a9b727a38ab7843203488c\xe2\x99\xbb Reload this website to hide mobile app metadata! \xe2\x99\xbb{\\"version\\":1,\\"color\\":-1118482}","ordering_time":1640170640052,"is_encrypted":false,"expected_db_ver":2,"selected_tab_index":0}\t\t\t\t\t\t\t\t\t'
最后修改:2022 年 04 月 11 日 02 : 11 PM
请作者喝杯奶茶吧~