Automne's Shadow.

HWCTF Mobile WriteUp

2019/07/25 Share

Android

作为一名弱鸡Android选手,刚了几个月的密码学,插播一条Android题。

使用JEB打开,可以看到给了AES-CBC加密后的密文,而且密文格式需要做一定处理,要求还原出明文。明文就是apk上要输入的密码。

automne

automne

代码里调用了so库,可以使用frida进行hook,将生成的IV和key打印出来再进行解密。也可以使用Android Studio加载so文件进行分析。

Hook方式

这里需要注意,对于byte[],直接再frida的js脚本里通过console.log打印将会返回Object对象,需要使用下面的方式打印IV。

js文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
setImmediate(function() {
Java.perform(function() {

var mc = Java.use("com.zhuotong.zzsence");
var mc2 = mc.$new();
console.log("---------")
var ret = mc2.generateIv();

//Handle byte[]
var buffer = Java.array('byte',ret);
console.log(ret);
console.log(buffer.length);

var result = [];
for(var i=0;i<buffer.length;++i){
result += buffer[i];
}
console.log(result);
console.log("+++++++++");
console.log(mc2.generatekey());
console.log("+++++++++");
});
});

Hook对应的apk后得到加密使用的IV和key值

automne

处理反编译读到的密文,得到byte[] n:

Android Studio的代码片段如下:

1
2
3
4
5
6
7
8
9
10
int[] t = new int[]{0x7F, 41, 0x20, -23, 53, 0xFFFFFF8F, -59, 0x9A, 5, 16, 52, 0xBC, 91, 150, 43, 0xA3, 140, 170, 0x9E, 36, 0x91, 140, 0xD3, 17, 18, 0x4F, 200, 0xB1, 0x7A, 78, 0xDB, 0xF7};

byte[] n = new byte[32];

Log.i("Leon",Integer.toString(t.length));

for(int j = 0; j < 32; j++) {
//Log.i("Leon",Integer.toString(j));
n[j] = ((byte) t[j]);
}

解密代码如下,注意这里的iv处理形式和解密使用的参数Cipher.DECRYPT_MODE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public String decrypt(byte[] arg6) throws Exception {

SecretKey key = handleKey("ipapmpnpoptppppppppppppppppppp").a();

byte[] iv = new byte[16];
int[] ivraw = new int[]{0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30};
for(int i = 0; i < 16; ++i) {
iv[i] = ((byte) ivraw[i]);
}

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
return new String(cipher.doFinal(arg6));
}

public static zzsence.a handleKey(String arg4) throws NoSuchAlgorithmException, UnsupportedEncodingException {
return new zzsence().new a(new SecretKeySpec(Arrays.copyOf(MessageDigest.getInstance("SHA-1").digest(arg4.getBytes("UTF-8")), 16), "AES"));
}

在Android Studio里调用decrypt(n)即可解出flag:flag{jsdg632t12}

加载SO方式

首先创建一个com.zhuotong.easyctf2的工程,zzsence的代码基本参考反编译后的内容。

并将libone.so放到app/main/jniLibs/armeabi-v7a下,如下图

automne

注意zzsence.java里和so库相关的部分代码片段。

1
2
3
4
5
6
7
static {
System.loadLibrary("one");
}

public static native byte[] generateIv();

public static native String generatekey();

根据代码特点,写出如下解密代码:

1
2
3
4
5
6
7
8
9
10
public String decrypt(byte[] arg6,zzsence.a arg4) throws Exception {

byte[] iv = zzsence.generateIv();
//SecretKey key = handleKey(zzsence.generatekey()).a();

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

cipher.init(Cipher.DECRYPT_MODE, arg4.a(), new IvParameterSpec(iv));
return new String(cipher.doFinal(arg6));
}

解密即可得到flag

1
decrypt(n, handleKey(zzsence.generatekey()))

在Android Studio里运行即可得到flag

automne

在apk里输入后提示正确。

automne

CATALOG
  1. 1. Hook方式
  2. 2. 加载SO方式