前言
对于车联网安全研究来说,大家应该都很熟悉ADB。ADB(是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具,它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell的访问。
Some ADB basis to begin
深入研究ADB有以下几个好处:
ADB是Google提供的一套调试工具集,于2008年随第一个版本的Android,即Android 1.0一同推出。虽然对于Android开发和调试至关重要,但ADB并没有直接包含在AOSP(Android开源项目)中,而是作为Android SDK(软件开发工具包)的一部分。该项目维护良好,其全部代码也是开源的,并可在android.googlesource.com获取。
ADB的主要目的是Android设备与开发机器之间的通信。它包括三个主要组件,大部分是用C++编写的:
• 客户端:安装在主机计算机上,与服务器交互。客户端和服务端实际上是相同的二进制文件,服务端只是根据客户端的需求通过fork()和execve()来启动。
• 服务器(称为host):同样安装在主机计算机上,它的主要角色是多路复用到“设备”的连接(这些设备可以是物理的或虚拟的),以及抽象传输层(可以是USB或TCP)。
• 守护进程(称为adbd):位于Android设备的“系统”分区内,它运行一个主循环等待连接,并处理连接以启动服务(如帧缓冲区、JDWP(Java调试有线协议)等)、发送或接收文件、执行命令等。其源代码位于adb/daemon文件夹下。
如前所述,客户端和服务端共享了大部分相同的代码。然而,一些代码也与adbd共享,并使用编译器指令有条件地包含。ADB_HOST指令标记适用于客户端和服务端的代码,而__ANDROID__则标识与adbd守护进程相关的特定部分代码。
从安全角度来看,除非明确授权,否则主机无法与设备通信。要建立连接,必须在开发者选项设置中启用USB调试功能(通过点击“Build number”五次进入隐藏面板)。当主机首次连接到设备时,设备上会出现一个确认弹窗,提示用户通过验证RSA密钥指纹来批准连接。快速浏览ADB源代码可以发现,主机使用的是默认存储在$(HOME)/.android/adbkey中的2048位RSA私钥。当新主机被授权连接到设备时,其公钥指纹会被保存在/data/misc/adb/adb_keys(仅可由“system”用户写入)或/adb_keys(帮助厂商预配置,不在生产设备上可用)。这种设置防止了每次连接时重复提示用户,并允许设备预配置带有预先批准的公钥。
这一认证过程仅发生在adb-server和adbd之间。然而,为了绕过服务器并直接与客户端互动,理解这个认证过程底层的工作原理将是必要的。
ADB protocol overview
在介绍了这些基本概念和三大主要组件之后,我们现在可以专注于这些实体之间用于通信的底层协议。Google在ADB仓库的README.md文件中提供了关于这些组件之间交互的详细而清晰的概述。
我们可以清楚地看到,该协议被分为两个不同的部分:
• 在左侧,ADB <-> ADB服务器:仅依赖于一种“smart”协议(基本上是指基于TCP/IP的协议),不论使用何种客户端(官方的adb客户端、ddmlib(Dalvik调试监视库)或其他第三方客户端)。
• 在右侧,ADB服务器 <-> ADB设备则完全不同:连接方式根据设备类型的不同而变化。物理设备可以通过USB或TCP/IP进行连接(通常用于同一本地或远程网络上的设备),而模拟器仅能通过TCP/IP访问。底层的智能协议与前者不同,并且服务器与物理设备之间的连接是在加密通道内进行的安全连接。
由于每一侧使用各自的协议,Google合乎逻辑地选择实现一个中间服务器,该服务器能够理解这两种协议,并在这两个世界之间架起桥梁。这种设计确保了ADB系统既可以处理多种类型的客户端请求,也能适应不同类型的Android设备连接方式,同时保证了通信的安全性和灵活性。
ADB Client <-> ADB Server
ADB服务器默认监听127.0.0.1:5037/tcp(尽管可以根据需要进行调整),并实现了一个相对简单的智能协议。
这个协议类似于LTV(长度类型值):一个请求以四个十六进制字节开始,指示数据的长度,随后是所需服务的文本表示,再之后是任何根据具体请求服务而定的可选数据(后面会提供示例)。Google选择发送命令的文本表示而不是像枚举这样的紧凑形式,是因为该协议设计之初就考虑到了从网络角度容易调试的需求。
在ADB的语境中,服务指的是客户端请求服务器执行的具体命令或操作。这些服务可以从查询服务器状态等简单任务到涉及与Android设备通信的更复杂操作,例如命令执行、文件下载/上传、设备日志流等。所有可能的服务请求及其相应用法的详尽列表可以在仓库中的SERVICES.md文件中找到。
host and local services
我们现在将专注于客户端可以请求的两种主要类型的服务:主机服务由服务器直接处理,无需查询或涉及设备来获取额外信息。相比之下,本地服务则与特定设备绑定,并由服务器转发给Android设备上的adbd守护进程进行处理。
主机请求的例子包括:
本地请求的例子包括:
自己编写ADB客户端的一个优势在于,它使我们能够访问官方ADB命令行界面未公开暴露的服务。
例如,帧缓冲区(framebuffer)服务允许转储设备的帧缓冲区以截取屏幕截图。该服务在SERVICES.md文件中有很好的文档说明,但却无法通过标准的ADB接口访问,而在设备的adbd上是可用的。
framebuffer:
This service is used to send snapshots of the framebuffer to a client.
It requires sufficient privileges but works as follow:
After the OKAY, the service sends 16-byte binary structure
containing the following fields (little-endian format):
depth: uint32_t: framebuffer depth
size: uint32_t: framebuffer size in bytes
width: uint32_t: framebuffer width in pixels
height: uint32_t: framebuffer height in pixels
With the current implementation, depth is always 16, and
size is always width*height*2
Then, each time the client wants a snapshot, it should send
one byte through the channel, which will trigger the service
to send it 'size' bytes of framebuffer data.
If the adbd daemon doesn't have sufficient privileges to open
the framebuffer device, the connection is simply closed immediately.
在自定义客户端中实现这个命令,相比使用经典的adb exec-out screencap -p > screen.png命令来截屏,可以加快截图过程。
Network interactions
下图展示了运行adb devices命令时adb客户端与adb-server(主机)之间的交互过程,以及发送未知命令(错误命令将产生相同的输出)所导致的结果:
-
客户端打开一个到服务器的TCP连接并请求其版本信息以确保兼容性。
-
服务器用OKAY响应确认请求。
-
服务器将其版本信息发送回客户端,然后关闭TCP连接。
-
客户端打开一个新的TCP连接,并要求服务器列出所有可用的设备。
-
请求被确认。
-
服务器回应一个结构化的对象(在本例中,这只是设备标识符和设备状态“device”,两者之间用空格分隔,类似于adb devices命令的输出),最后关闭这个连接。
-
发送未知命令会使服务器回应FAIL,并附带一条解释原因的上下文消息。
像Wireshark或tcpdump这样的网络捕获工具对于理解这部分协议的工作原理非常有用,因为这部分协议相对简单。然而,这种方法的一个限制是,Wireshark目前只能解析ADB版本低于1.0.31时客户端与服务器之间的网络数据包。尽管如此,通过直接检查原始TCP数据仍然可以获得协议的概览。
sync requests
sync命令是ADB协议中的一种特殊请求类型,它涵盖了四个底层操作:LIST、RECV、SEND和STAT。这些操作主要用于处理设备文件系统上的文件。
在sync模式下,协议结构与之前的交互保持一致,但需要一个特定的初始化过程。要进入此模式,必须首先通过sync:命令建立连接。这表明后续的交互将与文件同步任务相关。
• LIST:列出设备上目录的内容。
• RECV:从设备下载文件到客户端。
• SEND:从客户端上传文件到设备。
• STAT:获取设备上文件或目录的信息。
下图以通用方式(省略目标文件名)展示了执行adb push <源文件> <目标路径>命令时的网络交互:
Security considerations
使用ADB客户端 -> 服务器协议引入了若干必须在风险分析中考虑的安全风险:
• ADB通信中的TCP数据未加密,这意味着敏感信息可能被拦截,特别是在通过局域网(LAN)使用ADB时。
• 一旦设备完成配对,后续就不再需要进行认证,这使得如果有人能够与服务器交互,则存在未经授权访问的风险。
• 在网络配置不当(或故意为之)的情况下,默认监听于127.0.0.1的ADB服务器端口可能会暴露在互联网上。这可能导致与服务器配对的设备可以从世界任何地方访问,意味着设备变成了全球可达。(例如,Shodan.io索引了大量可用的设备……)
• 在ADB上可能存在(并且已经发现了)CVE(常见漏洞和暴露),这些安全漏洞会带来额外的风险。