BroadcastReceiver

📌What is a Broadcast Receiver?

  • A Broadcast Receiver in Android is a component that listens for system-wide broadcast messages or events, such as when the device is charging, the battery is low, or the internet connection changes. It allows your app to respond to these events, even if the app is not actively running.

  • These broadcast messages are Intent objects that are used to signal events or convey information between different parts of an Android application or even between different applications.

  • Broadcast Receivers can be registered either dynamically (in the Java code) or statically (in the AndroidManifest.xml file).

  • It's some kind of notification system for your applications.

📍System Broadcast VS. Custom Broadcast

  • System Broadcast messages

    • System broadcast messages are sent by the Android system to notify apps about changes in the device’s state or important events.

    • These messages (broadcasts) are predefined by the Android framework using specific Intent actions.

    • Examples:

      • Battery Low (Intent.ACTION_BATTERY_LOW), Screen On/Off (Intent.ACTION_SCREEN_OFF, Intent.ACTION_SCREEN_ON), Device Boot (Intent.ACTION_BOOT_COMPLETED), and so on.

    • As a developer, you can create a Broadcast Receiver in your app to listen for these system broadcast messages and take specific actions when they occur.

  • Custom Broadcast messages

    • Custom broadcast messages are messages that you define within your own app to communicate between different components of your app or, in some cases, between different apps (with restrictions on newer Android versions).

    • These messages are used to share information, trigger actions, or notify other parts of the app about specific events. For example:

      1. Event Notifications: Your app might send a custom broadcast message when a user performs a specific action, such as completing a task.

      2. Data Updates: If your app fetches data from a server, it could send a custom broadcast when new data is available, prompting UI components to update.

      3. Background Tasks: For background tasks, you might send a broadcast when a task finishes, allowing other parts of the app to respond accordingly.

    To use custom broadcast messages, you define a unique action string for each type of message, create an Intent with that action, and then send the intent. On the receiving side, you define a Broadcast Receiver that listens for intents with that specific action.

📍Who can receive the broadcast messages?

  • There are two types of broadcasts that a Broadcast Receiver can receive:

    1. Normal Broadcast: This type of broadcast is delivered to all registered receivers simultaneously, without any defined order. These broadcasts are generally efficient but do not allow modification of the broadcast data.

    2. Ordered Broadcast: This type of broadcast is delivered to one receiver at a time, in the order of their priority. The receiver can modify the broadcast data, set a result code, and even abort the broadcast to prevent other receivers from receiving it.

  • There are two main aspects of broadcast priority:

    1. Priority Level: Broadcast receivers can be assigned a priority level using an integer value. The higher the priority value, the higher the priority of the receiver. The priority value is set when you register a receiver in your app's manifest file using the <receiver> element's android:priority attribute. The possible priority values range from Integer.MIN_VALUE to Integer.MAX_VALUE.

    2. Ordered Broadcasts: When an ordered broadcast is sent, the system sends the broadcast to receivers one by one based on their priority. This means that the receiver with the highest priority receives the broadcast first, followed by receivers with lower priorities. Within the same priority level, the order of registration determines the order of reception.


📍Definition in the AndriodManifest.xml file (outdated approach)

<!-- Declare the BroadcastReceiver -->
        <receiver android:name=".MyBroadcastReceiver" android:enabled="true">
            <intent-filter>
                <!-- Specify the action(s) this receiver listens for -->
                <action android:name="com.example.myapp.CUSTOM_ACTION" />
                <!-- Add more actions if needed -->
            </intent-filter>
        </receiver>
  • Let's break down this code.

    1. <receiver> Element:

      • android:name: Specifies the fully qualified class name of the BroadcastReceiver.

      • android:enabled: Indicates whether the BroadcastReceiver is enabled. Set to "true" to enable it.

    2. <intent-filter> Element:

      • Inside the <intent-filter> element, you define the broadcast actions that this receiver should listen for using <action> elements.

  • When the specified action(s) match the action of a broadcast being sent, the BroadcastReceiver's onReceive() method will be invoked.

  • In our example, if any component sends a broadcast with the action “com.example.myapp.CUSTOM_ACTION", the MyBroadcastReceiver class will be triggered to handle the broadcast in its onReceive() method.

This approach is outdated and should not be used anymore since Android 8. It is better to define it in the Java code.

📍Definition in the java code (up to date)

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // This method is called when the broadcast with the given action is received
        if (intent.getAction().equals("com.example.myapp.CUSTOM_ACTION")) {
            // Handle the received broadcast shows a message to the user
            Toast.makeText(context, "Custom broadcast received!", Toast.LENGTH_SHORT).show();
        }
    }
}

// registerReceiver(reciver_name.new IntentFilter("action_name"));

To identify those broadcast receivers, we need to look into the AndroidManifest.xml. If no broadcast receiver is defined there, it doesn't necessarily mean that the app is not using them. We should also check the Java code and focus on the onReceive method, as it’s the only method through which you can interact with broadcast receivers.


📌Hacking Broadcast Receiver

  • Testing

    1. Review AndroidManifest.xml for android:exported="true".

    2. Inspect the onReceive method for sensitive data or actions.

    3. Search for dynamically registered receivers in code using registerReceiver().

    4. Example AndroidManifest.xml:

      <receiver android:exported="true" android:name=".myBroadcastReceiver">
          <intent-filter>
              <action android:name="com.apphacking.broadcastreceiver.alarmState" />
          </intent-filter>
      </receiver>

📌Exploitation

  • Most broadcast receivers are being exported to the outside world, which might make them vulnerable to attacks.

  • To identify broadcast receivers, we need to look into the Android Manifest XML file or Java code, depending on the SDK version. Then, we can determine the action name and what happens in the onReceive method.

  • There are various ways to exploit Broadcast Receivers, such as:

    1. Sensitive Data Exposure: Since broadcast messages are sent using intents, the sending app may unintentionally include sensitive data in the message. For example:

      intent.putExtraString("token=f03a-19b5-a9cd-4b8d")
    2. Permission Manipulation: If the developer has applied permissions to broadcast messages, you may be able to bypass these if they use custom permission by adding the <uses-permission> tag in your manifest file. However, if the permission uses a signature protection level, this approach will not work.

    3. Local Broadcasts: The LocalBroadcastManager class is used for sending information within the same app only, so it doesn’t impact other apps and is generally not a concern for external exploitation.

đź’ˇ Remember to review the noReceive() method in the Java code to understand which conditions or triggers activate the broadcast.

📍Examples

  • Example 1: Exploiting a Broadcast Receiver Declared in AndroidManifest.xml

    • Suppose there’s a broadcast receiver in AndroidManifest.xml that listens to com.example.app.VULNERABLE_ACTION:

      <receiver android:name=".VulnerableReceiver"
                android:exported="true"> <!-- Receiver is exported -->
          <intent-filter>
              <action android:name="com.example.app.VULNERABLE_ACTION" />
          </intent-filter>
      </receiver>
    • Since android:exported="true" makes the receiver accessible to other apps, you can send a broadcast to trigger this receiver using adb shell.

    • Exploit using adb shell

      adb shell am broadcast -a com.example.app.VULNERABLE_ACTION
    • This command sends a broadcast with the action com.example.app.VULNERABLE_ACTION. If the broadcast receiver in VulnerableReceiver performs sensitive actions without security checks, this broadcast can trigger those actions, which could lead to unintended behavior.

  • Example 2: Exploiting a Dynamically Registered Broadcast Receiver

    • If a broadcast receiver is registered dynamically in Java code without security checks (like permissions), you can similarly exploit it by using **adb shel**l.

    • Java Code Example

      public class MainActivity extends AppCompatActivity {
          private BroadcastReceiver vulnerableReceiver = new BroadcastReceiver() {
              @Override
              public void onReceive(Context context, Intent intent) {
                  // Vulnerable code execution here
              }
          };
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              // Registering without permissions
              IntentFilter filter = new IntentFilter("com.example.app.DYNAMIC_ACTION");
              registerReceiver(vulnerableReceiver, filter);
          }
      }
    • If this receiver listens for com.example.app.DYNAMIC_ACTION and does not enforce any security restrictions, you can send a broadcast with adb:

      adb shell am broadcast -a com.example.app.DYNAMIC_ACTION
    • This command will trigger vulnerableReceiver in the app, and if it performs any critical tasks, they could be exploited.


Last updated