柏鹭杯 2021重要信息还原

runwu2204 Lv6

给了两个文件夹,一个是源码一个是编译后的文件

image-20230713205556346

可以直接将resources压缩包打包为apk然后丢进jadx(apk本质就是压缩包)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" android:compileSdkVersion="29" android:compileSdkVersionCodename="10" package="com.example.c1" platformBuildVersionCode="29" platformBuildVersionName="10">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="false" android:supportsRtl="true" android:fullBackupContent="false" android:roundIcon="@mipmap/ic_launcher_round" android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<activity android:name="com.example.c1.MainActivity" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

只有一个activity

其主要逻辑流程如下

graph TB;
    C0-->|1.传入flag| B1;
    B1-->|2.传入flag|C1;
    C1-->|3.调用|B2;
    B2-->|4.传入key|C1;
    C1-->|5.返回RSA加密结果|B1
    B1-->|6.传入RSA加密结果|C2;
    C2-->|7.MD5后的字符串|B1
    B1-->|8.MD5后的字符串|D0
    D0-->D1
    D0-->D2
    D1-->|前16个作为AES密钥|D3
    D2-->|后面的字符串作偏移|D3
    D3-->|9.AES/CBC/PKCS7Padding解密|D4
    subgraph java层
        direction TB
        C0[onClickCheck]
        subgraph JNI层
        direction TB
        B1[JNI-b] 
        B2[JNI-a]
        C1[java-funcB]
        C2[java-funcA]
    end
        subgraph decryptMsg方法
        direction TB
        D0[字符串]
        D1[前16个字符串]
        D2[剩余的字符串]
        D3[assets中enc文件]
        D4[解密后的文件]
        end
    end

解密文件

RSA

可以通过JNI中的a函数获取公钥

公钥格式

1
2
3
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJgby/H1lmzAIGjC3NczfQEWl5e3gR2VDukg9Wm+UopVUgXbj9O4+YSMZ0brftk2Qkr8GHJU8a8YqK2DNFg2XD8CAwEAAQ==
-----END PUBLIC KEY-----

私钥格式

1
2
3
-----BEGIN PRIVATE KEY-----

-----END PRIVATE KEY-----

image-20230713205917019

根据题目在JNI b函数中的提示

1
__android_log_print(4, "HINT:", "http://www.factordb.com/");

可以通过该网站factordb.com分解出p和q,最后根据rsa的算法可以算出解密密钥d

注意此处是分组加密算法,需要将密文分成多组,原来我自己直接解密不知道是分组加密,卡了很久

AES

根据apk中的decryptMsg方法可以知道其获取的apk中funcA进行md5后的字符串(32字节,大写)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private final String funcA(String str) {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
Charset charset = Charsets.UTF_8;
if (str == null) {
throw new TypeCastException("null cannot be cast to non-null type java.lang.String");
}
byte[] bytes = str.getBytes(charset);
Intrinsics.checkExpressionValueIsNotNull(bytes, "(this as java.lang.String).getBytes(charset)");
byte[] m = messageDigest.digest(bytes);
MainActivity$funcA$1 mainActivity$funcA$1 = MainActivity$funcA$1.INSTANCE;
Intrinsics.checkExpressionValueIsNotNull(m, "m");
return mainActivity$funcA$1.invoke(m);
}
public final String invoke(byte b) {
String format = String.format("%02X", Arrays.copyOf(new Object[]{Byte.valueOf(b)}, 1));//此处是大写的hex字符串
Intrinsics.checkExpressionValueIsNotNull(format, "java.lang.String.format(this, *args)");
return format;
}

AES解密的算法可以简化为

1
2
3
4
5
6
7
8
9
10
11
12
String substring3 = str.substring(0, 16);
byte[] bytes = substring3.getBytes(Charsets.UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, "AES");//md5前16个字符串作为密钥
String substring4 = str.substring(16);
byte[] bytes2 = substring4.getBytes(Charsets.UTF_8);
IvParameterSpec ivParameterSpec = new IvParameterSpec(bytes2);//md5后16个字符串作为偏移
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");//注意此处是带填充的
cipher.init(2, secretKeySpec, ivParameterSpec);//解密模式
InputStream open = getAssets().open("enc");
Intrinsics.checkExpressionValueIsNotNull(open, "assets.open(\"enc\")");//解密文件
new FileOutputStream(getMsgFile()).write(cipher.doFinal(IOStreams.readBytes(open)));

python 解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import base64
from Crypto.Util.number import*
import gmpy2
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
base="j7WBExN4XN/P2HVCOFssAAquRgdQCqdWZKwDo9uTBLfcLpC+1XC6DmBokh5twaS7Ip1MBIEAlFX2WEzz2H9qwXT5WEUgzC4RF0AOe95wqU89oqf4dn7/ZiO2imb5a6FrDnpwo6SqtdhasU3OrGg7mgtapukCHjjmJH7Vx+yVPm0uR40bgxVCIPtnJ+b6iNp8o+Cgyrd2BZ/TCQX1GJz3pM80+cV5cZOMjr/JepVcWFN+7GNKxR8jaPa/bV+C7Y+S"
cipher_bytes = base64.b64decode(base)
tmp1=[]
for i in range(0,len(cipher_bytes),64):
tmp1.append(cipher_bytes[i:i+64]) #64个字节一组
e=65537
p=71037807056497808667473611757425298887086548124211388066888426631640585037969
q=112145533787143859495414888829654253787274898301436147509050442708404900683727
n=7966572791419081482888151379127643748169118610600984895753957531413662475745737840799418096417263789370960837649556218062403972113814987633647934355430463
d=gmpy2.invert(e,(p-1)*(q-1))
tmp2=[]
tmp3=[]
tmp4=''
for i in tmp1:
tmp2.append(pow(bytes_to_long(i),d,n))
for i in tmp2:
tmp3.append(long_to_bytes(i))
for i in tmp3:
tmp4+=i.decode()
tmp=''
for i in range(0,len(tmp4.replace('|','').replace('\x00','')),8):
tmp+=chr(int(tmp4.replace('|','')[i:i+8],2))
print(tmp)
tmp=str.upper(__import__("hashlib").md5(tmp.encode()).hexdigest())
password=tmp[0:16].encode()
iv=tmp[16:].encode()
with open(r".\resources\assets\enc','rb') as e:
with open(r'.\resources\assets\dec.7z',"wb+")as d:
enc=e.read()
cipher=AES.new(password,AES.MODE_CBC,iv)
dec=cipher.decrypt(enc)
dec=unpad(dec,AES.block_size)
d.write(dec)

解密后的文件是个,7z的压缩包

TLS解密

解压后的文件有一个数据包文件和一个keylog文件

image-20230713211514142

用wireshark打开数据包文件追踪TLS流发现没有显示,又根据keylog文件猜测是TLS进行了加密,直接导入keylog文件(之前获取密钥的日志文件)就可以解密了

具体操作

graph TB
A1[左上角的编辑选项]
A2[点击编辑选项最下面的首选项]
A3[点击左侧的Protocols的小三角]
A4[在展开的栏目中点击TLS]
A5["(Pre)-Master-Secret log filename中填入keylog文件的路径"]
A1-->A2-->A3-->A4-->A5

image-20230713212426147

最后直接点OK就行

选择解密后多出来的http流,右键选择追踪TLS流就可以得到flag了

image-20230713212620547

  • 标题: 柏鹭杯 2021重要信息还原
  • 作者: runwu2204
  • 创建于 : 2023-07-13 20:54:23
  • 更新于 : 2023-07-13 21:38:17
  • 链接: https://runwu2204.github.io/2023/07/13/CTF WP/Re/安卓/柏鹭杯 2021重要信息还原/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
柏鹭杯 2021重要信息还原