Post

nowyouseeme - Shakti CTF Writeup

Walkthrough for the nowyouseeme Android reverse engineering challenge from Shakti CTF.

nowyouseeme - Shakti CTF Writeup

Challenge Info

FieldDetails
CTFShakti CTF
Challengenowyouseeme
CategoryAndroid / Reverse Engineering

Description

Some secrets don’t like the spotlight. They prefer memory.

Solution

We can start by installing the APK and opening it in our emulator.

alt text

It displays the message in reverse, which we can read to

1
This is not a part of the module, making it too hard

Now, we can proceed to inspect it in Jadx,

alt text

The Main Activity hasn’t much in it, but wee see another class FlagEngine and calls a native method getFlag(str) but one thing is confusing,

1
2
3
4
static {
        System.loadLibrary("flagengine");
    }
}

The APK does not have libflagengine.so, the native lib bundles with it is libnowyouseeme.so, that means the native library is never loaded If we tried to hook the getFLag(str) method using Frida, we always get error:

1
2
3
4
Spawned `com.shaktictf.nowyouseeme`. Resuming main thread!
Error: unable to find module 'libnowyouseeme.so'
    at value (frida/runtime/core.js:381)
    at <eval> (/home/notRain/Downloads/script.js:27)

So, we would have to rely on Ghidra to get the flag,

alt text

We see that this function takes in our input and compares it with mysecretkey and if it matches it does a xor encryption with the encrypted bytes stored in the memory &DAT_001006b0 If we click on &DAT_001006b0 we can view the raw bytes and extract it

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        001006b0 00              ??         00h
        001006b1 00              ??         00h
        001006b2 21              ??         21h    !
        001006b3 00              ??         00h
        001006b4 00              ??         00h
        001006b5 00              ??         00h
        001006b6 00              ??         00h
        001006b7 20              ??         20h
        001006b8 20              ??         20h
        001006b9 24              ??         24h    $
        001006ba 48              ??         48h    H
        001006bb 03              ??         03h
        001006bc 46              ??         46h    F
        001006bd 68              ??         68h    h
        001006be 35              ??         35h    5
        001006bf 58              ??         58h    X
        001006c0 35              ??         35h    5
        001006c1 05              ??         05h
        001006c2 10              ??         10h
        001006c3 36              ??         36h    6
        001006c4 2e              ??         2Eh    .
        001006c5 47              ??         47h    G
        001006c6 39              ??         39h    9
        001006c7 3d              ??         3Dh    =
        001006c8 02              ??         02h
        001006c9 5b              ??         5Bh    [
        001006ca 5a              ??         5Ah    Z
        001006cb 59              ??         59h    Y
        001006cc 37              ??         37h    7
        001006cd 37              ??         37h    7
        001006ce 34              ??         34h    4
        001006cf 03              ??         03h
        001006d0 47              ??         47h    G
        001006d1 36              ??         36h    6
        001006d2 72              ??         72h    r
        001006d3 18              ??         18h
        001006d4 0a              ??         0Ah
        001006d5 2a              ??         2Ah    *
        001006d6 42              ??         42h    B
        001006d7 5a              ??         5Ah    Z
        001006d8 03              ??         03h
        001006d9 59              ??         59h    Y
        001006da 0c              ??         0Ch
        001006db 58              ??         58h    X
        001006dc 26              ??         26h    &
        001006dd 34              ??         34h    4
        001006de 17              ??         17h
        001006df 59              ??         59h    Y
        001006e0 27              ??         27h    '
        001006e1 47              ??         47h    G
        001006e2 39              ??         39h    9
        001006e3 6a              ??         6Ah    j
        001006e4 01              ??         01h
        001006e5 06              ??         06h
        001006e6 03              ??         03h

There are 56 bytes, we can write a python program to xor these bytes with myscretkey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
data = [
    0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x20,
    0x20,0x24,0x48,0x03,0x46,0x68,0x35,0x58,
    0x35,0x05,0x10,0x36,0x2e,0x47,0x39,0x3d,
    0x02,0x5b,0x5a,0x59,0x37,0x37,0x34,0x03,
    0x47,0x36,0x72,0x18,0x0a,0x2a,0x42,0x5a,
    0x03,0x59,0x0c,0x58,0x26,0x34,0x17,0x59,
    0x27,0x47,0x39,0x6a,0x01,0x06,0x03
]

key = "mysecretkey"

for i in range(len(data)):
    print(chr(data[i] ^ ord(key[i % len(key)])), end="")

If we run the program we get garbage value, myRecreTKA1n?;Gd]K>TDq>9+RC_f>[ koI0?w2i!KMd<D5\jcz This happened probably because the key is not mysecretkey, Upon closer inspection in Jadx,

alt text

This class has a static method getKey which opens zipped file assets/resources.dat and then does something but returns a string back We can use Frida to call this method and see if it returns the actual key

1
2
3
4
5
6
7
Java.perform(() => {
    var ActivityThread = Java.use('android.app.ActivityThread');
    var context = ActivityThread.currentApplication().getApplicationContext();
    var Interceptor = Java.use("com.shaktictf.nowyouseeme.DataBridge");
    console.log(Interceptor.getKey(context))

})

We use Java.use('android.app.ActivityThread'); and ActivityThread.currentApplication().getApplicationContext(); since the argument passed has to be context If we load this script,

alt text

It returns the string Sh@ktiCtf_1337 we can try this as the key to decrypt the raw bytes we found

1
2
3
4
5
6
7
8
9
10
11
12
13
14
data = [
    0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x20,
    0x20,0x24,0x48,0x03,0x46,0x68,0x35,0x58,
    0x35,0x05,0x10,0x36,0x2e,0x47,0x39,0x3d,
    0x02,0x5b,0x5a,0x59,0x37,0x37,0x34,0x03,
    0x47,0x36,0x72,0x18,0x0a,0x2a,0x42,0x5a,
    0x03,0x59,0x0c,0x58,0x26,0x34,0x17,0x59,
    0x27,0x47,0x39,0x6a,0x01,0x06,0x03
]

key = "Sh@ktiCtf_1337"

for i in range(len(data)):
    print(chr(data[i] ^ ord(key[i % len(key)])), end="")

We get the flag:shakticTF{y0u_F0und_M3_b3hinD_th3_illusi0n_0f_c0D3_5050}

This post is licensed under CC BY 4.0 by the author.