sterrasec/apk-interceptor

GitHub: sterrasec/apk-interceptor

一款轻量级 Android 安全评估辅助 APK,帮助安全工程师在无需 root 的前提下验证 deeplink 劫持、导出 Activity 暴露和 WebView bridge 可达性等漏洞。

Stars: 3 | Forks: 0

# apk-interceptor [![构建检查](https://github.com/sterrasec/apk-interceptor/actions/workflows/build.yml/badge.svg)](https://github.com/sterrasec/apk-interceptor/actions/workflows/build.yml) **Android deeplink、Intent 和 WebView bridge 评估辅助工具** apk-interceptor 是一款便携的 Android 测试 APK,专为授权的应用程序 安全评估设计。它可以帮助安全工程师验证 Android 应用 如何处理外部入口点,例如自定义 URI scheme、deeplink、导出的 Activity 和 WebView JavaScript bridge。 该工具在设计上有意做出了以下限制: - 它没有声明 `android.permission.INTERNET` - 它不会向外部服务器发送数据 - 它不执行 shell 命令 - 它不需要 root、Magisk、Frida 或运行时插桩 - 它只提供一个本地 `content://` payload 文件 - 它注册一个在构建时固定的自定义 URI scheme ## 动机 在 Android 应用程序安全评估过程中,静态分析的许多发现 仍然需要设备上的小规模概念验证才能得到确认:注册自定义 URI scheme、发送显式 Intent、提供本地 `content://` payload,或者检查 JavaScript 是否能到达 WebView bridge。 为每种情况构建一个新的临时测试应用程序既重复又容易出错。 manifest 条目、authorities、URI 授权、包名 或 Intent 构造上的微小差异都会拖慢验证速度,并使结果难以 复现。 apk-interceptor 的诞生就是为了使这一确认步骤可重复。与其 为每次评估编写一个新的 PoC APK,不如使用你需要的授权 scheme 或 application ID 构建此工具,在设备上运行测试,并 通过设计保持工作流的限制:无 INTERNET 权限,无外部数据 传输,无 shell 执行,无 root 依赖。 ## 可以测试的内容 apk-interceptor 适用于以下评估任务: | 场景 | 模块 | 它有助于验证的内容 | | --- | --- | --- | | 自定义 URI scheme 劫持 | Interceptor | 另一个应用是否可以注册相同的 scheme 并接收链接 | | Deeplink 参数处理 | Sender | 受评估的应用是否接受不安全的查询/路径参数 | | 导出的 Activity 暴露 | Sender | 导出的 Activity 是否可以直接被另一个应用启动 | | 通过 `content://` 暴露的 WebView bridge | Payload + Sender | 本地 HTML payload 是否可以到达 WebView JavaScript bridge | | 本地 payload 语法检查 | Payload | 你的 HTML/JS payload 是否在自测 WebView 中运行 | 详细的漏洞演练: - [自定义 URI Scheme 劫持](docs/vulnerabilities/custom-uri-scheme-hijacking.md) - [Deeplink开放重定向](docs/vulnerabilities/deeplink-open-redirect.md) - [带有不受信任 Intent 数据的导出 Activity](docs/vulnerabilities/exported-activity-intent-data.md) - [通过 `content://` 暴露的 WebView JavaScript Bridge](docs/vulnerabilities/webview-js-bridge-content-uri.md) 该应用程序为已发送的 Intent、接收到的 deeplink、 bridge 回调、JavaScript 结果和错误保留内存中的评估日志。当应用程序 进程被终止时,日志将消失。由于日志不会被持久化保存,因此在工作时请通过 屏幕截图或屏幕录制捕获证据。 ## 对比 apk-interceptor 是一款 **确认** 工具,而不是发现或利用 框架。它假定你已经通过静态分析知道要测试什么(scheme、Activity 类、 bridge 名称),并为你提供一种安全的、设备上的方法来验证 可达性并捕获证据。它的构建初衷是安装在评估 设备上,甚至可以与客户共享,因此它不包含 INTERNET 权限、没有 shell 执行、没有数据泄露,也没有 root 要求。 它与常见的 Android 工具的对比: | 工具 | 作用 | apk-interceptor 的不同之处 | | --- | --- | --- | | jadx / MobSF / QARK / Semgrep | 查找易受攻击的入口点(静态) | apk-interceptor 不进行扫描或反编译;它只确认你已有的发现 | | deep-C / NSdeepLink / `adb am start` | 枚举并*发送* deeplink | apk-interceptor 也可以发送,但它的区别在于*接收*被劫持的 scheme 并显示确切的 URI 和参数 | | drozer | 通用的设备端攻击框架(agent + 通常需要 root) | apk-interceptor 是一个单一的轻量级 APK,具有刻意的安全防护栏、更窄的范围以及更易于向客户分发的特性 | | Metasploit / Frida | 武器化或 Hook(例如 `addJavascriptInterface` RCE) | apk-interceptor 仅使用无害的 payload 检查 bridge 的*可达性*;它从不泄露数据或执行 shell 命令 | apk-interceptor 相比其他替代方案具有明显优势的两个领域是: - **Scheme 劫持证据** — 充当实际注册 该 scheme 的第二个应用,并记录接收到的每个参数,这是 `adb`/静态分析 无法显示的。 - **`content://` -> WebView bridge 验证** — 一个非导出的、单文件 provider,其 payload 仅通过临时的 Intent 读取权限传递, 外加一个本地自测 WebView 以首先验证 payload 语法。 ## 发送与拦截 apk-interceptor 对*发送*和*拦截*的处理方式不同,这是在使用它之前需要理解的 最重要的一点: | 操作 | 模块 | 构建时需要自定义 scheme? | | --- | --- | --- | | 向另一个应用**发送** Intent 或 deeplink | Sender | 否 — 在运行时输入任何 URI、包名或 Activity | | 为自定义 scheme **拦截**(接收)deeplink | Interceptor | 是 — scheme 在构建时被固定到 APK 中 | 要向受评估的应用*发送*定制的 deeplink,你不需要重新构建: 使用 Sender 标签页的 **Implicit Deeplink** 模式并输入任何 URI。 要*拦截* deeplink —— 即让 Android 将自定义 scheme 路由到 apk-interceptor 以便你可以观察潜在的 scheme 劫持 —— 你必须通过 `--scheme` 使用该 scheme 构建 APK。该 scheme 在构建时被固定是 刻意的(一种设计防护栏);apk-interceptor 从不在 运行时注册任意 scheme。如果你更改了正在评估的 scheme,请重新构建并重新安装。 ## 环境要求 - 带有 Android SDK 35 的 Android Studio - Android 12+ 设备或模拟器 - JDK 17+ - 用于安装设备和可选命令行测试的 `adb` ## 构建和安装 使用你获得授权评估的自定义 URI scheme 构建 APK: ``` ./build-interceptor.sh --scheme adb install ./out/apk-interceptor--debug.apk ``` 可选的构建参数: ``` ./build-interceptor.sh \ --scheme \ --app-id \ --output ./out ``` `--app-id` 在构建时设置已安装的 application ID(设备上的包标识符和 `content://.payload` authority)。 默认值为 `com.sterrasec.apkinterceptor`。当你需要为不同的评估提供多个可独立安装的构建时,使用 `--app-id` 覆盖它。 Windows 下的等价物是 `build-interceptor.bat`。 默认 scheme `intercept-poc-example` 是一个无害的占位符。构建 脚本拒绝使用该默认 scheme 生成评估 APK。 ## 首次启动 在每个应用版本的首次启动时,apk-interceptor 会显示一个授权使用 对话框。在你点击 **I understand** 后,同一版本不会再次 显示该对话框。 Sender 标签页仍会显示一个持续性警告,因为它可以向其他 应用发送 Intent。 Authorized use dialog ## 截图 | Sender | Payload | Interceptor | | --- | --- | --- | | Sender tab | Payload tab | Interceptor tab | ## 应用模块 ### Interceptor 使用此标签页验证自定义 URI scheme 拦截。 显示的内容: - 编译进此 APK 的 scheme - 如果仍在使用虚拟默认 scheme,则会显示警告 - 接收到的 deeplink 日志 - 测试查询参数字段 - **Send Test Deeplink** - **Clear** 基本工作流程: 1. 使用受评估的自定义 scheme 构建 APK。 2. 将其与受评估的应用一起安装。 3. 从受评估的流程、浏览器、adb 或内置的 **Send Test Deeplink** 按钮触发该 scheme 的 deeplink。 4. 如果 Android 将链接路由到 apk-interceptor,请打开 Interceptor 标签页并 查看接收到的 URI 和查询参数。 关于 **Send Test Deeplink**:它总是发送带有 固定 `test` host 的 `://test?`,因此它是用来确认 apk-interceptor 接收并记录了该 scheme —— 而不是用于驱动受评估应用的特定 deeplink 路由。要发送与受评估应用的 所需 host 或路径匹配的定制 deeplink,请改用 Sender 标签页的 **Implicit Deeplink** 模式。 adb 示例: ``` adb shell am start -W \ -a android.intent.action.VIEW \ -d 'my-authorized-scheme://test?source=adb\&message=hello%20world' ``` 在通过 `adb shell` 发送多个查询参数时使用 `\&`;否则 设备 shell 可能会将 `&` 视为命令分隔符。 预期结果: - apk-interceptor 打开 Interceptor 标签页 - 出现 `RECEIVED` 日志条目 - 点击日志条目可展开完整的 URI 和参数列表 ### Sender 在授权测试期间使用此标签页发送受控的 Intent。 模式: - **Implicit Deeplink**:发送 `Intent(ACTION_VIEW, Uri.parse(uri))` - **Explicit Activity**:向特定的包名和 Activity 类发送 Intent 字段和控件: - 用于隐式 deeplink 模式的 **URI** - 用于显式 Activity 模式的 **Package name** - 用于显式 Activity 模式的 **Activity class** - **Attach content:// URI**,用于将本地 payload URI 设置为 Intent 数据 (仅在 **Explicit Activity** 模式中显示 —— 见下文注释) - **FLAG_GRANT_READ_URI_PERMISSION**,用于授予对所附加 payload URI 的读取权限 - **Send Intent** 隐式 deeplink 工作流程: 1. 选择 **Implicit Deeplink**。 2. 输入与受评估应用的 deeplink 模式匹配的 URI。 3. 点击 **Send Intent**。 4. 观察受评估应用的行为和 apk-interceptor 日志。 显式 Activity 工作流程: 1. 确认目标 Activity 已导出且在你的授权范围内。 2. 选择 **Explicit Activity**。 3. 输入受评估应用的包名。 4. 输入导出的 Activity 类名。 5. 可选择启用 **Attach content:// URI**。 6. 点击 **Send Intent**。 注意: - apk-interceptor 不知道受评估的应用是否安全地处理了 Intent。 你必须观察受评估应用的行为、日志或测试环境。 - `content://` 附件在测试目标 Activity 是否将不受信任的 Intent 数据传递给 WebView 时很有用。 - **Attach content:// URI** 仅在 **Explicit Activity** 模式中提供。 payload 作为 Intent 的 `data` 传递,这将覆盖你在 **Implicit Deeplink** 模式中输入的 URI,因此该选项在那里被隐藏。 - `PayloadProvider` 未导出。受评估的应用只能读取附加的 `content://` payload,因为 Intent 通过 **FLAG_GRANT_READ_URI_PERMISSION** 授予了它临时读取权限。 保持该标志为启用状态,并通过 Intent 传递 URI —— 以任何其他方式打开的 `content://` URI 将无法被另一个应用读取。 ### Payload 使用此标签页创建本地 HTML payload 并在 apk-interceptor 自身的自测 WebView 中验证 JavaScript bridge 语法。 它包含的内容: - **HTML** 编辑器 - **JavaScript evaluated after page load** 编辑器 - **Bridge object name** - 生成的 `content://` URI - **Save Payload** - **Run Self-Test** - 自测 WebView - Bridge 结果和控制台日志 生成的 payload URI 格式: ``` content://.payload/current.html ``` provider 仅提供此固定文件: ``` filesDir/payloads/current.html ``` Payload 自测工作流程: 1. 在 **HTML** 字段中输入或粘贴 HTML。 2. 输入你想在本地测试的 bridge 对象名称,例如 `localBridge`。 3. 在 HTML 内部或 JavaScript 编辑器中添加 JavaScript。 4. 点击 **Save Payload**。 5. 点击 **Run Self-Test**。 6. 检查日志中的 `BRIDGE_RESULT`、`console.log` 和 `evaluateJavascript result` 条目。 自测 JavaScript 示例: ``` console.log("payload loaded"); window.localBridge.logResult(window.localBridge.getInfo()); ``` 自测 bridge 暴露的内容: ``` window..logResult("message"); window..getInfo(); ``` 重要限制: 自测 WebView 确认你的本地 payload 和 bridge 调用语法 可以在 apk-interceptor 内部工作。它无法观察另一个应用的 WebView 是否执行了你的 payload 或调用了其自身的 bridge。对于受评估的应用,如果该应用 是可调试的,请通过该应用的 UI、日志、测试钩子或 Chrome DevTools 进行验证。 ## 面向漏洞的工作流程 ### 1. 自定义 URI Scheme 劫持 风险: Android 应用注册了自定义 URI scheme,而不是经过验证的 App Link。 任何其他应用都可以注册相同的 scheme,因此 Android 可能会显示应用选择器 或将链接路由到不同的应用使用 apk-interceptor 检查: - 该 scheme 是否可以由另一个应用注册 - Android 是否提供 apk-interceptor 作为处理程序 - deeplink 参数中是否出现敏感值 步骤: 1. 从受评估应用的 manifest 或 文档中识别其自定义 scheme。 2. 使用该 scheme 构建 apk-interceptor。 3. 将 apk-interceptor 和受评估的应用安装在同一个测试设备上。 4. 从授权的测试流程中触发 deeplink。 5. 如果 apk-interceptor 接收到它,请检查 Interceptor 日志。 需要捕获的证据: - 操作系统选择器行为(如果显示) - 完整的接收到的 URI - 查询参数以及它们是否包含敏感值 - 路由链接所需的用户交互 ### 2. Deeplink 参数注入 风险: 受评估的应用信任 deeplink 参数来进行导航、URL 加载、 功能标志、账户选择或渲染,而没有进行充分的验证。 使用 apk-interceptor 检查: - 是否接受构造的参数 - 应用是否导航到非预期的屏幕 - 是否使用了不安全的 URL/路径/content 值 步骤: 1. 识别受评估应用的 deeplink 格式。 2. 打开 **Sender**。 3. 选择 **Implicit Deeplink**。 4. 输入带有受控参数的授权测试 URI。 5. 点击 **Send Intent**。 6. 观察受评估应用的行为。 示例占位符: ``` my-authorized-scheme://open?next=https%3A%2F%2Fauthorized-test.example%2Flanding ``` 不要使用真实的第三方域名或账户,除非它们明确在 测试范围内。 ### 3. 导出的 Activity 访问控制 风险: 导出的 Activity 执行敏感操作或显示敏感数据, 而没有验证调用者、用户状态或所需的授权。 使用 apk-interceptor 检查: - 导出的 Activity 是否可以从另一个应用启动 - 是否在没有预期检查的情况下执行敏感行为 - Intent 数据是否改变了其行为 步骤: 1. 确认该 Activity 已导出且在范围内。 2. 打开 **Sender**。 3. 选择 **Explicit Activity**。 4. 输入包名和 Activity 类名。 5. 可选择附加本地 `content://` payload URI。 6. 点击 **Send Intent**。 7. 观察受评估应用是否实施了访问控制。 需要捕获的证据: - Activity 已启动或被阻止 - 任何身份验证或授权提示 - 敏感操作或数据暴露 - Activity 使用的 Intent 数据 ### 4. 通过 `content://` 暴露的 WebView JavaScript Bridge 风险: 受评估的应用将不受信任的 `content://` Intent 数据加载到 WebView 中,该 WebView 还通过 `addJavascriptInterface` 暴露了 JavaScript bridge。 使用 apk-interceptor 检查: - 本地 HTML payload 是否可以作为 `content://` 传递 - 目标 WebView 是否加载了该 payload - 来自该源的 JavaScript 是否可以到达 bridge 步骤: 1. 在授权分析期间识别目标 Activity 和 bridge 对象名称。 2. 打开 **Payload**。 3. 创建调用预期 bridge 的 HTML/JS。 4. 使用 **Run Self-Test** 在本地验证你的语法。 5. 打开 **Sender**。 6. 选择 **Explicit Activity**。 7. 输入目标包名和 Activity 类名。 8. 启用 **Attach content:// URI** 并保持启用 **FLAG_GRANT_READ_URI_PERMISSION**。 9. 点击 **Send Intent**。 10. 观察受评估的应用,确定其 WebView 是否加载了 payload 并执行了 bridge 调用。 重要限制: 除非另一个应用明确返回或显示结果,否则 apk-interceptor 无法从中接收 结果。该工具旨在传递本地 payload 并验证语法,而不是用于窃取数据。 ## 命令行检查 验证 APK 是否未请求网络访问权限: ``` aapt dump permissions ./out/apk-interceptor--debug.apk ``` 预期:无 `android.permission.INTERNET`。 显式向 apk-interceptor 触发 deeplink: ``` adb shell am start -W \ -n com.sterrasec.apkinterceptor/.InterceptActivity \ -a android.intent.action.VIEW \ -d 'my-authorized-scheme://test?source=adb' ``` 通过 Android 的 resolver 触发 deeplink: ``` adb shell am start -W \ -a android.intent.action.VIEW \ -d 'my-authorized-scheme://test?source=adb' ``` 显式命令确认 `InterceptActivity` 行为。隐式 命令确认 manifest intent-filter 和 resolver 行为。 ## 测试 单元测试在 JVM 上使用 Robolectric 运行 —— 不需要设备或模拟器。 它们涵盖 `PayloadProvider`,包括路径白名单和遍历 检查,以确保 provider 仅提供单一的 `current.html` payload,而不提供其他任何内容。 ``` ./gradlew testDebugUnitTest ``` 测试结果写入 `app/build/reports/tests/testDebugUnitTest/index.html`。 相同的任务会在 CI 中针对每次推送到 `main` 的代码和 pull request 运行。 ## 设计防护栏 - 无 `android.permission.INTERNET` - 无外部数据传输或自动数据泄露 - 无 shell 命令执行功能 - 无 root、Magisk、Frida 或插桩依赖 - 无运行时注册任意 scheme - 无通用文件提供 provider - `PayloadProvider` 仅提供 `/current.html` ## 许可证 MIT
标签:Android安全, Deeplink测试, Intent劫持, 反取证, 安全测试, 安全评估, 攻击性安全, 目录枚举, 移动安全, 足迹探测