HTB | Supermarket
Machine - https://app.hackthebox.com/challenges/Supermarket
File - Supermarket.apk
Description - My supermarket list is too big and I only have $50. Can you help me get the Discount code?
Skill Learned
Android Reverse Engineering.
Reading decompiled Java code.
Enumeration
Running the application

Analyzing the Source code
We have found a class textWatcher
which have an onTextChanged
the function which is responsible for decrypting and checking the discount code:
String obj = MainActivity.this.f2075q.getText().toString();
- Retrieves the text input from a UI element (likely anEditText
).stringFromJNI()
seems to return a Base64-encoded encrypted string.A secret key is constructed from
stringFromJNI2()
and cipher type fromstringFromJNI3()
.The cipher is initialized in decrypt mode (mode
2
).if (!obj.equals(new String(cipher.doFinal(Base64.decode(stringFromJNI, 0)), "utf-8")))
Decrypts the encrypted string and compares it to the user input.
If it doesn't match, a list is filled from
this.f2085c
, and a variablef2076r
is set to5.0d
.If it matches, the list is filled from
this.f2084b
, andf2076r
is set to2.5d
.
So if we get the encrypted string, we can get the discount code (maybe ?)

There is another onCreate which is responsible for all the calculations we see on the UI/ front end

Decompiling and analyzing a native library
We can see that the libsupermarket.so
is being loaded
static {
System.loadLibrary("supermarket");
}
We can also see the methods stringFromJNI()
, stringFromJNI2()
, and stringFromJNI3()
, which are native method calls defined in Java, typically using JNI (Java Native Interface), and implemented in native code — usually C or C++
String stringFromJNI = mainActivity.stringFromJNI(); // Encrypted base64 string
SecretKeySpec secretKeySpec = new SecretKeySpec(mainActivity.stringFromJNI2().getBytes(), mainActivity.stringFromJNI3());
Cipher cipher = Cipher.getInstance(mainActivity.stringFromJNI3());
stringFromJNI()
Returns a Base64-encoded string — probably encrypted data (maybe the correct discount code).
stringFromJNI2()
Returns the encryption key (used to create SecretKeySpec
).
stringFromJNI3()
Returns the cipher algorithm string, e.g., "AES"
or "AES/CBC/PKCS5Padding"
— used in Cipher.getInstance(...)
.
Now we need to reverse the libsupermarket.so
and find all three functions.
For this purpose, we will load the libsupermarket.so
in the Ghidra tool
Analyzing the libsupermarket.so
We can see the three functions

stringFromJNI()
We can see that it is doing some logic and returning the value (probably encrypted discount code)

stringFromJNI2()
Same as stringFromJNI() it is also doing some logic and math and returning the variable (probably encryption key)

stringFromJNI3()
Same as stringFromJNI() it is also doing some logic and math and returning the variable (probably Cipher encryption algorithm)

Exploiting the APK
Frida
We can use Frida to hook the functions and get what is being returned
Java.perform(function () {
var myActivity = Java.use("com.example.supermarket.MainActivity");
Java.choose("com.example.supermarket.MainActivity", {
onMatch: function (instance) {
let JNI = instance.stringFromJNI();
let JNI2 = instance.stringFromJNI2();
let JNI3 = instance.stringFromJNI3();
console.log("JNI: " + JNI);
console.log("JNI2: " + JNI2);
console.log("JNI3: " + JNI3);
},
onComplete: function () {
console.log("Search complete.");
},
});
});
We found encrypted text(discount code ?), key and cipher algorithm

Now, to crack this, we will use online AES decryption, and we got the flag

Last updated