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)
**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。
## 截图
| Sender | Payload | Interceptor |
| --- | --- | --- |
|
|
|
|
## 应用模块
### 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
## 截图
| Sender | Payload | Interceptor |
| --- | --- | --- |
|
|
|
|
## 应用模块
### 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 的 `标签:Android安全, Deeplink测试, Intent劫持, 反取证, 安全测试, 安全评估, 攻击性安全, 目录枚举, 移动安全, 足迹探测