hacktricks/mobile-pentesting/ios-pentesting/ios-custom-uri-handlers-deeplinks-custom-schemes.md
2023-08-03 19:12:22 +00:00

13 KiB
Raw Blame History

☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

自定义URL scheme允许应用程序通过自定义协议进行通信。应用程序必须声明对这些scheme的支持并处理使用这些scheme的传入URL。

URL scheme提供了一种潜在的攻击向量因此请确保验证所有URL参数丢弃任何格式错误的URL。此外,将可用的操作限制为不会危及用户数据的操作。

例如URImyapp://hostname?data=123876123调用注册了scheme mydata应用程序(即与hostname hostname相关的操作),并发送带有值123876123参数data

一个脆弱的例子是2010年发现的Skype Mobile应用程序中的以下漏洞Skype应用程序注册了skype://协议处理程序,这允许其他应用程序触发对其他Skype用户和电话号码的呼叫。不幸的是Skype在拨打电话之前没有向用户请求权限因此任何应用程序都可以在用户不知情的情况下拨打任意号码。攻击者通过放置一个不可见的<iframe src="skype://xxx?call"></iframe>(其中xxx被一个高级号码替换来利用此漏洞因此任何不经意访问恶意网站的Skype用户都会拨打高级号码。

你可以在应用程序的Info.plist文件中找到应用程序注册的scheme,搜索**CFBundleURLTypes**(例如来自iGoat-Swift的示例):

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.iGoat.myCompany</string>
<key>CFBundleURLSchemes</key>
<array>
<string>iGoat</string>
</array>
</dict>
</array>

然而,请注意恶意应用程序可以重新注册已被应用程序注册的URI。因此如果您通过URI发送敏感信息myapp://hostname?password=123456恶意应用程序可以拦截带有敏感信息的URI。

此外这些URI的输入应该经过检查和清理因为它可能来自试图利用SQL注入、XSS、CSRF、路径遍历或其他可能的漏洞的恶意来源

应用程序查询方案注册

应用程序可以调用canOpenURL来验证目标应用程序是否可用。然而,由于这种方法被恶意应用程序用作枚举已安装应用程序的方式从iOS 9.0开始传递给它的URL方案也必须在应用程序的Info.plist文件中添加LSApplicationQueriesSchemes键,并包含最多50个URL方案的数组

<key>LSApplicationQueriesSchemes</key>
<array>
<string>url_scheme1</string>
<string>url_scheme2</string>
</array>

canOpenURL将始终对未声明的scheme返回NO,无论是否安装了适当的应用程序。然而,这个限制只适用于canOpenURL

测试URL处理和验证

为了确定URL路径是如何构建和验证的如果你有原始的源代码你可以搜索以下方法

  • application:didFinishLaunchingWithOptions:方法或application:will-FinishLaunchingWithOptions:验证决策是如何做出的以及如何检索URL的信息。
  • application:openURL:options::验证资源是如何被打开的,即数据是如何被解析的,验证options,特别是是否允许或拒绝调用应用程序(sourceApplication访问。当使用自定义URL scheme时应用程序可能还需要用户权限。

在Telegram中你将找到四种不同的方法被使用

func application(_ application: UIApplication, open url: URL, sourceApplication: String?) -> Bool {
self.openUrl(url: url)
return true
}

func application(_ application: UIApplication, open url: URL, sourceApplication: String?,
annotation: Any) -> Bool {
self.openUrl(url: url)
return true
}

func application(_ app: UIApplication, open url: URL,
options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
self.openUrl(url: url)
return true
}

func application(_ application: UIApplication, handleOpen url: URL) -> Bool {
self.openUrl(url: url)
return true
}

测试向其他应用程序发送URL请求

方法openURL:options:completionHandler:已弃用的UIApplicationopenURL:方法负责打开URL(即向其他应用程序发送请求/进行查询该URL可能是当前应用程序的本地URL也可能是由其他应用程序提供的URL。如果您有原始源代码可以直接搜索这些方法的用法。

此外如果您想知道应用程序是否正在查询特定的服务或应用程序并且该应用程序是众所周知的您还可以在线搜索常见的URL schemes并将它们包含在您的grepsliOS应用程序scheme列表****中。

egrep -nr "open.*options.*completionHandler" ./Telegram-iOS/
egrep -nr "openURL\(" ./Telegram-iOS/
egrep -nr "mt-encrypted-file://" ./Telegram-iOS/
egrep -nr "://" ./Telegram-iOS/

测试废弃的方法

搜索废弃的方法,例如:

例如,在这里我们找到了这三个方法:

$ rabin2 -zzq Telegram\ X.app/Telegram\ X | grep -i "openurl"

0x1000d9e90 31 30 UIApplicationOpenURLOptionsKey
0x1000dee3f 50 49 application:openURL:sourceApplication:annotation:
0x1000dee71 29 28 application:openURL:options:
0x1000dee8e 27 26 application:handleOpenURL:
0x1000df2c9 9 8 openURL:
0x1000df766 12 11 canOpenURL:
0x1000df772 35 34 openURL:options:completionHandler:
...

调用任意URL

  • Safari: 要快速测试一个URL scheme你可以在Safari中打开URL并观察应用程序的行为。例如如果你写入 tel://123456789Safari将尝试拨打该号码。
  • Notes App: 长按你写的链接以测试自定义URL scheme。记得退出编辑模式以便能够打开它们。请注意只有在安装了应用程序时你才能点击或长按包含自定义URL scheme的链接否则它们不会被标记为“可点击的链接”。
  • IDB:
  • 启动IDB连接到你的设备并选择目标应用程序。你可以在IDB文档中找到详细信息。
  • 转到URL Handlers部分。在URL schemes中,点击Refresh在左侧你将找到正在测试的应用程序中定义的所有自定义scheme的列表。你可以通过点击右侧的Open来加载这些scheme。通过简单地打开一个空的URI scheme例如打开myURLscheme://),你可以发现隐藏的功能(例如,调试窗口)并绕过本地身份验证。
  • Frida:

如果你只想打开URL scheme你可以使用Frida来实现

$ frida -U iGoat-Swift

[iPhone::iGoat-Swift]-> function openURL(url) {
var UIApplication = ObjC.classes.UIApplication.sharedApplication();
var toOpen = ObjC.classes.NSURL.URLWithString_(url);
return UIApplication.openURL_(toOpen);
}
[iPhone::iGoat-Swift]-> openURL("tel://234234234")
true

在这个来自Frida CodeShare的示例中作者使用非公开的API LSApplicationWorkspace.openSensitiveURL:withOptions: 来打开URL来自SpringBoard应用程序

function openURL(url) {
var w = ObjC.classes.LSApplicationWorkspace.defaultWorkspace();
var toOpen = ObjC.classes.NSURL.URLWithString_(url);
return w.openSensitiveURL_withOptions_(toOpen, null);
}

请注意非公开API的使用在App Store上是不允许的这就是为什么我们甚至不测试这些API但我们可以在动态分析中使用它们的原因。

Fuzzing URL Schemes

如果应用程序解析URL的某些部分你还可以执行输入模糊测试以检测内存损坏漏洞。

我们上面学到的知识现在可以用来构建你自己选择的语言例如Python的模糊测试器并使用Frida的RPC调用openURL。该模糊测试器应该执行以下操作:

  • 生成有效载荷。
  • 对于每个有效载荷,调用openURL
  • 检查应用程序是否在/private/var/mobile/Library/Logs/CrashReporter中生成崩溃报告(.ips)。

FuzzDB项目提供了可以用作有效载荷的模糊测试字典。

使用Frida进行模糊测试

使用Frida进行这个操作非常简单你可以参考这篇博文来查看一个在iGoat-Swift应用程序上进行模糊测试的示例适用于iOS 11.1.2)。

在运行模糊测试器之前我们需要将URL schemes作为输入。从静态分析中我们知道iGoat-Swift应用程序支持以下URL scheme和参数iGoat://?contactNumber={0}&message={0}

$ frida -U SpringBoard -l ios-url-scheme-fuzzing.js
[iPhone::SpringBoard]-> fuzz("iGoat", "iGoat://?contactNumber={0}&message={0}")
Watching for crashes from iGoat...
No logs were moved.
Opened URL: iGoat://?contactNumber=0&message=0

参考资料

{% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-object-persistence-mstg-platform-8" %}

☁️ HackTricks 云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥