MASTG-TEST-0069: 测试应用权限
此测试即将更新
此测试目前可使用,但将作为新的 OWASP MASTG v2 指南 的一部分进行全面修订。
请提交 PR 来帮助我们完成以下内容:MASTG v1->v2 MASTG-TEST-0069:测试应用权限 (ios)
概述¶
静态分析¶
自从 iOS 10 以来,以下是您需要检查权限的主要区域:
- Info.plist 文件中的用途字符串
- 代码签名权限文件
- 嵌入式 Provisioning Profile 文件
- 编译后的应用二进制文件中嵌入的权限
- 源代码中权限的使用
Info.plist 文件中的用途字符串¶
如果拥有原始源代码,则可以验证 Info.plist
文件中包含的权限
- 使用 Xcode 打开项目。
- 在默认编辑器中查找并打开
Info.plist
文件,然后搜索以"Privacy -"
开头的键。
您可以切换视图以显示原始值,方法是右键单击并选择“显示原始键/值”(例如,这样 "Privacy - Location When In Use Usage Description"
将变为 NSLocationWhenInUseUsageDescription
)。
如果只有 IPA
- 解压缩 IPA。
Info.plist
位于Payload/<appname>.app/Info.plist
中。- 如果需要,请转换它(例如,
plutil -convert xml1 Info.plist
),如“iOS 基本安全测试”一章的“Info.plist 文件”部分所述。 -
检查所有*用途字符串 Info.plist 键*,通常以
UsageDescription
结尾<plist version="1.0"> <dict> <key>NSLocationWhenInUseUsageDescription</key> <string>Your location is used to provide turn-by-turn directions to your destination.</string>
对于 Info.plist
文件中的每个用途字符串,检查该权限是否有意义。
例如,假设以下几行是从 Solitaire 游戏使用的 Info.plist
文件中提取的
<key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
<string>Share your health data with us!</string>
<key>NSCameraUsageDescription</key>
<string>We want to access your camera</string>
一个普通的纸牌游戏请求这种资源访问应该是可疑的,因为它可能不需要访问相机或用户的健康记录。
除了简单地检查权限是否有意义之外,还可以通过分析用途字符串来得出进一步的分析步骤,例如,它们是否与存储敏感数据有关。例如,NSPhotoLibraryUsageDescription
可以被视为存储权限,授予对应用程序沙箱之外的文件的访问权限,并且可能也可以被其他应用程序访问。在这种情况下,应测试是否没有在那里存储敏感数据(在这种情况下为照片)。对于其他用途字符串,例如 NSLocationAlwaysUsageDescription
,还必须考虑应用程序是否安全地存储此数据。有关安全存储敏感数据的更多信息和最佳实践,请参阅“测试数据存储”一章。
嵌入式 Provisioning Profile 文件¶
当您没有原始源代码时,您应该分析 IPA 并在其中搜索*嵌入式 Provisioning Profile*,该文件通常位于根应用程序 bundle 文件夹 (Payload/<appname>.app/
) 中,名称为 embedded.mobileprovision
。
此文件不是 .plist
,而是使用加密消息语法进行编码的。在 macOS 上,您可以使用以下命令检查嵌入式 Provisioning Profile 的权限
security cms -D -i embedded.mobileprovision
然后搜索权限键区域 (<key>Entitlements</key>
)。
编译后的应用二进制文件中嵌入的权限¶
如果您只有应用程序的 IPA,或者只是在越狱设备上安装的应用程序,通常您将无法找到 .entitlements
文件。embedded.mobileprovision
文件也可能是这种情况。但是,您仍然应该能够从应用程序二进制文件中提取权限属性列表(请参阅* 从 MachO 二进制文件中提取权限*)。
源代码中权限的使用¶
检查完 <appname>.entitlements
文件和 Info.plist
文件后,就该验证所请求的权限和分配的权限的实际使用方式了。为此,源代码审查应该足够了。但是,如果您没有原始源代码,则验证权限的使用可能特别具有挑战性,因为您可能需要对应用程序进行逆向工程,有关如何继续操作的更多详细信息,请参阅“动态分析”。
在进行源代码审查时,请注意
Info.plist
文件中的*用途字符串*是否与程序实现匹配。- 注册的功能是否以不会泄漏机密信息的方式使用。
用户可以随时通过“设置”授予或撤销授权,因此应用程序通常在访问功能之前检查该功能的授权状态。这可以通过使用专用的 API 来完成,这些 API 适用于许多系统框架,这些框架提供对受保护资源的访问。
您可以使用Apple 开发者文档作为起点。例如
- 蓝牙:
state
属性的CBCentralManager
类用于检查使用蓝牙外围设备 的系统授权状态。 -
位置:搜索
CLLocationManager
的方法,例如locationServicesEnabled
。func checkForLocationServices() { if CLLocationManager.locationServicesEnabled() { // Location services are available, so query the user’s location. } else { // Update your app’s UI to show that the location is unavailable. } }
有关完整列表,请参阅 “确定位置服务的可用性”(Apple 开发者文档)中的表 1。
浏览应用程序,搜索这些 API 的用法,并检查可能从这些 API 获得敏感数据会发生什么。例如,它可能会存储或通过网络传输,如果是这种情况,则应额外验证适当的数据保护和传输安全性。
动态分析¶
借助静态分析,您应该已经有一个正在使用的包含权限和应用程序功能列表。但是,如“源代码检查”中所述,当您没有原始源代码时,发现敏感数据和与这些权限和应用程序功能相关的 API 可能是一项具有挑战性的任务。动态分析可以帮助在这里获取输入,以便迭代到静态分析中。
遵循如下所示的方法应该可以帮助您发现提到的敏感数据和 API
- 考虑在静态分析中标识的权限/功能列表(例如
NSLocationWhenInUseUsageDescription
)。 - 将它们映射到相应系统框架的专用 API(例如
Core Location
)。您可以使用Apple 开发者文档 来实现此目的。 - 跟踪这些 API 的类或特定方法(例如
CLLocationManager
),例如,使用frida-trace
。 - 确定应用程序在访问相关功能(例如“共享您的位置”)时真正使用哪些方法。
- 获取这些方法的回溯并尝试构建调用图。
一旦识别出所有方法,您可以使用这些知识来对应用程序进行逆向工程,并尝试找出数据的处理方式。在执行此操作时,您可能会发现过程中涉及的新方法,您可以再次将其提供给上面的步骤 3,并在静态分析和动态分析之间保持迭代。
在以下示例中,我们使用 Telegram 从聊天中打开共享对话框,并使用 frida-trace 识别正在调用的方法。
首先,我们启动 Telegram 并开始跟踪与字符串“authorizationStatus”匹配的所有方法(这是一种通用方法,因为除了 CLLocationManager
之外的更多类都实现了此方法)
frida-trace -U "Telegram" -m "*[* *authorizationStatus*]"
-U
连接到 USB 设备。-m
将 Objective-C 方法包含到跟踪中。您可以使用 glob 模式(例如,使用“*”通配符,-m "*[* *authorizationStatus*]"
表示“包含任何包含 'authorizationStatus' 的类的任何 Objective-C 方法”)。键入frida-trace -h
以获取更多信息。
现在我们打开共享对话框
将显示以下方法
1942 ms +[PHPhotoLibrary authorizationStatus]
1959 ms +[TGMediaAssetsLibrary authorizationStatusSignal]
1959 ms | +[TGMediaAssetsModernLibrary authorizationStatusSignal]
如果我们单击位置,将跟踪另一个方法
11186 ms +[CLLocationManager authorizationStatus]
11186 ms | +[CLLocationManager _authorizationStatus]
11186 ms | | +[CLLocationManager _authorizationStatusForBundleIdentifier:0x0 bundle:0x0]
使用 frida-trace 的自动生成的存根来获取更多信息,例如返回值和回溯。对以下 JavaScript 文件进行以下修改(路径相对于当前目录)
// __handlers__/__CLLocationManager_authorizationStatus_.js
onEnter: function (log, args, state) {
log("+[CLLocationManager authorizationStatus]");
log("Called from:\n" +
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join("\n\t") + "\n");
},
onLeave: function (log, retval, state) {
console.log('RET :' + retval.toString());
}
再次单击“位置”会显示更多信息
3630 ms -[CLLocationManager init]
3630 ms | -[CLLocationManager initWithEffectiveBundleIdentifier:0x0 bundle:0x0]
3634 ms -[CLLocationManager setDelegate:0x14c9ab000]
3641 ms +[CLLocationManager authorizationStatus]
RET: 0x4
3641 ms Called from:
0x1031aa158 TelegramUI!+[TGLocationUtils requestWhenInUserLocationAuthorizationWithLocationManager:]
0x10337e2c0 TelegramUI!-[TGLocationPickerController initWithContext:intent:]
0x101ee93ac TelegramUI!0x1013ac
我们看到 +[CLLocationManager authorizationStatus]
返回了 0x4
(CLAuthorizationStatus.authorizedWhenInUse) 并且被 +[TGLocationUtils requestWhenInUserLocationAuthorizationWithLocationManager:]
调用。正如我们之前预期的那样,您可以使用这种信息作为对应用程序进行逆向工程的入口点,并从那里获取输入(例如,类或方法的名称)以保持动态分析的进行。
接下来,有一种可视方式来检查使用 iPhone/iPad 时某些应用程序权限的状态,方法是打开“设置”并向下滚动,直到找到您感兴趣的应用程序。单击它时,这将打开“允许 APP_NAME 访问”屏幕。但是,并非所有权限都可能显示出来。您必须触发它们才能在该屏幕上列出它们。
例如,在前面的示例中,直到我们第一次触发权限对话框后,“位置”条目才被列出。一旦我们这样做,无论我们是否允许访问,“位置”条目都将显示出来。