- 文档
- 教程
- 网络安全
【免费下载链接】mastg
The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.
MASTG-DEMO-0136 是 OWASP MASTG 仓库中一个刻意构造的反面教材:一个 Android 应用通过setAction("org.owasp.mastestapp.INTERNAL_ACTION")发送隐式 Intent来启动自己的内部 Activity,并把user_id、session_token等敏感数据放进 Intent extras。本文将以该样本为主体,完整拆解不安全实现、Android 的 Intent 解析机制、基于 semgrep 规则的静态检测流程、测试判定逻辑(MASTG-TEST-0372),以及最终改用显式 Intent 的修复方案(MASTG-BEST-0056),让读者掌握"内部通信必须显式指定目标组件/包名"这一 Android 安全红线及其可落地的检测手段。
一、背景知识:显式 Intent 与隐式 Intent 的本质区别
要理解这个样本为什么"不安全",首先要明确 Android 中两种 Intent 的根本差异。仓库中的知识文档 MASTG-KNOW-0025 给出了精确定义:
- 显式 Intent(Explicit Intent):直接指定处理该 Intent 的目标应用包名或完整组件类名。调用方明确知道目标 Activity/Service 是谁,因此 Intent 只会被送达这一个组件。典型写法为
Intent(context, DownloadActivity::class.java)。 - 隐式 Intent(Implicit Intent):不指名任何具体组件,只声明 action(以及可选的 data、category)。系统需要把 Intent 与所有已安装应用中声明了
<intent-filter>的组件进行意图解析(Intent Resolution),匹配结果才决定最终投递给谁。
Intent 解析的匹配规则
当系统收到一个隐式 Intent 时,会按照文档中描述的解析算法逐项比较:
| 匹配维度 | 规则 |
|---|---|
| Action | <intent-filter>必须声明与 Intent 完全相同的 action 字符串 |
| Category | Intent 中的全部 category 必须出现在 filter 中;filter 可额外声明更多 category |
| Data | URI 的 scheme、host、path 以及 MIME type 必须满足 filter 中<data>的约束 |
匹配结果分两种情况:若只有一个组件命中,系统直接把 Intent 路由过去;若命中多个组件,系统会弹出 chooser(应用选择器/歧义对话框)让用户挑选,或遵循已设置的默认处理器。这正是隐式 Intent 内部通信的致命漏洞所在——任何第三方应用只要声明一个匹配的<intent-filter>,就会成为候选接收方。
此外,MASTG-KNOW-0025 还记录了一个重要的平台演进事实:当应用以 Android 14(API level 34)及以上为目标平台时,系统保证隐式 Intent永远不会投递给应用的内部组件,这迫使开发者必须为内部通信实现显式 Intent,否则应用自身功能都无法正常工作。
二、样本剖析:不安全实现的完整代码全貌
MASTG-DEMO-0136 样本位于 demos/android/MASVS-CODE/MASTG-DEMO-0136/,由 Kotlin 源码、Manifest、反编译 Java、检测脚本与输出五部分组成。
2.1 Kotlin 源码:隐式 Intent 发起内部通信
MastgTest.kt 是样本的核心。它先构造一个没有任何目标组件信息的空Intent,仅通过setAction指定自定义 action,再塞入两个敏感 extras,最后以context.startActivity(implicitIntent)派发:
package org.owasp.mastestapp import android.content.Context import android.content.Intent // SUMMARY: This sample demonstrates the insecure use of implicit intents for internal communication. class MastgTest (private val context: Context){ fun mastgTest(): String { val r = DemoResults("0x01") // FAIL: [MASTG-TEST-0372] The app uses an implicit intent to start an internal activity. val implicitIntent = Intent().apply { action = "org.owasp.mastestapp.INTERNAL_ACTION" putExtra("user_id", "12345") putExtra("session_token", "abcde-fghij-12345") addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } try { context.startActivity(implicitIntent) r.add(Status.FAIL, "Launched internal activity via implicit intent") } catch (e: Exception) { r.add(Status.ERROR, e.toString()) } /* // PASS: [MASTG-TEST-0372] The app uses an explicit intent for internal communication. val explicitIntent = Intent(context, InternalActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } try { context.startActivity(explicitIntent) r.add(Status.PASS, "Launched internal activity via explicit intent") } catch (e: Exception) { r.add(Status.ERROR, e.toString()) } */ return r.toJson() } }代码中有几个值得注意的细节:
- Intent 构造方式:
Intent()空构造 +setAction,没有setPackage、setClass、setComponent或Intent(context, Class)构造函数,因此从意图解析的角度看,它没有任何"目标限定"。 - 敏感 extras:
user_id与session_token被直接放进 extras。一旦 Intent 被第三方应用接收,这些数据将完整泄露给攻击者。 - FLAG_ACTIVITY_NEW_TASK:由于该示例在非 Activity 上下文中启动 Activity,需要此 flag(对应十进制值
268435456,即0x10000000)来在新任务栈中启动目标。 - 对照修复代码:源码中注释保留了一段 PASS 分支,展示正确写法——
Intent(context, InternalActivity::class.java)显式指定目标类。
同一文件末尾还定义了目标组件InternalActivity,一个仅显示 "Internal Activity" 文本的极简 Activity:
class InternalActivity : android.app.Activity() { override fun onCreate(savedInstanceState: android.os.Bundle?) { super.onCreate(savedInstanceState) val textView = android.widget.TextView(this) textView.text = "Internal Activity" textView.textSize = 24f textView.gravity = android.view.Gravity.CENTER setContentView(textView) } }2.2 Manifest:内部组件对外暴露的关键开关
AndroidManifest.xml 揭示了问题成立的第二个条件——InternalActivity被声明为android:exported="true"且带有匹配自定义 action 的<intent-filter>:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application> <activity android:name="org.owasp.mastestapp.MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- Internal activity with an intent-filter, making it a resolver candidate --> <activity android:name="org.owasp.mastestapp.InternalActivity" android:exported="true"> <intent-filter> <action android:name="org.owasp.mastestapp.INTERNAL_ACTION" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>这里的组合十分微妙:InternalActivity本意是"内部"组件,却同时满足了两个使它"外部可达"的条件——exported="true"允许其他应用直接启动它,而<intent-filter>使它可以作为隐式 Intent 的解析候选。也就是说,它既能接收本应用发出的隐式 Intent,也完全能被其他应用发出的同 action 隐式 Intent 命中。整个场景构成了双向的暴露面。
2.3 反编译视角:恶意分析者眼中的样子
AndroidManifest_reversed.xml 是 APK 反编译后的完整 Manifest,补充了样本的编译环境信息(compileSdkVersion="35"、minSdkVersion="29"、targetSdkVersion="35"),并确认InternalActivity的android:exported="true"与 intent-filter 在打包后原样保留。而 MastgTest_reversed.java 是 Kotlin 反编译回 Java 的产物,展示了恶意分析者实际会看到的形态:
public final String mastgTest() { DemoResults r = new DemoResults("0x01"); Intent implicitIntent = new Intent(); implicitIntent.setAction("org.owasp.mastestapp.INTERNAL_ACTION"); implicitIntent.putExtra("user_id", "12345"); implicitIntent.putExtra("session_token", "abcde-fghij-12345"); implicitIntent.addFlags(268435456); try { this.context.startActivity(implicitIntent); r.add(Status.FAIL, "Launched internal activity via implicit intent"); } catch (Exception e) { r.add(Status.ERROR, e.toString()); } return r.toJson(); }反编译代码把漏洞特征暴露得更加直白:new Intent()之后只有setAction与putExtra,从头到尾没有任何一次调用把 Intent 绑定到具体目标。addFlags(268435456)即前文提到的FLAG_ACTIVITY_NEW_TASK。这正是静态扫描工具最理想的检测目标——代码模式高度可识别。
三、风险机理:为什么隐式内部通信是危险的
结合 MASTG-TEST-0372 的说明,这个样本的危害链条可以总结为三步:
- 本应用发出隐式 Intent:action 为
org.owasp.mastestapp.INTERNAL_ACTION,携带user_id、session_token等敏感 extras,未指定目标包名或组件。 - 第三方应用声明匹配
<intent-filter>:任何恶意应用都能在自己的 Manifest 中声明同样的 action,从而在 Android 意图解析阶段与本应用的InternalActivity一起成为候选。 - Intent 被劫持或泄露:若系统弹出 chooser,用户可能误选第三方应用;若该 action 仅有恶意应用一个匹配项(或已被设为默认处理器),Intent 会未经用户明确决策直接送达攻击者,extras 中的令牌与凭据随之泄露。
需要特别强调的是,这个漏洞并不依赖本应用的目标组件是否 exported——即使InternalActivity保持 exported,攻击面在于接收方可以换人:Intent 是"广播式"地被解析,谁匹配谁接收,而 app-specific 的自定义 action 并不具备任何保密性。测试文档明确将startActivity、startActivityForResult、ActivityResultLauncher.launch、startService、bindService、sendBroadcast等全部列为需要排查的派发 API,凡是"内部或可信组件间通信却未指名接收者"的 Intent 都在违规之列。
四、静态检测实战:semgrep 规则扫描反编译代码
样本配套提供了开箱即用的检测链路:先反编译拿到 Java 代码,再用 semgrep 规则扫描。对应的仓库资源为静态分析技术 MASTG-TECH-0014 与规则工具 MASTG-TOOL-0110。
4.1 检测脚本
run.sh 只有一行核心命令,直接对反编译得到的MastgTest_reversed.java运行规则并捕获输出:
#!/bin/bash # SUMMARY: This script uses semgrep to detect implicit intents in the source code. NO_COLOR=true semgrep --config ../../../../rules/mastg-android-implicit-intent-internal-communication.yml MastgTest_reversed.java --text > output.txt参数含义:NO_COLOR=true关闭彩色输出以方便落盘;--config指向仓库根目录下的 mastg-android-implicit-intent-internal-communication.yml;--text以纯文本格式输出;结果重定向到output.txt。实际测试时把MastgTest_reversed.java换成任意待测反编译文件即可复用。
4.2 规则解析:三个正模式与三个反模式
这条 semgrep 规则是整个检测方案的灵魂,它用一个命中模式 + 三个排除模式精确刻画"隐式 Intent 内部通信":
rules: - id: mastg-android-implicit-intent-internal-communication patterns: - pattern: | $INTENT = new Intent(...); ... $INTENT.setAction($ACTION); ... $CONTEXT.startActivity($INTENT); - pattern-not: | $INTENT = new Intent(...); ... $INTENT.setPackage(...); ... $CONTEXT.startActivity($INTENT); - pattern-not: | $INTENT = new Intent(...); ... $INTENT.setComponent(...); ... $CONTEXT.startActivity($INTENT); - pattern-not: | $INTENT = new Intent($CONTEXT, $CLASS); ... $CONTEXT.startActivity($INTENT); message: "[MASVS-CODE-4] The app uses an implicit intent for internal component communication. Use explicit intents by specifying the package or component." languages: [java] severity: WARNING metadata: summary: Detects implicit intents used for internal component communication without specifying a package or component.规则的设计逻辑非常清晰:
- 正模式:
new Intent(...)创建 →setAction(...)指定 action →startActivity(...)派发,构成隐式 Intent 的完整生命周期;...表示中间允许任意代码,因此putExtra、addFlags等调用不影响匹配。 - 反模式 1:
setPackage(...)—— 一旦按包名限定目标,Intent 只能投递到该包内组件,即显式化。 - 反模式 2:
setComponent(...)—— 按组件名限定目标,同样显式化。 - 反模式 3:
Intent($CONTEXT, $CLASS)构造函数 —— 直接在构造时指定目标类,这是最严格的显式形式。
也就是说,只有当"创建 → 设 action → 派发"完整出现且没有任何目标限定调用时,规则才报出告警,有效避免了大量显式 Intent 的误报。告警级别为 WARNING,归属于 MASVS-CODE-4(代码质量与构建配置类问题),声明的语言为 Java——这正是反编译产物的形态。
4.3 结果解读
output.txt 记录了真实扫描结果,共命中1 处代码发现:
┌────────────────┐ │ 1 Code Finding │ └────────────────┘ MastgTest_reversed.java ❯❱ rules.mastg-android-implicit-intent-internal-communication [MASVS-CODE-4] The app uses an implicit intent for internal component communication. Use explicit intents by specifying the package or component. 22┆ Intent implicitIntent = new Intent(); 23┆ implicitIntent.setAction("org.owasp.mastestapp.INTERNAL_ACTION"); 24┆ implicitIntent.putExtra("user_id", "12345"); 25┆ implicitIntent.putExtra("session_token", "abcde-fghij-12345"); 26┆ implicitIntent.addFlags(268435456); 27┆ try { 28┆ this.context.startActivity(implicitIntent); 29┆ r.add(Status.FAIL, "Launched internal activity via implicit intent"); 30┆ } catch (Exception e) { 31┆ r.add(Status.ERROR, e.toString()); 32┆ } [hid 1 additional lines, adjust with --max-lines-per-finding]告警精确地锚定在第 22–28 行,把隐式 Intent 的完整构造与派发链(new Intent()→setAction→ 两个putExtra→startActivity)一行不漏地呈现给分析人员,报告中的关键要素与样本文档的观察结论完全一致:
- Intent 创建:
new Intent(); - Action 赋值:
implicitIntent.setAction("org.owasp.mastestapp.INTERNAL_ACTION"); - 派发前加入的 extras:
user_id与session_token; - 派发 API:
this.context.startActivity(implicitIntent); - 缺少目标限定:整段代码中没有
setPackage、setClass、setClassName、setComponent或显式Intent(context, Class)构造函数。
这条检测链路可以无缝移植到真实项目:对任意 APK 先做反编译(对应技术 MASTG-TECH-0013),再对全部反编译 Java 文件运行该规则,即可批量发现内部通信误用隐式 Intent 的代码点。
五、测试判定:MASTG-TEST-0372 为何判 Fail
本样本对应测试用例 MASTG-TEST-0372(Implicit Intents Used for Internal App Communication),元数据标记为type: [static, code, manual],关联弱点枚举MASWE-0032,并分别关联最佳实践 MASTG-BEST-0056 与知识条目 MASTG-KNOW-0025。
根据测试的判定标准:若用于应用内部或可信组件通信的 Intent 是隐式的,且其他应用可以声明或注册匹配组件来接收它,则测试失败。在本样本中:
- action
org.owasp.mastestapp.INTERNAL_ACTION虽为应用自定义,InternalActivity也在 Manifest 中被声明为预期处理者; - 但报告出的派发点没有命名该组件,也没有限定目标包;
- 其他应用完全可以通过声明匹配的
<intent-filter>成为 Android 意图解析的候选。
因此样本文档 MASTG-DEMO-0136.md 明确判定该用例Fail,对应源码注释也标记为FAIL: [MASTG-TEST-0372]。
此外,测试文档还给出了进一步人工验证的要求(配合 MASTG-TECH-0023 逐一检查报告位置):
- 检查 Intent 是否已带显式组件或包名;
- 检查其他应用是否能为该 action、data、categories 声明或注册匹配的
<intent-filter>; - 对于广播,检查发送方是否要求了可阻止不可信接收者的权限;
- 确认该 Intent 是面向应用自身组件或可信应用,而非有意交给用户选择的外部应用。
其中第 2、4 条正是本样本 Fail 的直接依据——它面向自身InternalActivity,却给了外部应用插手的余地。
六、修复方案:改用显式 Intent(MASTG-BEST-0056)
正确的修复方向在源码的 PASS 注释分支里已经给出,最佳实践 MASTG-BEST-0056 则提供了完整规范:同应用内部组件间通信一律使用显式 Intent——显式指定目标组件后,Intent 只能送达预期接收者,第三方应用无法通过正常意图解析截获。
6.1 Java/Kotlin 侧修复
// Explicit by package - restricts delivery to your own app val intent = Intent("com.example.app.PROCESS_DATA").apply { setPackage("com.example.app") putExtra("key", "value") } startActivity(intent) // Explicit by component - the most restrictive form val intent = Intent(context, TargetActivity::class.java).apply { putExtra("key", "value") } startActivity(intent)两种显式写法按限制强度递增:setPackage("com.example.app")把投递范围锁死在本应用包内(即使其他应用声明了同 action 的 filter 也无法接收);Intent(context, TargetActivity::class.java)则直接指名目标类,是最严格的形式。回到本样本,只需把Intent().apply { action = ... }替换为Intent(context, InternalActivity::class.java)即可消除漏洞,同时照常携带 extras 与FLAG_ACTIVITY_NEW_TASK。
最佳实践还特别强调了一条铁律:绝不要把敏感数据(令牌、凭据、API Key)放进隐式 Intent。Android 通过匹配已安装应用声明<intent-filter>的方式解析隐式 Intent,任何匹配应用都可能成为最终接收者并读到 extras——这正是本样本中user_id、session_token面临的处境。
6.2 Manifest 侧加固
对于内部组件,还需确保它们没有被无意中暴露给其他应用。样本中InternalActivity的exported="true"加上 intent-filter 属于典型的多余暴露——如果组件只供本应用使用,应移除 intent-filter 并将exported设为false;关于 Manifest 更系统的加固细节,MASTG-BEST-0056 指向了专门条目 MASTG-BEST-0052 进行展开(见 best-practices 目录)。
七、对照攻击样本:MASTG-DEMO-0140 的接管演示
为完整呈现威胁,仓库还配套提供了攻击方视角的对照样本 MASTG-DEMO-0140:该演示应用在自己的 Manifest 中声明了与org.owasp.mastestapp.INTERNAL_ACTION匹配的<intent-filter>,从而成为本样本隐式 Intent 的解析候选。二者配套阅读可以直观验证"另一个应用如何成为处理者候选"的完整过程——这也是本样本文档中的 note 明确指引的实验路径。图 1 展示的就是这一时刻系统弹出的应用选择器界面。
八、关联资源索引
围绕本主题,仓库中可继续深入阅读的材料(均以仓库根目录为起点的相对路径):
- 样本文档:demos/android/MASVS-CODE/MASTG-DEMO-0136/MASTG-DEMO-0136.md
- 源码与反编译产物:MastgTest.kt、MastgTest_reversed.java、AndroidManifest.xml、AndroidManifest_reversed.xml
- 检测脚本与结果:run.sh、output.txt
- semgrep 规则:rules/mastg-android-implicit-intent-internal-communication.yml
- 测试用例:tests-beta/android/MASVS-CODE/MASTG-TEST-0372.md
- 最佳实践:best-practices/MASTG-BEST-0056.md
- 背景知识:knowledge/android/MASVS-PLATFORM/MASTG-KNOW-0025.md
- 攻击对照样本:demos/android/MASVS-CODE/MASTG-DEMO-0140/MASTG-DEMO-0140.md
总结而言,MASTG-DEMO-0136 用最小化的代码演示了"内部通信隐式化"这一常见且高危的 Android 反模式:显式 Intent 是内部 IPC 的默认选项,setPackage/setComponent/组件构造器是强制约束手段,而 semgrep 规则 + 反编译产物扫描则提供了一条低成本、可自动化的持续检测路径。对照攻击样本、测试用例与最佳实践,读者可以在此样本基础上形成完整的"发现—判定—修复—验证"闭环能力。
- 文档
- 教程
- 网络安全
【免费下载链接】mastg
The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.
相关推荐
用 semgrep 揪出 Android 隐式 Intent 泄漏:OWASP MASTG MASTG-DEMO-0138 实战指南
用 semgrep 揪出 Android 隐式 Intent 泄漏:OWASP MASTG MASTG DEMO 0138 实战指南 本篇技术指南聚焦 OWAS
文档教程网络安全OWASP MASTG 实战:Android 内部存储明文敏感数据检测(MASTG-DEMO-0010 / MASTG-TEST-0207)
OWASP MASTG 实战:Android 内部存储明文敏感数据检测(MASTG DEMO 0010 / MASTG TEST 0207) 导读 本文以 OW
文档教程网络安全OWASP MASTG 最佳实践:Android 内部 IPC 必须使用显式 Intent(MASTG-BEST-0056)
OWASP MASTG 最佳实践:Android 内部 IPC 必须使用显式 Intent(MASTG BEST 0056) 导读 本文是 OWASP Mobi
文档教程网络安全
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考