Flagdroid
- 147 solves
- 153 points
- Easy
- Category: Reverse
- Author: m0ney
- Text: “This app won’t let me in without a secret message. Can you do me a favor and find out what it is?”
- Download file: an APK
Analysis of the app
We decompile the application. The validation of the flag is done when you press the button check:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public void onClick(View arg10) {
TextView tvWrong = (TextView)MainActivity.this.findViewById(0x7F0700EC); // id:textViewWrong
TextView tvCorrect = (TextView)MainActivity.this.findViewById(0x7F0700EB); // id:textViewCorrect
String secretInput = ((EditText)MainActivity.this.findViewById(0x7F0700C4)).getText().toString(); // id:secretInput
Matcher match = Pattern.compile("flag\\{(.*)\\}").matcher(secretInput);
if(match.find()) {
String[] flagcore = match.group().replace("flag{", "").replace("}", "").split("_");
if(flagcore.length == 4 && ((MainActivity.this.checkSplit1(flagcore[0])) && (MainActivity.this.checkSplit2(flagcore[1])) && (MainActivity.this.checkSplit3(flagcore[2])) && (MainActivity.this.checkSplit4(flagcore[3])))) {
tvWrong.setVisibility(4);
tvCorrect.setVisibility(0);
return;
}
}
|
The flag is surrounded by flag{...}
and each part is separated by a _
. There are 4 different parts. Each part is validated by a method checkSplitX()
where X is the number of the split.
First part
It is a base64 string dEg0VA==
: tH4T
Second part
The second part is created from an algorithm that:
- checks the length is 9
- performs a translation on the character
- XORs the result with a fixed key
hack.lu20
To do the decode, we must do it the other way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| public static String createSplit2() {
try {
String s = new String("\u001fTT:\u001f5\u00f1HG");
char[] v8 = s.toCharArray();
byte[] key = "hack.lu20".getBytes("UTF-8");
int v3;
for(v3 = 0; v3 < 9; ++v3) {
v8[v3] = (char)(v8[v3] ^ key[v3]);
v8[v3] = (char)(v8[v3] - v3);
}
System.out.println("Result: "+ String.valueOf(v8));
return new String(v8);
}
catch(UnsupportedEncodingException unused_ex) {
System.out.println("Exception");
}
return null;
}
|
The main difficulty is to copy paste the Unicode string correctly…
Result: w45N-T~so
Third part
We know the part consists of 8 characters. The first four are h4rd
, possibly with a different case.
The last 4 characters are not given, but we know the MD5 of the string must be 6d90ca30c5de200fe9f671abb2dd704e
.
We search for the string on MD5 reverse but it is not known
So, we brute force it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import hashlib
prefix = 'h4rd'
for a in ['h', 'H']:
for b in ['r', 'R']:
for c in ['d', 'D']:
for i in range(ord('-'), ord('~')+1):
for j in range(ord('-'), ord('~')+1):
for k in range(ord('-'), ord('~')+1):
for l in range(ord('-'), ord('~')+1):
s = a + '4' + b + c + chr(i) + chr(j) + chr(k) + chr(l)
print("Testing: {0}".format(s))
value = hashlib.md5(bytes(s,'utf-8')).hexdigest()
if value == "6d90ca30c5de200fe9f671abb2dd704e":
print("FOUND: {0}".format(s))
quit()
|
Result:
1
2
3
4
5
| Testing: h4rd~hue
Testing: h4rd~huf
Testing: h4rd~hug
Testing: h4rd~huh
FOUND: h4rd~huh
|
Fourth part
The last part of the flag is given by a native function stringFromJNI
.
We write a Frida hook for that:
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
| 'use strict';
console.log("[*] INSIDE native-lib.js");
global.run = function () {
console.log("[debug] global.run: Java.available="+Java.available);
Java.perform(function () {
var mainClass = Java.use("lu.hack.Flagdroid.MainActivity");
mainClass.stringFromJNI.implementation = function() {
console.log("[*] Hooking");
var ret = this.stringFromJNI();
console.log("ret="+ret);
return ret;
}
mainClass.checkSplit1.implementation = function(b) {
var ret = this.stringFromJNI();
console.log("ret="+ret);
return this.checkSplit1(b);
}
console.log("[*] loaded hooks - v4");
});
};
|
Then, we launch the Frida server on the smartphone, launch the app, and on the laptop, launch Frida client: frida -U -l native-lib.js -n lu.hack.Flagdroid
1
2
| [*] Hooking
ret=0r~w4S-1t?8)
|
Final solution
flag{tH4T_w45N-T~so_h4rd~huh_0r~w4S-1t?8)}