[📓] Writeup - NahamCon 2023 Mobile

Terbit pada tanggal 18 Juni 2023

Ditulis oleh: AnYujin
NahamCon 2023
NahamCon 2023

NahamCon 2023 Writeup - Mobile


during the 16th - 18th june 2023 we participated in NahamCon ctf 2023 i managed to solve 4 out of 5 mobile challenges available, this is my writeups for the challenges i managed to solve, i mainly use genymotion as emulator to these challenge.

JNINJASPEAK

a application named jninjaspeak.apk was given, the first thing i do is quickly try to decompile the app using apktool and then analyze the smali files using jadx-gui, i understood that this app will do somekind of "translation" to the text we give, but i can't find the "translation" scheme so i try opening the app in genymotion.

jninja1

i tried translating a few things and i notice something, when i translate the word "flag" the translation result is empty, so i thought that i had to find the right string to make the translation result empty and the string will be the flag, but after getting the string and submitting it into the NahamCon web it's not the flag :X.

after that i noticed something again, if i filled it with a character for example "b" it will be translated into "0" and if i try to translate "0" it will be "b" and then i wonder, what will happen if i translate spaces " ", and after giving a few space i found this

jninja2

i noticed that it will produce the flag, and i try to give it more spaces so it will produce the flag

jninja3

flag{1f539e4a706e6181dae9db3fad6a78f1}

Fortune Teller

in this chall a apk file fortune_teller.apk was given, after decompiling it with apktool and opening the smali with jadx i understood that i have to give the correct string which is equal to the value of correct_guess to be able to produce the decrypted image which was encrypted using AES CBC mode before, i tried opening the R class file in jadx and found something interesting fortune teller1

so the value of the correct string and encrypted are actually obtainable, first i try to find the correct_guess string in the /res/values/strings.xml and i actually found it

fortune teller2

and i also found the encrypted file in the /res/raw folder, but i don't really want to construct a manual CBC encryption so i try feeding the correct_guess into the application and the image of the flag was given fortune teller3

flag{d7687f4af1a9c75c1811488a12cb54a6n}

Where's Waldo

a apk file wheres_waldo.apk was given, i decompiled the apk and then open it using jadx but the jadx gives error after trying to opening it :D, so i decided to see throught the painful smali files manually, the first thing i noticed is this app is trying to get the location of the android device based on the latitude and the longitude.In the MainActivity class onCreate function i found something interesting.

waldo1

there's a request url with the parameter "lat" and "long", so i copied the url and try it in the web using random value of "long" and "lat" which i assumed as longitude and latitude , and it's actually a api endpoint. waldo2

so we know how far we're off by, i actually tried brute forcing the value of the latitude and longitude using this script

Script
import requests
import json
lat=5.1735064
lon=90.898947
payload=f"http://challenge.nahamcon.com:30001/location?lat={lat}&long={lon}"

temp=requests.get(payload).text
temp=json.loads(temp)
verdict=temp['message']
dist=temp['off_by']
while verdict=='Waldo is not here!':
	test1=f"http://challenge.nahamcon.com:30001/location?lat={lat-1}&long={lon}"
	test2=f"http://challenge.nahamcon.com:30001/location?lat={lat+1}&long={lon}"
	test3=f"http://challenge.nahamcon.com:30001/location?lat={lat}&long={lon-1}"
	test4=f"http://challenge.nahamcon.com:30001/location?lat={lat}&long={lon+1}"
	test1=requests.get(test1).text
	test2=requests.get(test2).text
	test3=requests.get(test3).text
	test4=requests.get(test4).text
	test1=json.loads(test1)
	test2=json.loads(test2)
	test3=json.loads(test3)
	test4=json.loads(test4)
	if int(test1['off_by'])<int(dist):
		dist=test1['off_by']
		verdict=test1['message']
		lat-=1
	elif int(test2['off_by'])<int(dist):
		dist=test2['off_by']
		verdict=test2['message']
		lat+=1
	elif int(test3['off_by'])<int(dist):
		dist=test3['off_by']
		verdict=test3['message']
		lon-=1
	else:
		dist=test4['off_by']
		verdict=test4['message']
		lon+=1
	print(verdict)
	print(dist)


but maybe it was a bad idea and i didn't find the correct value then i just took the brute force approach and try the points manually and after around 15 minutes i actually managed to find the correct point and the flag

waldo3

flag{eff45e45ecc16922b78d4c3b0776b577n}

Red Light Green Light

we're given another apk red_light_green_light.apk i try to decompile it again using apktool then load it into jadx and i read the MainActivity class source code, and i found the interesting part in the source code

red light1

we actually need the value of red to be false so we can actually access the decryption process, i tried hooking the apk using frida to change the value of red in the checkLight method and it seem i was able to change it?, but when i push the button there's no response so i think maybe i can't do it that way.

Then i noticed something, there's the "Log.w("KEY", getKey());" syntax so i assume that the log.w will print the key when the CheckLight method was called, so i search for a way to hook that log call using frida, and found the script to hook it.

frida.js
Java.perform(function() {
    var Log = Java.use("android.util.Log");
    Log.w.overload('java.lang.String', 'java.lang.String').implementation = function(a, b) {
        console.log("The application reports Log.w(" + a.toString() + ", " + b.toString() + ")");
        return this.w(a, b);
    };

});

now i just need to load the script into frida to hook the method.

red light2

succesfully hooked

red light3

got the key :D

after getting the key, i found the encrypted file in the /res/raw folder, and finally i just need to recreate the decryption scheme just like in the application.

decrypt.py
from Crypto.Cipher import AES
key=b"zxzaKk5uLHdoKo9y8osZSnTe5DCdrIX0"
iv = 16 * b'\x00'
f=open('encrypted','rb').read()
cipher = AES.new(key, AES.MODE_CBC, iv)
cipher_enc = cipher.decrypt(f)
print(cipher_enc)
hasil=open('hasil','wb')
hasil.write(cipher_enc)

after that i got the file and i do binwalk and i found a JPEG file inside so i extracted it using binwalk too

red light4

red light4

flag{29b9edf8fd1e28ea8cd4faa37a6dbf25}

Made with♥️by CCUG Core Team.