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:
Event Notifications: Your app might send a custom broadcast message when a user performs a specific action, such as completing a task.
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.
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:
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.
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:
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'sandroid:priority
attribute. The possible priority values range fromInteger.MIN_VALUE
toInteger.MAX_VALUE
.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)
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.
<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.
<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"
, theMyBroadcastReceiver
class will be triggered to handle the broadcast in itsonReceive()
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)
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 theonReceive
method, as it’s the only method through which you can interact with broadcast receivers.
📌Hacking Broadcast Receiver
Testing
Review
AndroidManifest.xml
forandroid:exported="true"
.Inspect the
onReceive
method for sensitive data or actions.Search for dynamically registered receivers in code using
registerReceiver()
.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:
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")
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 asignature
protection level, this approach will not work.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 tocom.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 usingadb 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 inVulnerableReceiver
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 withadb
: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