deeplink介绍
首先大家需要了解一下什么是deeplink,简单来说,deeplink是一种在网页中启动App的超链接。点击链接之后,Android系统会按顺序尝试以下操作:
- 如果用户指定了可以处理该 URI 的首选应用,就打开此应用。
- 打开唯一可以处理该 URI 的应用。
- 允许用户从对话框中选择应用。
然后就会打开应用中指定的活动。一般是在AndroidManifest.xml中指定intent过滤器,当然也只是一般来说。
<activity
android:name="com.example.android.GizmosActivity"
android:label="@string/title_gizmos" >
<intent-filter android:label="@string/filter_view_http_gizmos">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "http://www.example.com/gizmos” -->
<data android:scheme="http"
android:host="www.example.com"
android:pathPrefix="/gizmos" />
<!-- note that the leading "/" is required for pathPrefix-->
</intent-filter>
<intent-filter android:label="@string/filter_view_example_gizmos">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "example://gizmos” -->
<data android:scheme="example"
android:host="gizmos" />
</intent-filter>
</activity>
如上代码可以看到,http://www.example.com/gizmos和example://gizmos都可以解析到该activity。
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
<data android:scheme="app" android:host="open.my.app" />
</intent-filter>
如上所示,这不仅仅支持https://www.example.com和
app://open.my.app,还支持https://open.my.app和app://www.example.com.
URL验证不足
该漏洞原型类似于著名的价值8500刀的Facebook app漏洞,首先我们来看一下活动注册界面

<data android:scheme="insecureshop" android:host="com.insecureshop"/>
可以看到,根据data,我们可以构造出insecureshop://com.insecureshop这一类的deeplink链接,然后再查看一下com.insecureshop.WebViewActivity类下的代码。

首先对于(StringsKt.equals$default(uri.getPath(), "/web", false, 2, null)) 该语句来说,意味着我们需要在
insecureshop://com.insecureshop的基础上,再构建上/web参数,然后后面会发现没有进行url验证,那么我们就可以在后面构造意图来加载任意内容。
比如说此时构造一个insecureshop://com.insecureshop/web?url=的链接。
写出POC:
<html>
<body>
<a href="insecureshop://com.insecureshop/web?url=">click here to exploit</a>
</body>
</html>
进行测试。
使用python搭建简单的本地服务器
python -m http.server 8000


点击我们的poc代码。

此时点击打开后进成功进入webview。
然后此时我们将poc更改href="insecureshop://com.insecureshop/web?url=file:///sdcard/1.txt",查看能否打开本地文件。
不出所料也是可以成功打开。

这就是由于URL验证不足而导致的开放重定向。
弱主机校验
还是相同的类下,在下方还有一段添加url验证的代码

对于以上代码可以分析看出,确实是验证了url后面的内容,但是StringsKt.endsWith$default该语句表面,此时只需要后缀为insecureshopapp.com,还是可以利用deeplink链接进行重定向,此时只需要是attackerinsecureshopapp.com此类型的网址都有效。此处大家可以自行验证一下嗷。100%成功率。
总结
以上总结了简化后的两类deeplink漏洞,主要的难点其实还是在deeplink的收集上,因为目前的app中,deeplink的protocol://hostname比较好找,但是完整的URI还是比较难拼凑的。
何牛在之前的文章中提供了5种方法:
本地搜索:通过Mainifest文件筛选出自定义的deeplink URL scheme,进而在本地逆向代码中正则匹配,提取出尽可能完整的deeplink URI,注意不要漏过所有文件。因为以经验来看,deeplink可能出现在App的Java代码中、Asset目录的资源文件/js中,甚至还可能出现在so当中;
流量监控:对app进行抓包,利用HTTP抓包工具或者实现成burp插件监测流量中的deeplink,尽可能在app中点击各种场景,从请求包和返回包中正则匹配出完整的deeplink;
IPC监控:通过hook动态监测IPC通信中出现的deeplink,将Intent中的data提取出来,可以利用burp插件brida,甚至与流量监控整合;
远程爬取:对app Web端网页进行爬取,筛选出deeplink。不过这种方法我没有实践过,只是偶尔在网页源码中发现过。
基于deeplink特征:如果APP使用了一些路由分发的sdk,由于这类sdk有特定的规律,因此可以通过正则解析这类规律来获取到完整的deeplink。以ali arouter为例,可以通过提取build Route后面的path作为deeplink URI的path。提取build Autowired后面的name作为deeplink中的parameters。然后和第一步中获取到的内容进行拼接,从而获取到一个完整的deeplink。
何牛YYDS。
大家有什么问题可以在评论区一起讨论呀。