ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

使用 Semgrep 检测 Android 应用绕过作用域存储写入外部存储的漏洞:MASTG-DEMO-0003 实战指南

使用 Semgrep 检测 Android 应用绕过作用域存储写入外部存储的漏洞:MASTG-DEMO-0003 实战指南 文档教程网络安全【免费下载链接】mastgThe 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.项目地址https://gitcode.com/gh_mirrors/ow/mastg点击查看免费下载本文基于 OWASP MASTGMobile Application Security Testing Guide仓库中的MASTG-DEMO-0003示例完整演示如何通过静态分析Semgrep 规则扫描识别 Android 应用绕开 Scoped Storage作用域存储限制、向共享外部存储写入未加密敏感数据的漏洞。读完本文你将掌握MANAGE_EXTERNAL_STORAGE权限的声明方式与风险、Environment#getExternalStorageDirectory等遗留 API 的判别方法以及如何在反编译产物上运行 MASTG 官方规则并依据输出定位与评估安全测试用例。背景外部存储与 Scoped Storage 之争从 Android 10API 29开始系统强制推行 Scoped Storage作用域存储应用只能无额外权限地访问自己专属的目录如getExternalFilesDir返回的路径以及通过MediaStore访问媒体集合不能再随意向共享外部存储根目录写入文件。然而Android 11API 30引入了 All files access所有文件访问特殊权限应用只要在清单中声明MANAGE_EXTERNAL_STORAGE并经用户在系统设置中手动授予后就可以继续使用Environment.getExternalStorageDirectory()这类遗留 API直接向/storage/emulated/0这样的共享存储根目录写入文件。这种做法的安全风险在于共享外部存储中的文件对所有具备存储读取权限的应用可见任何文件一旦以明文落盘就等于把数据暴露给了同设备上的其他应用。这正是 MASTG-TEST-0202对应 MASWE-0002所关注的弱点应用引用外部存储 API 与相关权限且将敏感数据未加密写入共享存储。MASTG-DEMO-0003正是该测试用例的可复现示例一个刻意编写了漏洞的测试应用一段反编译后的 Java 代码两份 Android 清单文件以及两套 Semgrep 规则与运行脚本完整呈现写代码 → 反编译 → 规则扫描 → 定位 → 评估的整条测试链路。Sample存在漏洞的示例代码示例的核心代码位于 MastgTest.kt一个 Kotlin 类MastgTest其mastgTest()方法直接绕过 Scoped Storage 向外部存储根目录写入文件package org.owasp.mastestapp import android.content.Context import android.os.Environment import android.util.Log import java.io.File import java.io.FileOutputStream import java.io.IOException class MastgTest (private val context: Context){ fun mastgTest(): String { val externalStorageDir Environment.getExternalStorageDirectory() val fileName File(externalStorageDir, secret.txt) val fileContent Secret not using scoped storage try { FileOutputStream(fileName).use { output - output.write(fileContent.toByteArray()) Log.d(WriteExternalStorage, File written to external storage successfully.) } } catch (e: IOException) { Log.e(WriteExternalStorage, Error writing file to external storage, e) return ERROR!!\n\nError writing file to external storage. Do you have the MANAGE_EXTERNAL_STORAGE permission in the manifest and its granted in All files access? } return SUCCESS!!\n\nFile $fileName with content $fileContent saved to $externalStorageDir } }代码中的三个关键点Environment.getExternalStorageDirectory()返回共享外部存储根目录如/storage/emulated/0这是 Android 10 之前写入共享存储的经典方式在 Scoped Storage 时代必须依赖 All files access 特殊权限才能继续使用。File(externalStorageDir, secret.txt)直接在共享存储根目录创建文件而非使用getExternalFilesDir等应用私有外部目录。明文写入Secret not using scoped storage这是一个敏感数据的替身实际场景中可能是密码、令牌、个人信息未做任何加密即落盘。为了能正常运行AndroidManifest.xml 中声明了特殊权限?xml version1.0 encodingutf-8? manifest xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:toolshttp://schemas.android.com/tools uses-permission android:nameandroid.permission.MANAGE_EXTERNAL_STORAGE / application android:allowBackuptrue android:dataExtractionRulesxml/data_extraction_rules android:fullBackupContentxml/backup_rules android:iconmipmap/ic_launcher android:labelstring/app_name android:roundIconmipmap/ic_launcher_round android:supportsRtltrue android:themestyle/Theme.MASTestApp tools:targetApi31 activity android:name.MainActivity android:exportedtrue android:themestyle/Theme.MASTestApp intent-filter action android:nameandroid.intent.action.MAIN / category android:nameandroid.intent.category.LAUNCHER / /intent-filter /activity /application /manifest注意MANAGE_EXTERNAL_STORAGE与普通运行时权限如WRITE_EXTERNAL_STORAGE不同它属于特殊应用权限无法在运行时通过requestPermissions弹窗授予必须引导用户进入系统设置中的 All files access所有文件访问页面手动开启且 Google Play 对该权限有严格的上架审核限制仅允许文件管理器、备份类等核心功能为文件管理的应用使用。反编译视角Kotlin 如何变成 Java测试过程模拟真实逆向场景对 APK 反编译后得到 MastgTest_reversed.java对应 MASTG-TECH-0013 逆向工程技术Kotlin 编译器产物被还原为等价的 Javapackage org.owasp.mastestapp; import android.content.Context; import android.os.Environment; import android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; ... /* compiled from: MastgTest.kt */ public final class MastgTest { private final Context context; public MastgTest(Context context) { Intrinsics.checkNotNullParameter(context, context); this.context context; } public final String mastgTest() { File externalStorageDir Environment.getExternalStorageDirectory(); File fileName new File(externalStorageDir, secret.txt); try { FileOutputStream fileOutputStream new FileOutputStream(fileName); ... output.write(bytes); Log.d(WriteExternalStorage, File written to external storage successfully.); ... } catch (IOException e) { Log.e(WriteExternalStorage, Error writing file to external storage, e); ... } } }这段反编译代码与 Kotlin 源码逻辑一一对应第 27 行File externalStorageDir Environment.getExternalStorageDirectory();就是后续 Semgrep 规则将命中的位置。这也说明静态分析直接作用于反编译产物是完全可行的——这正是 MASTG 测试方法论所倡导的做法MASTG-TEST-0202 的步骤 1 即要求先逆向 APK。同样地APK 解包得到的 AndroidManifest_reversed.xml 保留了MANAGE_EXTERNAL_STORAGE权限声明第 2 行并额外暴露了编译细节compileSdkVersion34、android:debuggabletrue、android:testOnlytrue以及 androidx 运行时组件CoreComponentFactory、InitializationProvider、ProfileInstallReceiver等。规则两套 MASTG Semgrep 规则详解本演示使用 MASTG-TOOL-0110Semgrep 作为静态扫描器。Semgrep 是能够扫描 Java、Kotlin 和 Swift 的静态代码扫描工具MASTG 仓库将其规则以 YAML 形式存放在 rules 目录下本次用到两套规则。针对反编译 Java 代码的 API 规则rules/mastg-android-data-unencrypted-shared-storage-no-user-interaction-apis.yml 定义了三条子规则覆盖三类外部存储访问模式子规则 ID命中模式风险描述...-external-api-publicgetExternalStorageDirectory(...)、getExternalStoragePublicDirectory(...)、getDownloadCacheDirectory(...)、Intent.ACTION_CREATE_DOCUMENT返回共享外部存储位置其他应用可访问...-external-api-scopedgetExternalFilesDir(...)、getExternalFilesDirs(...)、getExternalCacheDir(...)、getExternalCacheDirs(...)、getExternalMediaDirs(...)返回作用域外部存储位置Android 10 及以下在具备相关权限时可能被其他应用访问...-mediastoreimport android.provider.MediaStore、$X.MediaStore通过 MediaStore API 写入外部存储数据可被其他应用访问该规则文件使用 Semgrep 的pattern-either语法每条子规则都带有severity: WARNING和message元信息。第一类external-api-public的 message 为[MASVS-STORAGE] Make sure to encrypt files at these locations if necessary即命中后提示开发者如有必要请加密这些位置的文件。针对 Manifest 的权限规则rules/mastg-android-data-unencrypted-shared-storage-no-user-interaction-manifest.yml 使用generic语言对清单文件做模式匹配命中以下任一存储相关声明即告警pattern-either: - pattern: WRITE_EXTERNAL_STORAGE - pattern: MANAGE_EXTERNAL_STORAGE - pattern: ACCESS_ALL_EXTERNAL_STORAGE - pattern: requestLegacyExternalStoragetrue - pattern: preserveLegacyExternalStoragetrue - pattern: android:requestRawExternalStorageAccesstrue这套规则覆盖了 Scoped Storage 时代所有绕过或降级手段WRITE_EXTERNAL_STORAGEAndroid 10 之前的旧权限在 Android 11 上已失去授予意义系统对共享存储默认只读但遗留代码中仍可能出现MANAGE_EXTERNAL_STORAGEAndroid 11 引入的All files access特殊权限本文示例正是命中此项ACCESS_ALL_EXTERNAL_STORAGE面向 TV 等特殊设备的全部文件访问权限requestLegacyExternalStoragetrueAndroid 10 的清单属性允许应用暂时沿用旧存储模型Android 11 起被忽略preserveLegacyExternalStoragetrue应用更新时保留旧存储模型的属性android:requestRawExternalStorageAccesstrue针对 Android 14API 34新增的原始文件访问。Steps运行 Semgrep 规则扫描仓库为演示提供了开箱即用的执行脚本 run.sh其中两条命令分别对反编译产物执行两套规则NO_COLORtrue semgrep -c ../../../../rules/mastg-android-data-unencrypted-shared-storage-no-user-interaction-apis.yml ./MastgTest_reversed.java output.txt NO_COLORtrue semgrep -c ../../../../rules/mastg-android-data-unencrypted-shared-storage-no-user-interaction-manifest.yml ./AndroidManifest_reversed.xml output2.txt命令要点-c--config指定规则文件路径。此处使用相对路径指向仓库根目录下的 rules 目录在实际项目中也可替换为 Semgrep Registry 的规则 ID 或远程配置 URL目标文件直接扫描反编译产物MastgTest_reversed.java与AndroidManifest_reversed.xml而非原始源码真实还原了无源码审计场景NO_COLORtrue禁用彩色输出便于将结果重定向到文件、接入 CI 或供后续脚本解析输出重定向分别写入output.txt与output2.txt。运行前提是本地已安装 Semgreppip install semgrep或参考 MASTG-TOOL-0110 的官方来源安装。规则采用标准 Semgrep YAML 格式因此也完全兼容semgrep scan --config目录级批量扫描——仓库 rules 目录下的全部规则可直接作为一个扫描集使用。Observation规则输出解读运行脚本后得到两份输出。第一份 output.txt 来自 API 规则命中 1 处代码位置┌────────────────┐ │ 1 Code Finding │ └────────────────┘ MastgTest_reversed.java ❯❱ rules.mastg-android-data-unencrypted-shared-storage-no-user-interaction-external-api-public [MASVS-STORAGE] Make sure to encrypt files at these locations if necessary 27┆ File externalStorageDir Environment.getExternalStorageDirectory();输出清晰标注了命中规则 ID...-external-api-public、告警消息以及精确的源码位置文件MastgTest_reversed.java第 27 行这正是后续人工评估的锚点。第二份 output2.txt 来自 Manifest 规则同样命中 1 处┌────────────────┐ │ 1 Code Finding │ └────────────────┘ AndroidManifest_reversed.xml ❯❱ rules.mastg-android-data-unencrypted-shared-storage-no-user-interaction-manifest [MASVS-STORAGE] Make sure to encrypt files in external storage if necessary 2┆ uses-permission android:nameandroid.permission.MANAGE_EXTERNAL_STORAGE/两处命中恰好一一对应漏洞的两个必要条件代码中调用了Environment.getExternalStorageDirectory()第 27 行具备向共享存储写文件的能力清单中声明了MANAGE_EXTERNAL_STORAGE第 2 行为上述调用提供了授权。这印证了规则设计的成对思路仅查 API 会漏掉有能力但未授权或已授权未使用的场景仅查权限又无法定位具体写入代码因此 MASTG-TEST-0202 将两者结合再辅以动态测试补足实际写入的路径与内容信息静态分析无法提供运行时写入的真实数据。Evaluation评估与判定按照 MASTG-TEST-0202 的评估标准测试失败需要同时满足三个条件应用在 Android 清单中声明了相关权限如WRITE_EXTERNAL_STORAGE、MANAGE_EXTERNAL_STORAGE等——✅ 已命中应用使用了写入共享存储的 API如getExternalStoragePublicDirectory、getExternalStorageDirectory、getExternalFilesDir、getExternalCacheDir、MediaStore等——✅ 已命中写入共享存储的数据为敏感数据且未加密——需人工验证。第三点无法由静态规则自动判定需要按照 MASTG-TECH-0023静态分析的人工复核审查输出中报告的位置文件与行号。对MastgTest_reversed.java第 27 行附近的代码进行复核后可以看到mastgTest()方法将Secret not using scoped storage明文写入secret.txt且未做任何加密处理——该内容在本示例中即为敏感数据真实场景可能是密码、令牌或个人信息的替身。由此可以得出结论该测试失败。应用绕过 Scoped Storage 限制将敏感数据未加密写入共享外部存储任何具备存储读取权限的应用均可读取违反 MASVS-STORAGE 相关要求。延伸如何修复与加固结合规则与测试文档的提示针对此类漏洞的缓解方向包括改用作用域存储 API将Environment.getExternalStorageDirectory()替换为context.getExternalFilesDir(...)应用专属外部目录或MediaStore媒体文件并移除MANAGE_EXTERNAL_STORAGE权限声明加密敏感数据若确需写入共享存储使用 Android Keystore 派生的密钥对数据进行加密参考仓库 MASVS-CRYPTO 与 MASVS-STORAGE 下的其他演示用例彻底移除清单中的冗余声明删除requestLegacyExternalStorage、preserveLegacyExternalStorage等历史兼容属性避免旧存储模型回退常态化扫描将 rules 目录下的 Semgrep 规则接入 CI 流水线对每次构建产物含反编译产物自动执行semgrep --config扫描使此类问题在发布前暴露。总结MASTG-DEMO-0003完整展示了一次针对外部存储未加密写入弱点的端到端静态分析从 MastgTest.kt 的漏洞代码与 AndroidManifest.xml 的权限声明到反编译产物 MastgTest_reversed.java 与 AndroidManifest_reversed.xml再到两套 Semgrep 规则与 run.sh 的精确命中最终依据 MASTG-TEST-0202 的判定标准得出失败结论。这套反编译 → 规则扫描 → 人工复核的流程可以直接迁移到真实 App 的安全测试中在无源码的情况下仅凭 APK 即可通过仓库 rules 下的规则快速定位外部存储相关风险点再结合动态测试如 MASTG-TEST-0001 家族用例验证实际写入的数据与路径从而对 MASWE-0002 类弱点给出有据可依的评估结论。赞分享文档教程网络安全【免费下载链接】mastgThe 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.项目地址https://gitcode.com/gh_mirrors/ow/mastg点击查看免费下载相关推荐DeepSeek-V3.2 NPU 量化训练与推理实践CANN AMCT 中的 W8A8C8/W4A8C8 量化策略全解析DeepSeek V3.2 NPU 量化训练与推理实践CANN AMCT 中的 W8A8C8/W4A8C8 量化策略全解析 导读 DeepSeek 团队发布的文档教程网络安全Android 文件系统完全指南内部存储、外部存储与作用域存储Scoped Storage实战Android 文件系统完全指南内部存储、外部存储与作用域存储Scoped Storage实战 Android 文件系统决定了应用读写数据的存储位置与权限文档教程知识库Android 文件存储实战使用 File API 在内部存储与外部存储中保存数据Android 文件存储实战使用 File API 在内部存储与外部存储中保存数据 本指南聚焦于 Android 官方培训课程《数据保存》系列中的文件存储主题文档教程移动开发上一篇3分钟实现手机号码精准定位location-to-phone-number开源项目技术深度解析下一篇Syft SBOM 生成教程3 条命令摸清软件物料清单创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表