介绍
今年9月15日,Chrome61发布,它启用了WebUSB作为其默认功能。而WebUSB是一个Javascript API,可以允许网页访问已连接的USB设备。这里的USB设备是指系统和工业的USB设备,所以不支持常见的USB设备(比如网络摄像头,HID或大容量储存设备)。然而通过WebUSB API,很多其他的USB设备可以被访问,且当用户授权给网页时,自己可能根本不了解网页获取的访问权限级别。
这篇文章探寻WebUSB的功能,以深入了解其工作原理,攻击方法及隐私问题。我们会解释访问设备所需的过程,以及浏览器是如何处理权限的,然后我们会讨论一些安全隐患,并演示一个网站如何使用WebUSB来建立ADB连接来入侵安卓手机。
基础
当USB设备插入主机时,浏览器会读取设备发送的描述符,然后将其储存在内部USB设备储存器中。此过程由Chrome的浏览器内核Blink处理。日志可以在chrome://device-log(GET参数“refresh = 1”非常有用)中查看。
根据规范,设备可以在其二进制对象存储中的平台描述符中明确地声明对WebUSB的支持。
浏览器将每个USB设备存储在自己的设备存储器中。WebUSB的可访问性由本机驱动程序支持所决定。在Windows上,我们可以通过浏览器访问由WinUSB驱动程序处理的每个USB设备。其他的诸如大容量存储设备,网络摄像头或HID等就无法通过网络访问了,因为它们具有处理这些设备的专用驱动程序。
根据规范(和本博客文章),一旦设备注册,浏览器就会显示一条通知。看起来像这样:
但是,这种行为不容易重现。我们在以下系统上尝试过:
- Windows 7, Chrome 61
- Windows 10, Chrome 61
- Debian, Chromium 60 (启用了chrome://flags/#enable-experimental-web-platform-features)
- Debian, Google Chrome 61
- Arch Linux, Chromium 61
- Arch Linux, Google Chrome 61
Platform Descriptor中有一个有趣的元素叫做“iLandingPage”。即使规范将协议“http://”和“https://”作为前缀,我们也可以选择一个空协议,在这种情况下,我们应该可以在提供的URL本身中指定协议。
但是,Chrome已移除或根本没有实现注入任意URL前缀的功能。以下是源文件中名为“webusb_descriptors.cc”的代码片段。它解析接收到的描述头,包括“iLandingPage”。将URL前缀限制为“http://”和“https://”。
- // Look up the URL prefix and append the rest of the data in the descriptor.
- std::string url;
- switch (bytes[2]) {
- case 0:
- url.append("http://");
- break;
- case 1:
- url.append("https://");
- break;
- default:
- return false;
- }
- url.append(reinterpret_cast<const char*>(bytes.data() + 3), length - 3);
请求访问设备
网页可以打开提示请求访问设备,它必须指定过滤器来过滤可用的设备。如果过滤器为空,那么即允许用户从所有可用设备中选择设备。打开的提示如下所示:
用户可以看到所有(过滤的)可用设备。设备名称引用于自身所发送的产品名称。如果没有指定产品名称,Chrome会尝试通过有关设备的已知信息来猜测一个表达性的名称。然后,它会将设备命名为“来自<vendor_name>”的未知设备。用户选择设备并点击“连接”后,即可授予访问设备的权限。
权限处理
权限由Chrome的permission API处理。一旦向网页授予权限访问设备,权限会一直持续,直到用户手动撤销。处理权限的API根据其根源区分“网页”,即当具有匹配的协议,主机和端口时,浏览器就会认为这个网页与另一网页相同。浏览器识别唯一设备的行为不是很明显,用于识别的候选目标由设备在其描述头中发送。候选目标如下:
- GUID
- Vendor ID
- Product ID
虽然GUID是唯一的ID,但它不能用于识别设备。以下是多次插入和拔出测试设备的日志的截图,可见每次设备都有不一样的GUID,即便如此,每次插入后设备都被许可且可以访问,不需要进一步的许可请求。
这表明Chrome使用Vendor ID和Product ID的组合来标识设备。
访问设备
一旦网页被授予访问设备的权限,那么就可以访问它了。首先其必须打开设备,打开设备的过程中就开始了与设备的会话,然后设备会被锁定,这样同一浏览器会话中的其他选项卡就无法访问了。但是另一个浏览器的另一个网页仍然可以打开相同设备。
为了与设备进行通信,浏览器必须声明要与之通信的接口。在声明接口之后,主机上的任何其他应用程序都是无法声明的。使用声明的接口,页面可以与指定接口的端点通信。
接下来,页面启动控制传输来设置设备,这基本上指定了它希望与设备通信的方式以及所要求的确切功能。一旦设备设置好,它就可以传输数据,并且完成USB设备接口的所有功能。
检查WebUSB的支持
我们构建了一个小型概念性证明(PoC)工具,可以轻松确定WebUSB是否支持设备。该工具测试是否能至少声明一个已连接的USB设备的接口,如果存在,那么就意味着它可以与设备通信,因此该设备是被支持的。
不过该工具无法测试USB设备是否完全不受支持,因为无法声明接口的原因有所不同。该接口可以被另一个程序声明,或浏览器可能没有系统(Linux)的访问权限。
该工具是一个简单的静态网站。你可以点击这里下载。这是它的外观:
要测试设备是否支持,请单击“选择设备”按钮打开权限提示。此提示将列出所有可用的USB设备。通过选择所需的设备并单击“连接”,工具将打开设备,并遍历每个可用的界面,并尝试声明。结果记录在页面底部的表格中。被声明的interfaces列显示可以声明的接口编号。
如果要在其他地方使用受支持的设备,则需要刷新站点或关闭该选项卡。
安全性考虑
总体来说WebUSB是安全的,但是像所有新添加的代码一样,它扩大了代码库,因此也扩大了浏览器的受攻击面。这是一种新技术,所以问题是不可避免的,在这方面的一些安全状况已经有了初步意见。
WebUSB在Chrome的浏览器内核Blink中运行。因此,发现WebUSB中的内存崩溃可能并不比Blink中其他地方的内存崩溃更影响更大。
实现WebUSB的网站应确保节制使用XSS是一个优先事项。利用XSS漏洞的攻击者可能具有与网站相同的对已连接设备的访问权,期间用户并不会注意到。
处理WebUSB的权限对于用户可能不是很明显。当页面请求访问USB设备时,向用户发出的通知不包含任何警告,而该站点从这时起将具有对该设备的完整的,静默的USB访问权限。
我们构建了一个概念性证明(PoC)来证明这个问题。在这种情况下,基于WebUSB的ADB主机实现被用于访问连接的Android手机。一旦用户接受请求,该页面使用WebUSB可以从相机文件夹中检索所有图片。【点击这里下载PoC】
通过这种访问级别,网站不仅可以从文件系统中窃取每个可读取的文件,还可以安装APK,访问摄像头和麦克风来监视用户,并可能将权限升级到root。
该示例受到用户交互的高度限制,因此风险大大降低 – 用户必须向其手机授予网页权限,在其手机上激活USB调试,并最终允许来自主机的ADB连接。到目前为止,这只适用于Linux,因为在Windows中的实现相当不稳定。然而,它既可以作为在WebUSB上运行复杂协议的示例,也可以显示WebUSB请求的一次点击如何导致数据泄露。
您可以在下面的视频中看到PoC的操作。有两个虚拟机,左边的一个作为恶意的Web服务器,右边的一个作为受害者。网站连接到手机后,ADB连接在手机上确认。然后检索所有拍摄的照相机图像并将其显示出来。【点击这里下载源码】
视频地址:https://labs.mwrinfosecurity.com/assets/Uploads/WebADB-Demo.mp4
进一步的研究
进一步的研究可能集中在发现实现WebUSB的缺陷,并可能会披露内存崩溃bug。然而,代码库相对较小,并且新的修复也在持续写入。
另一个有趣的调查对象是用恶意的USB设备攻击Chrome。前者可能会发送错误的USB描述符,并可能在浏览器中触发未预期的行为。 Chrome可以为WebUSB(chrome://usb-internals/)添加虚拟测试设备,这很有帮助。这样的攻击向量需要物理访问设备,所以显得有点不太现实。
另外,在研究WebUSB或任何其他新的网络标准时,如Web蓝牙或Web NFC,请记住,这些功能日新月异,甚至一个月前的信息可能已经过时了。
总结
一般来说,由于在有限的审查期间管理和限制,WebUSB被确定具有良好的安全标准。支持的设备非常有限,WebUSB无法访问网络摄像头,HID和大容量存储设备。然而进一步研究后,我们发现这是一个有趣的技术,特别是在引入重大变化或附加功能时。
建议用户永远不要让不受信任的网站访问包含任何敏感数据的USB设备。这可能导致设备被入侵。
原文发布时间为:2017-10-18
本文作者:Covfefe
本文来自云栖社区合作伙伴51CTO,了解相关信息可以关注51CTO。