Android Broadcast Security
0x00 Popular Science
Broadcast Recevier is a component that focuses on receiving and processing Broadcast notifications. Many broadcasts originate from system code, such as notifying time zone changes, low battery, taking a picture, or changing language options. Applications can also be broadcast-for example, to notify other applications that some data has been downloaded and is available. An application can have any number of broadcast receivers to respond to all notifications that interest it. All receivers inherit from the BroadcastReceiver base class. The broadcast receiver has no user interface. However, they can start an activity to respond to the information they receive, or use icationicationmanager to notify users. Notifications can be used in many ways to attract users' attention-flashing back lights, vibrations, and playing sounds. In general, a persistent icon is placed on the status bar. You can open it and get the message.
0x01 knowledge points
Registration Form: dynamic or static
The name attribute of the element specifies the subclass of the activity that implements the Activity. The icon and label attributes point to the resource file that contains the icons and labels of the activity displayed to the user. Other components are declared in a similar way -- An element is used to declare a service, Element is used to declare the broadcast receiver, and The element is used to declare the content provider. Activities, services, and content providers that are not declared in the manifest file will not be seen by the system and thus will not be run. However, the broadcast receiver can be declared in the manifest file or dynamically created in the Code and registered to the system by calling Context. registerReceiver.
(Differences between static and dynamic register broadcast receivers)
Callback Method
The broadcast receiver has only one callback method:
void onReceive(Context curContext, Intent broadcastMsg)
When a broadcast message arrives at the receiver, Android calls its onReceive () method and passes the Intent object containing the message to it. The broadcast receiver is active only when it executes this method. When onReceive () is returned, it is inactive. A process with an active broadcast receiver is protected and not killed. However, a process that only has an inactive component will be killed at any time when other processes need the memory occupied by it. This method leads to a problem: if it takes a long time to respond to a broadcast information, we generally include it in a derived thread to complete it, rather than completing it within the main thread, this ensures smooth user interaction. If onReceive () derives a thread and returns it, the whole process, including the new thread, will be regarded as inactive (unless other application components in the process are still active ), so it may be killed. The solution to this problem is to enable onReceive () to start a new service and use it to complete the task, so the system will know that the process is still working.
Permission
Set the receiving app
Intent setPackage(String packageName)(Usually optional) Set an explicit application package name that limits the components this Intent will resolve to.
Set the receiving permission
abstract void sendBroadcast(Intent intent, String receiverPermission)Broadcast the given intent to all interested BroadcastReceivers, allowing an optional required permission to be enforced.
ProtectionLevel
Normal: default value. Low-risk permissions, which can be used as long as they are applied for. You do not need to confirm the installation.
Dangerous: permissions such as WRITE_SETTING and SEND_SMS are risky because these permissions can be used to reconfigure the device or cause a call charge. Use this protectionLevel to identify some permissions that users may be concerned. Android will warn users about these permission requirements when installing the program. The specific behavior may vary depending on the Android version or the installed mobile device.
Signature: these permissions are only granted to programs that are signed with the same key as the application.
SignatureOrSystem: similar to signature, programs in the system also need to be accessible. This allows custom Android applications to gain permissions. This protection level helps the compilation process of the integrated system.
Broadcast type
System broadcast: when an event such as startup, SMS, or low battery usage occurs, the system sends a specific broadcast to notify the application, after an application receives a broadcast, it will send it to the user in some form.
Custom broadcast: Unlike System broadcast events, an application can customize a broadcast event for its own broadcast receiver.
Ordered Broadcast
OrderedBroadcast-ordered Broadcast and Broadcast-normal Broadcast. The difference is that after an ordered Broadcast is sent, the receiver that can adapt to the Broadcast receives the Broadcast in a certain order of permission, in addition, the previous receiver can modify the content of the broadcast. The modified result is received by the later receiver, and the receiver with a higher priority can end the broadcast, the receiver with lower priority will not be able to receive the broadcast. After a normal broadcast is sent, the receiver that can adapt does not receive the broadcast in a certain sequence, nor can it terminate the broadcast.
Sticky broadcast
This broadcast is not discarded but stored in AMS after it is sent and distributed to the corresponding receiver through AMS (ActivityManagerService, when a new consumer request for AMS registration needs to be dynamically registered, if the consumer can receive this broadcast, AMS will immediately send this broadcast to the consumer after the consumer registration is successful. This type of broadcast is called stickybroadcast.
SendStickyBroadcast () literally means to send a sticky broadcast. To use this api, you need permission for android. manifest. permission. BROADCAST_STICKY: The sticky broadcast feature that Intent will be retained until the broadcast event ends, and this broadcast has no so-called 10-second limit, the 10-second limit refers to the normal broadcast. If the onReceive method is executed for too long, the system will set the broadcast to the candidate that can be killed when the system resources are insufficient, the broadcast will be killed so that it will not be executed.
(Broadcast features)
Change
Broadcast receivers of android3.1 and later versions cannot be registered before the application is started. You can set the flag of intent to Intent. FLAG_INCLUDE_STOPPED_PACKAGES to send the broadcast to the broadcast receiver that has not started the application.
Key Methods
SendBroadcast (intent) sendOrderedBroadcast (intent, null, empty, null, null) onReceive (Context context, Intent intent) getResultData () abortBroadcast () registerReceiver () unregisterReceiver () localBroadcastManager. getInstance (this ). sendBroadcast (intent) sendStickyBroadcast (intent) 0x02 category
Private broadcast receiver: only receives the broadcast public broadcast receiver sent by the app itself: can receive the broadcast internal broadcast receiver sent by all apps: only receives the broadcast sent by the internal app
Security suggestions
Recommended combination of intent-filter nodes and exported attribute settings
The private broadcast receiver is set to exported = 'false', and intent-filter is not configured. (The private broadcast receiver can still receive broadcasts with the same UID)
<receiver android:name=".PrivateReceiver" android:exported="false" />
Verify the received broadcast.
Use protectionLevel = 'signature' to verify whether an internal app is broadcast between internal apps.
When returning results, pay attention to whether the received app will leak information.
When the sent broadcast contains sensitive information, you must specify the broadcast receiver to use the explicit or
setPackage(String packageName)
Sticky broadcast should not contain sensitive information
Ordered Broadcast recommends setting the receiving permission receiverPermission to prevent malicious applications from setting a high priority to accept this Broadcast and then execute the abortBroadcast () method.
0x03 Test Method
1. Search for dynamic broadcast receivers: retrieve registerReceiver () after decompiling (),
dz> run app.broadcast.info -a android -i
2. Search for static broadcast receivers: view the configuration file after decompiling to find the broadcast Receiver component Note the exported attribute.
3. Search for information in the sending broadcast to retrieve sendBroadcast and sendOrderedBroadcast. Note that the setPackage method is in the receiverPermission variable.
Send test broadcast
adb shell:am broadcast -a MyBroadcast -n com.isi.vul_broadcastreceiver/.MyBroadCastReceiveram broadcast -a MyBroadcast -n com.isi.vul_broadcastreceiver/.MyBroadCastReceiver –es number 5556. drozer:dz> run app.broadcast.send --component com.package.name --action android.intent.action.XXX code:Intent i = new Intent();ComponentName componetName = new ComponentName(packagename, componet); i.setComponent(componetName); sendBroadcast(i);
Receives a specified broadcast
public class Receiver extends BroadcastReceiver { private final String ACCOUNT_NAME = "account_name"; private final String ACCOUNT_PWD = "account_password"; private final String ACCOUNT_TYPE = "account_type"; private void doLog(Context paramContext, Intent paramIntent) { String name; String password; String type; do { name = paramIntent.getExtras().getString(ACCOUNT_NAME); password = paramIntent.getExtras().getString(ACCOUNT_PWD); type = paramIntent.getExtras().getString(ACCOUNT_TYPE); } while ((TextUtils.isEmpty(name)) || (TextUtils.isEmpty(password)) || (TextUtils.isEmpty(type)) || ((!type.equals("email")) && (!type.equals("cellphone")))); Log.i("name", name); Log.i("password", password); Log.i("type", type); } public void onReceive(Context paramContext, Intent paramIntent) { if (TextUtils.equals(paramIntent.getAction(), "account")) doLog(paramContext, paramIntent); } }
0x04 case
Case: Sensitive Information Leakage
An application uses the Broadcast Transmission User Account Password
Send Sensitive Information implicitly
public class ServerService extends Service { // ... private void d() { // ... Intent v1 = new Intent(); v1.setAction("com.sample.action.server_running"); v1.putExtra("local_ip", v0.h); v1.putExtra("port", v0.i); v1.putExtra("code", v0.g); v1.putExtra("connected", v0.s); v1.putExtra("pwd_predefined", v0.r); if (!TextUtils.isEmpty(v0.t)) { v1.putExtra("connected_usr", v0.t); } } this.sendBroadcast(v1);}
Receive POC
public class BcReceiv extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent){ String s = null; if (intent.getAction().equals("com.sample.action.server_running")){ String pwd = intent.getStringExtra("connected"); s = "Airdroid => [" + pwd + "]/" + intent.getExtras(); } Toast.makeText(context, String.format("%s Received", s), Toast.LENGTH_SHORT).show(); }}
After the code is fixed, broadcasts sent using LocalBroadcastManager. sendBroadcast () can only be received by the app's own broadcast receiver.
Intent intent = new Intent("my-sensitive-event");intent.putExtra("event", "this is a test event");LocalBroadcastManager.getInstance(this).sendBroadcast(intent);