# Catchmouse - 2020 Defenit CTF (rev, 690p, 8 solved)## Introduction
Catchmouse is a reversing task.
A single file is provided : `catchMouse.apk`. It is an Adroid application.
The application is a game. Each round last 10 seconds. The player has to tap onimages of mouse gain points. When the time is over, the best 5 scores arestored.
The apk contains JVM code and a native library, `libjniCalculator.so`.
## Java 
The Java code can be decompiled with recent decompilers.[Procyon](https://bitbucket.org/mstrobel/procyon/wiki/Java%20Decompiler) workedthe best.
The class `com.example.touchgame.ResultActivity` contains a string that mentionsthe flag. It is slightly obfuscated in the sense that `jadx` could not decompilethe `onStart` method.
The `onCreate` method sets class properties, in particular `this.t` is set tothe current player's name and `this.u` is set to the current player's score.
```javathis.t = ((Activity)this).getIntent().getStringExtra("name");this.u = ((Activity)this).getIntent().getIntExtra("score", 0);```
The `onStart` method takes `this.u`, the score, and calls `Convertkey1` on it.It then calls `Convertkey2` on its return value, and so on until `Convertkey7`.
```javathis.v = this.Convertkey1(this.u);this.v = this.Convertkey2(this.v);this.v = this.Convertkey3(this.v);this.v = this.Convertkey4(this.v);this.v = this.Convertkey5(this.v);this.v = this.Convertkey6(this.v);this.v = this.Convertkey7(this.v);```
The method then retrieves a signature, hashes it, and encodes the result inbase64.
The [Android documentation](https://developer.android.com/reference/android/content/pm/Signature)states that Signature is an `Opaque[...] representation of a signingcertificate`.
```javafor (final Signature signature : ((Activity)this).getPackageManager().getPackageInfo("com.example.touchgame", 64).signatures) {	final MessageDigest instance = MessageDigest.getInstance("SHA-256");	instance.update(signature.toByteArray());	this.y = Base64.encodeToString(instance.digest(), 0);}```
The score is then concatenated with the base64 string, and hashed again.
```javafinal StringBuilder sb = new StringBuilder();sb.append(Long.toString(this.v));sb.append(this.y);final String string = sb.toString();
final MessageDigest instance2 = MessageDigest.getInstance("SHA-256");instance2.update(string.getBytes());final byte[] digest = instance2.digest();```
The new digest is converted to its hexadecimal representation.
```javafinal StringBuffer sb2 = new StringBuffer();for (int k = n; k < digest.length; ++k) {	sb2.append(Integer.toString((digest[k] & 0xFF) + 256, 16).substring(1));}String string2 = sb2.toString();```
And this hexadecimal representation is used as a parameter of the `b.b.a.a`class.
Snippets of the `b.b.a.a` class would serve no purpose in this write-up. Itperforms encryption and decryption of AES-128-CBC. The parameter is both the keyand the IV. Only the first 128 bits are used. The IV and the key are the same.
The player's name is encrypted as explained above. If the result matches`6ufrtSAmvqHgdpLJ3dJJYmKHcE3FyqnXGe2rzFGDsBE=`, the good boy is displayed.
In other words, `6ufrtSAmvqHgdpLJ3dJJYmKHcE3FyqnXGe2rzFGDsBE=` is the flagencrypted with a key derived from the score and the application's signature.
```javafinal b.b.a.a a2 = new b.b.a.a(string2); // aes-128-cbcfinal String b2 = a2.b(this.t); // encryptfinal String a3 = a2.a(b2); // decryptfinal StringBuilder sb3 = new StringBuilder();sb3.append("decrypt:");sb3.append(a3);Log.e("catname", sb3.toString());
if (b2.equals("6ufrtSAmvqHgdpLJ3dJJYmKHcE3FyqnXGe2rzFGDsBE=")) {	Toast.makeText(((Activity)this).getApplicationContext(), (CharSequence)"Good!!! Cat Name is Flag", 1).show();}```
To sum it up :```pythonhash = ck7(ck6(ck5(ck4(ck3(ck2(ck1(score)))))))key  = sha256(str(hash) + base64(sha256(signature)))iv   = key[0x00:0x10]
flag = decode(key, iv, "6ufrtSAmvqHgdpLJ3dJJYmKHcE3FyqnXGe2rzFGDsBE=")```
This construction ensures the application is not modified, as the signaturewould become invalid.
## JNI
The `libCalculator.so` library exports the `Convertkey` functions.
These contain the same pattern repeated multiple times :```clocal_40 = 1;while (local_40 < 0x4d5) {	local_18 = local_18 + 0x539 % local_40 + -0x852a4b69;	local_40 = local_40 + 1;}
local_44 = 1;while (local_44 < 0x25) {	local_18 = local_18 + 0x539 % local_44 + 0x852a5a91;	local_44 = local_44 + 1;}```
`Convertkey1` is different. It checks that the input is within the `[500, 1000]`interval. It returns a constant value if it is not, hinting that the expectedscore is between 500 and 1000.
```cif ((param_3 < 1000) && (499 < param_3)) {	local_20 = [...];}else {	local_20 = 0x12535623cbac930f;}return local_20;```
Fortunately, `libCalculator.so` has been compiled for x86_64. None of itsfunction call any functions. It is thus possible to lift the code from thosefunctions and use it without any modification.
## Finding the flag
With both parts of the application reversed, it becomes clear that the followingare required in order to find the flag :1. retrieve the signature, its hash or the base64 of it2. bruteforce the score between 500 and 1000 to find the key
The first part can be done with Frida. Frida is a great tool. Its documentationhowever...
Frida can find an Android phone connected via USB with `frida.get_usb_device()`.
It can attach to a running process with `device.attach('package.id')`.
Then, it can execute code within the Java context with `Java.perform(code)`.
The code can obtain references to Java classes with `Java.use("class.name")`.
The methods can be accessed with `class.methodName`. If a method is definedmultiple time (overloaded), it can be discriminated with`class.methodName.overload("arg1_type", "arg2_type", ...)`. type is thedescriptor representation of the type (e.g. `[B` for a byte array) as defined inChapter [4.3. Descriptors and Signature](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3)of the Java Virtual Machine Specification.
The easiest way is to pretend there is no need for an overload. Frida will printa helpful message about what methods signatures can be overloaded.
The implementation of a method can be replaced with `method.implementation =function(x) { ... }`. The `this` object represents the current object.`this.foo` will call the original `foo` method, even if it is overloaded.
The `hook.py` script hooks `java.lang.StringBuilder` and outputs strings itbuilt. This shows the following base64 :`wo6sy9VK4Aql1J6+yXpizrQcKa33BlE48v+LmgOiKrY=\n` (mind the new line !)
Using this string and a C script to try every scores, the flag can be decryptedin no time.
```./bf | ./pwn.php | stringsDefenit{Cat_Name_Is_MeOw_mEOw}```
**Flag**: `Defenit{Cat_Name_Is_MeOw_mEOw}`
## Appendices
### hook.py
```pythonimport frida, sys
def on_message(message, data):    if message['type'] == 'send':        print("[*] {0}".format(message['payload']))    else:        print(message)
jscode = """Java.perform(function () {	Java.use("android.util.Base64").encodeToString.overload('[B', 'int').implementation = function(a, b) {		console.log("base64");
		var str = "";		for(var i = 0; i < a.length; i++) {			var byte = a[i] & 0xFF;
			if(byte < 0x10)				str += "0";
			str += byte.toString(16) + " ";		}
		console.log(str);		return this.encodeToString(a, b);	};
	Java.use("java.lang.StringBuilder").toString.implementation = function() {		var ret = this.toString();
		console.log("sb = " + ret);		return ret;	};});"""
process = frida.get_usb_device().attach('com.example.touchgame')print(process)
script = process.create_script(jscode)script.on('message', on_message)script.load()sys.stdin.read()```
### bf.c
```c#include <stdio.h>#include <sys/mman.h>#include <fcntl.h>
typedef long jni(int, int, long);
int main(int argc, char *argv[]){	int fd;	void *base;	long (*ck1)(int, int, long);	long (*ck2)(int, int, long);	long (*ck3)(int, int, long);	long (*ck4)(int, int, long);	long (*ck5)(int, int, long);	long (*ck6)(int, int, long);	long (*ck7)(int, int, long);
	fd = open("lib/x86_64/libjniCalculator.so", O_RDONLY);	base = mmap(NULL, 0x2000, 7, MAP_PRIVATE, fd, 0);
//	printf("%p\n", base);	ck1 = (jni*)(base + 0x850);	ck2 = (jni*)(base + 0x910);	ck3 = (jni*)(base + 0xb20);	ck4 = (jni*)(base + 0xe50);	ck5 = (jni*)(base + 0x1200);	ck6 = (jni*)(base + 0x1430);	ck7 = (jni*)(base + 0x1650);
	for(int i = 500; i < 1000; i++) {		long hash = i;
		hash = ck1(0, 0, hash);		hash = ck2(0, 0, hash);		hash = ck3(0, 0, hash);		hash = ck4(0, 0, hash);		hash = ck5(0, 0, hash);		hash = ck6(0, 0, hash);		hash = ck7(0, 0, hash);
	//	printf("%d %016lX\n", i, hash);		printf("%ld\n", hash);	}}```
### pwn.php
```php#!/usr/bin/php