摘要
平台安全是计算机安全体系中重要的组成部分。平台对上层应用,服务,功能提供支持,主要体现在硬件,固件,协议及协议实现等。这方面有许多攻击方法,比如边信道攻击,中间人攻击,旁侧降权攻击等。这些高级攻击方法,如果结合平台安全中的漏洞,将会十分危险。本文是360CERT对2017年平台安全的总结。
平台安全中的攻击方法
侧信道攻击
边信道最早的实践是通过采集加密电子设备在运行过程中的时间消耗、功率消耗或者电磁辐射消耗等边缘信息的差异性进行攻击的手段。而随着研究的深入,也逐渐从加密设备延伸到计算机内部CPU、内存等之间的信息传递等方面。
近年,这种攻击方法最典型的案例莫过于Linux下TCP边信道安全问题(CVE-2016-5696)。为了减少CPU和带宽资源浪费,要限制challenge ACK发出的数量,所以引入了这里的ACK Throttling机制。正是这个ACK Throttling机制,带来了边信道攻击的可行性。
利用边信道攻击方式,攻击者不需要处在“中间人”的位置,整个过程不需要与受害者进行互动,这种攻击手法在平台安全中应用广泛。
中间人攻击
中间人攻击(Man-in-the-MiddleAttack,简称“MITM攻击”)是一种“间接”的入侵攻击,这种攻击模式是通过各种技术手段将受入侵者控制的一台计算机虚拟放置在网络连接中的两台通信计算机之间,这台计算机就称为“中间人”。这种攻击方法通过拦截正常的网络通信数据,并进行数据篡改和嗅探,而通信的双方却毫不知情。MITM由来已久,但在今天仍然活跃,如SMB会话劫持、DNS欺骗等攻击都是典型的MITM攻击。
2017年披露了CVE-2017-0783和CVE-2017-8628,攻击者利用这两个漏洞,可以分别在Android设备和windows设备上进行MITM攻击。
降级攻击
降级攻击主要应用在安全协议方面,比较典型的一个例子便是4G LTE攻击。利用了3GPP的漏洞取得手机的IMSI码,通过DoS攻击迫使手机接入黑客控制的虚假GSM网络中。或者把手机导入一个与运营商网络连接的受黑客控制的合法基站上,从而能够对手机通信进行窃听以及对上网流量进行嗅探。这种攻击方法的应用还有很多,比如HTTPS降级攻击,TLS降级攻击等
其他
其他情景的攻击方法同样适用于平台安全中,比如暴力猜解,重放,接口鉴权攻击等。
还有许多不常用的攻击方法,只能针对特定的环境。比如2017的WPA2密钥重载攻击,他让我们意识到,消息可能丢失的协议可能会变得特别脆弱,毕竟这些协议用设计用来重传帧时,就有可能密钥重载。
下面就今年几个比较典型的平台安全漏洞及攻击方法进行详细介绍。
Intel ME固件漏洞
今年五月份, Intel公司公布了一个严重高危级别安全漏洞,攻击者可以在目标操作系统不可直接访问的区域进行加载/执行任意代码,具备极高的隐蔽性,常规方法无法检测到。酷睿,至强,凌动等部分型号均受影响。
事件描述
Intel 芯片中有一个独立于 CPU 和操作系统的微处理器,叫做英特尔管理引擎 Intel Management Engine,简称 ME。多种技术基于ME,例如代码处理、媒体DRM、可信平台模块TPM等。
ME 是一个有别于 CPU 的独立系统,它可以在不受 CPU 管控下通过搭配 AMT(英特尔主动管理技术)来远程管理企业计算机。AMT 技术能够自动执行一个独立于操作系统的子系统,使得在操作系统出现故障的时候,管理员能够在远程监视和管理客户端、进行远程管理和系统检测、软硬件检查、远端更新 BIOS 、病毒码及操作系统,甚至在系统关机的时候,也可以通过网络对服务器进行管理操作。
该漏洞主要存在英特尔管理引擎(ME ),英特尔服务器平台服务(SPS),英特尔可信执行引擎(TXE)。攻击者可以模拟ME/SPS/TXE,来影响本地安全认定的有效性,在目标操作系统不可直接访问的区域进行加载/执行任意代码,具备极高的隐蔽性,常规方法无法检测到。
总结
根据intel官方公告,相关产品漏洞一共有8个CVE:CVE-2017-5705、CVE-2017-5706、CVE-2017-5707、CVE-2017-5708、CVE-2017-5709、CVE-2017-5710、CVE-2017-5711、CVE-2017-5712。酷睿,至强,凌动™,赛扬™等部分型号产品受到该漏洞影响。
事实上,这并不是英特尔第一次被曝出产品存在严重漏洞。Intel ME固件漏洞相对于操作系统,用户是完全透明的。操作系统的一切安全机制,漏洞缓解机制都是无用的。
Intel ME固件漏洞主要影响的是服务器,个人PC平台。巧合的是,今年的一枚博通wifi芯片漏洞影响数十亿台Android 和 IOS设备,移动设备在今年也被披露存在平台安全问题,未能幸免。
博通wifi芯片漏洞
今年披露的一枚名为BroadPwn远程代码执行漏洞, 影响Android 和 iOS 数十亿台设备。7月初,谷歌,苹果陆续发布了安全补丁。未进行安全更新的设备,一旦置身在恶意WiFi范围内就会被黑客捕获、入侵。当手机打开wifi时,无需任何操作,攻击者便可在我们毫无察觉的情况下,完全控制手机,这是多么恐怖的事情。
背景及相关知识
在过去的一段时间,Wi-Fi的使用再移动设备上已经普及。逐渐地,涉及物理层,数据链路层的Wi-Fi已经发展成为一套健全的规范。为了拓展和解决各种未知的复杂问题,供应商已经开始生产基于“FullMAC”的Wi-Fi SoC。这些是小的SoC执行所有PHY, MAC和MLME数据处理。FullMAC芯片容易集成,在固件中实现MLME处理,这种解决方案降低了主机端的复杂性,十分受厂商欢迎。但是引入这些新硬件,运行专有和复杂的代码库,可能会削弱设备的整体安全性,引入危及整个系统的漏洞。
技术分析
参考Google的Project Zero团队对该漏洞的分析,问题出在内部通信渠道。
上图是追踪处理事件框架(dhd_wl_host_event)的入口点的控制流程,我们可以看到几个事件接收,并被独立处理。一旦初始完成,帧就被插入队列。然后事件由内核线程出队列,其唯一用处是从队列中读取事件并将其分派到相应的处理函数。这种关联是通过使用事件的内部“event_type”字段作为处理函数数组的索引来完成的,采用的evt_handler。
该漏洞太过复杂,一些先决条件我们不进行探讨,直接指出到漏洞关键点:处于dhd_handle_swc_evt 函数的total_count字段。
漏洞的逻辑可归结为:
- “ WLC_E_PFN_SWC ” 类型的事件处理SWC。
- 通信中的每个SWC事件帧包含事件(wl_pfn_significant_net_t),总计数(total_count )和数组中的事件数(pkt_count )。
- 当接收到SWC事件代码时,触发一个初始处理程序来处理事件。处理程序在内部调用“ dhd_handle_swc_evt ”函数来处理事件的数据。
- dhd_handle_swc_evt处理函数无法验证total_count 和pkt_count 之间的关系。
关键函数:
“event_data”是通信的事件中封装的任意数据,函数首先初始化一个数组来保存事件的总数(如果之前没有分配的话),然后在缓冲区中建立results_rxed_so_far与传入数据的联系。但是,处理程序无法验证total_count 和pkt_count 之间的关系!攻击者可以指定一个小的total_count 和一个大的pkt_count ,触发一个简单的内核堆溢出。之后可以通过一些堆溢出利用方法,实现远程代码执行。
总结
该漏洞影响Android 和 iOS 数十亿台设备。我们使用的智能机,平板电脑,都支持wifi功能,如果使用了博通受影响芯片的设备,均在危险之中。wi-fi芯片这种基本的元件存在的漏洞,如果被利用的话,那么会有杀伤力会很惊人。我们都知道现在的智能机都支持热点功能,如果将该漏洞做成蠕虫勒索病毒,感染后,开启免密热点吸引其他手机连接,通过无线网络进行传播,俨然一场低配版的Wannacry。
说到wifi芯片漏洞,不得不提今年披露的WPA2 KRACK(密钥重载攻击),不止我们使用的设备不安全,我们wifi使用的WPA2加密协议也存在问题。
WPA2 KRACK(密钥重载攻击)
2017年10月16日,针对WiFi+WPA2网络,名为KRACK的漏洞攻击方式被披露。KRACK主要是利用802.11i ,4次握手中的漏洞来最终实现解密和伪造加密的WiFi流量,该漏洞由来自imec-DistriNet的Mathy Vanhoef和 KU Leuven发现。本次漏洞事件有多种攻击型态,AP热点端,中继端,和客户端均受到影响。根据krackattacks.com和部分厂商发布的安全公告综合分析,包括Linux,Android, Cisco wireless products, OpenBSD, MacOS, Windows, iOS等产品或平台受到影响。
相关知识
当客户端要连接 WiFi 网络,自动开始(互相)身份验证和连接。图 2 描述了连接阶段的握手。但是当第一次连接到网络时,是没有实际的身份验证。相反,使用了开放系统身份验证,对客户端进行身份验证。实际身份验证在四次握手中使用。但真正的身份认证仅在两个采用 fast BSS transition 握手协议的相同网络 AP 之间漫游时使用。在开放式身份验证之后,客户端连接到网络中。通过客户端向 AP 发送一个连接请求完成。这条消息包含客户端希望使用的成对的密码组。AP 回复一个连接响应,通知客户端连接是否被成功建立。
图1
四次握手提供相互身份验证,基于共享密钥技术,这种技术称为成对的主密钥 PairwiseMaster Key(PMK),并协商一个新的会话秘钥 PairWise Transient Key(PTK)。在这次握手中,客户端称为 supplicant,而 AP 称为 authenticator,PMK 由个人网络中的预共享密码生成,在企业网络中使用 802.1x 身份验证来进行协商。PTK 由 PMK,Authenticator Nonce (ANonce),Supplicant Nonce (SNonce)和 supplicant 和 authenticator 使用的 MAC 地址派生而来。一旦生成,PTK 被分割成确认 key(KCK), 加密 Key(KEK),和临时 Key(TK),确认 Key 和加密 Key 使用来保护握手消息,TK 和数据机密性协议是用来保护正常数据帧,如果使用了 WPA2,四次握手协议也传输现在的 Group Temporal Key 组临时密钥(GTK)到 supplicant。
四次握手中的每一条消息都是使用 EAPOL 帧格式(如图 1)。对字段进行介绍首先,消息的头部定义了所代表的消息类型,我们将使用 message n 和 MsgN 来代表四次握手中第 n 段消息。Replay count(重放计数器)字段用于检测重放的数据帧:authenticator 在发送一个帧之后会自增长,当 supplicant 对 authenticator 发送的 EAPOL 帧做出应答时,它使用相同的 replaycount。Nonce 字段是一个随机的 nones 值,这个随机值是 supplicant 和 authenticator 在生成新的会话秘钥这一步骤产生的。接下来,如果 EAPOL 帧传输一个组密钥,RSC(接受序列)包含了 key 起始包号。组密钥是存储在 Key Data 字段,使用加密 Key(KEK)加密。最后,使用消息确认 Key(KCK)来进行完整性校验. MIC(Message Integrity Check)。
图2
四次握手中的第 N 条消息,重放计数器 replay count 为 r, 给定的 nonce,在’;’之后的参数都存储在数据域中,也就是说会使用 KEK 加密。
- Authenticator 通过发送 message 1 来初始化四次握手。包含 ANonce,是唯一一个没有MIC(完整性校验) EAPOL 格式消息。
- 当收到消息时,suplicant 生成一个 SNonce 而且导出 PTK,suplicant 发送 message2 给authenticator,message2 包含了(SNonce)。
- authenticator 收到 SNonce,也会导出 PTK。并且发送组密钥 GTK 给 supplicant。
- supplicant 在安装 PTK 和 GTK 之后回复 message4
- authenticator 收到 message4 之后也会安装 PTK,其中 GTK 在 AP 启动时就已经安装。
1,2 条消息使用来传输 nonces,最后两条消息是用来传输组密钥 而且使用抵御降级攻击注意:在已经存在的连接中,PTK 可以被刷新初始化新的四次握手。在密钥重载的过程中,所有的四次握手
消息都是使用 PTK 完成数据机密性加密的。
技术细节
802.11i协议(即:WPA2协议)通过两种独立的机制来保证数据传输的机密性。
第一个是在记录层通过加密WiFi帧的方式,保证明文无法被读取或嗅探。该加密机制通常是通过AES-CCM的方式,当然也有部分启动GCM模式,还有部分老的RC4-TKIP方式。需要认真考虑的是AES-CCM(还包括GCM, TKIP)是一种流加密,这意味着在重用加密参数key和nonce(即:初始向量)的情况下是可以被攻击的。802.11i是基于包计数(packet number number)的方式,其在会话建立后的初始值为0,且会不停递增(当然到了2^48的时候,会触发更新key操作)。这样一来,假设在包计数不被重置的情况下,就可以成功防范key+nonce的重用攻击。第二个机制是AP和客户端(supplicant)之间的4次握手流程,主要用于协商加密key。KRACK漏洞会直接利用到4次握手中的#3包,#3包可作用于客户端新key安装使用。
KRACK的主要漏洞在于 #3包可以被恶意阻断。当这个情况发生时,AP端会重发这个消息,会导致同样的一个key在客户端中被重装。带来的副作用是也会导致包计数会被重置为0(部分客户端,如Android6,会把key重置为0),最终,就会触发key+nonce的重用攻击了。攻击者可以利用它来全流量解密,TCP劫持等。
此外,还有如下2种攻击:
- 包括针对客户端的基于GTK的攻击;
- 针对AP端的11 RFT握手攻击;
https://github.com/vanhoefm/krackattacks-scripts
目前公开poc都是只针对客户端,和服务器进行安全检测,但不排除已经有一键傻瓜式工具利用。
总结
针对客户端的攻击类似中间人的形式,需要迫使无线客户端从AP连接到攻击者伪造的AP上,所以漏洞利用需要在一个有限地域范围内进行攻击,漏洞利用需要有针对性;不需要与被攻击者产生任何交互,漏洞利用触发难度小,对于针对性的实战利用是很有意义的。
漏洞存在于linux,Android到windows各种终端,可以对一些明文传输或者不正确配置的https网站进行嗅探,数据捕获,考虑到现阶段安全状况,利用效果较好。同时,WPA2 KRACK(密钥重载攻击)并没有从根本上打破WPA系列密钥体系基本的安全特性,暂时不存在更换加密方式,只需要针对特定客户端和AP进行修复。考虑到无线设备更新修复难度,建议在需要高安全性环境时,进行无线连接时采取vpn等方式加密进行连接。
360CERT建议广大用户:
- 及时更新无线路由器、手机,智能硬件等所有使用WPA2无线认证客户端的软件版本。
- 合理部署WIPS(无线入侵防御系统),及时监测合法WiFi区域内的恶意钓鱼WiFi,并加以阻断干扰,使其恶意WiFi无法正常工作。
- 无线通信连接使用VPN加密隧道及强制SSL规避流量劫持与中间人攻击造成的信息泄漏。
- 在不使用WiFi时关闭手机WiFi功能,公共WiFi下不要登录有关支付、财产等账号、密码。如需登录、支付,将手机切换至数据流量网络。
- 及时更新官方补丁:
Linux的hostapd和wpa_supplicant 补丁地址:https://w1.fi/security/2017-1/微软在Windows 10 操作系统中发布补丁 KB4041676苹果在最新的 beta 版本iOS、macOS、 tvOS和 watchOS中修复了无线网络安全漏洞。
BlueBorne蓝牙漏洞
上述的三个漏洞和攻击方法分别分别属于引擎,固件,协议三个方面平台安全。此外,今年还有另外一些值得我们注意漏洞。
9月12日,armis披露了一系列蓝牙的漏洞,手机开启了蓝牙,就可能被远程控制。无接触无感知接管系统的能力有点可怕,而且基本上影响所有的蓝牙设备,危害不可估量。
所有Android智能机,平板,可穿戴设备均受到4个高危漏洞的影响,其中有两个是远程代码执行漏洞(CVE-2017-0781 和 CVE-2017-0782),有一个可被利用来进行MITM攻击(CVE-2017-0783),还有一个会导致信息泄露(CVE-2017-0785)。
Windos设备中Windows Vista以外所有版本系统均受“Bluetooth Pineapple” 攻击(CVE-2017-8628)影响,可使攻击者进行MITM攻击。微软已在今年7月11日发布安全更新,并在9月12日发布了相应的通知。iOS设备中iPhone, iPad, iPod在iOS 9.3.5及以下版本,AppleTV7.2.2及以下版本均受RCE(远程代码执行漏洞)影响。
背景及相关知识
首先给出armis的披露漏洞时,整理的蓝牙架构图:
图上把蓝牙的各个层次关系描述得很详尽,不过我们这里暂时只需要关心这么几层:HCI,L2CAP,BNEP,SDP。BNEP和SDP是比较上层的服务,HCI在最底层,直接和蓝牙设备打交道,而承载在蓝牙服务和底层设备之间的桥梁,也就是L2CAP层了。每一层都有它协议规定的数据组织结构,所有层的数据包组合在一起,就是一个完整的蓝牙包(一个SDP包为例):
虽然协议在各个平台的架构一样,但具体实现方式有所不同,Linux用的BlueZ,而Android用的BlueDroid。
- 在Linux里,用的是BlueZ架构,c 通过注册sock协议的方式提供了针对userspace的接口。
L2CAP的数据是由HCI层传过来的,在hci_core.c的hci_rx_work函数里处理,当L2CAP层有SDP数据后,通过sdp-server.c中的io_session_event来获取这个数据包,递交给sdp-request.c的handle_request。
- 在Android里用的时BlueDroid架构。这个和BlueZ架构很大不同的一点是:BlueDroid将L2CAP层放在了userspace。
SDP连接建立起来后,在收到SDP数据包之后呢,会触发回调函数sdp_data_ind,这个函数会把数据包交个sdp-server.c的sdp_server_handle_client_req函数进行处理。BNEP连接建立起来后,再收到BNEP的包,和SDP类似,会触发回调函数bnep_data_ind,这个函数包含了所有对BNEP请求的处理。
漏洞分析
Armis披露漏洞时,介绍了细节。360VulpeckerTeam对这几个漏洞进行了深入分析,这里引用借鉴下。
CVE-2017-1000251
这个漏洞触发的思路如下:
- 建立和目标机器的L2CAP 连接,这里sock_type的选择应该是SOCK_RAW,如果不是,内核会自动帮我们完成sent_infomation_request , send_connection_request, send_configure_request这些操作,也就无法触发目标机器的漏洞了。
- 建立SOCK_RAW连接,connect的时候,会自动完成sent_infomation_request的操作,不过这个不影响。
- 接下来我们需要完成send_connection_request操作,来确定SCID,DCID。完成这个操作的过程是发送合法的 L2CAP_CONN_REQ数据包。
- 接下来需要发送包含有L2CAP_CONF_EFS类型的数据,而且L2CAP_CONF_EFS数据的stype == L2CAP_SERV_NOTRAFIC的L2CAP_CONF_REQ包,这一步是为了让目标机器的conf_state变成CONF_LOC_CONF_PEND。
- 这里就到了发送cmd_len很长的L2CAP_CONN_RSP包了。这个包的result字段需要是L2CAP_CONF_PENDING。这个包发过去之后,目标机器内核就会栈溢出,要么重启了,要么死机了。
我们的漏洞发生在对L2CAP_CONFIG_RSP(config response)的处理上。那么来看l2cap_config_rsp:
staticinline int l2cap_config_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
...
scid = __le16_to_cpu(rsp->scid); //从包中剥离出scid
flags = __le16_to_cpu(rsp->flags); //从包中剥离出flag
result = __le16_to_cpu(rsp->result); //从包中剥离出result
switch(result) {
caseL2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len);
clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
break;
caseL2CAP_CONF_PENDING:
set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
if(test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
charbuf[64]; //buf数组大小64字节
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
buf, &result);
...
}
gotodone;
...
当收到的数据包里,满足result == L2CAP_CONF_PENDING,且自身的连接状态conf_state == CONF_LOC_CONF_PEND的时候,会走到 l2cap_parse_conf_rsp函数里,而且传过去的buf是个长度为64的数据,参数len ,参数rsp->data都是由包中的内容来任意确定。那么在l2cap_parse_conf_rsp函数里:
仔细阅读这个函数的代码可以知道,这个函数的功能就是根据传进来的包,来构造将要发出去的包。而数据的出口就是传进去的64字节大小的buf。但是对传入的包的数据的长度并没有做检验,那么当len很大时,就会一直往出口buf里写数据,比如有64个L2CAP_CONF_MTU类型的opt,那么就会往buf里写上64*(L2CAP_CONF_OPT_SIZE + 2)个字节,那么显然这里就发生了溢出。由于buf是栈上定义的数据结构,那么这里就是一个栈溢出。
CVE-2017-1000250
这个漏洞是BlueZ的SDP服务里的信息泄露漏洞。这个不像L2CAP层的连接那么复杂,主要就是上层服务,收到数据就 进行处理。那么我们也只需要关注处理的函数。BlueZ的SDP收到数据是从io_session_event开始。之后,数据的流向是:
io_session_event–>handle_request–>process_request。
SDP协议它有一个sdp_pud_hdr的头部,头部数据里定义了PUD命令的类型,tid,以及pdu parameter的长度,然后就是具体的parameter。最后一个字段是continuation state,当一个包发不完所要发送的数据的时候,这个字段就会有效。对于这个字段,BlueZ给了它一个定义:
typedefstruct {
uint32_t timestamp;
union {
uint16_t maxBytesSent;
uint16_t lastIndexSent;
} cStateValue;
} sdp_cont_state_t;
对于远程的连接,PDU命令类型只能是这三个:SDP_SVC_SEARCH_REQ, SDP_SVC_ATTR_REQ, SDP_SVC_SEARCH_ATTR_REQ。这个漏洞出现在对SDP_SVC_SEARCH_ATTR_REQ命令的处理函数service_search_attr_req里面 ,其功能有这几点:
- extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); 解析service search pattern(对应SDP协议数据结构图)
- max = get_be16(pdata); 获得Maximu Attribute Byte
- scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);解析Attribute ID list
- if (sdp_cstate_get(pdata, data_left, &cstate) < 0) ;获取continuation state状态cstate,如果不为0,则将包里的continuation state数据复制给
漏洞发生在对cstate状态不为0的时候,这部分代码:
sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
if (pCache) {
uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
pResponse = pCache->data;
memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
buf->data_size += sent;
cstate->cStateValue.maxBytesSent += sent;
if (cstate->cStateValue.maxBytesSent == pCache->data_size)
cstate_size = sdp_set_cstate_pdu(buf, NULL);
else
cstate_size = sdp_set_cstate_pdu(buf, cstate);
sdp_get_cached_rsp函数其实是对cstate的timestamp值的检验,如何过这个检验之后再说。当代码走到第五行处的memcpy时,由于cstate->maxBytesSent就是由数据包里的数据所控制,而且没有做任何检验,所以这里可以为任意的uint16_t值。那么很明显,这里就出现了一个对pResponse的越界读的操作。而越界读的数据还会通过SDP RESPONSE发送给攻击方,那么一个信息泄露就发生了。
CVE-2017-0785
这个漏洞也是SDP的信息泄露漏洞,不过是BlueDroid的。与BlueZ的那个是有些类似的。我们也从对SDP数据包的处理函数说起。 SDP数据包会通过sdp_data_ind函数送给sdp_server_handle_client_req。与BlueZ一样,这个函数也会根据包中的pud_id来确定具体的处理函数。这个漏洞发生在对SDP_PDU_SERVICE_SEARCH_REQ命令的处理,对包内数据的解析与上文BlueZ中的大同小异,不过注意在BlueDroid中,cstate结构与BlueZ中有些不同:
typedefstruct {
uint16_t cont_offset;
} sdp_cont_state_t;
关注漏洞处的代码:
Ⅰ,Ⅱ中代码可以看出,变量num_rsp_handles的值,一定程度上可以由包中的Maximu Attribute Byte字段控制。
Ⅲ中代码是对带cstate的包的处理,第一步是对大小的检查,第二步是获得cont_offset,然后对cont_offset进行检查,第三步就到了
rem_handles = num_rsp_handles – cont_offset
可以思考一种情况,如果num_rsp_handles < cont_offset,那么这个代码就会发生整数的下溢,而num_rsp_handles在一定程度上我们可以控制,而且是可以控制它变成0,那么只要cont_offset不为0,这里就会发生整数下溢。发生下溢的结果给了rem_handles,而这个变量代表的是还需要发送的数据数。
在④中,如果rem_handles是发生了下溢的结果,由于它是uint16_t类型,它将变成一个很大的数,所以会走到 p_ccb->cont_offset += cur_handles;,cur_handles是一个固定的值,如果这个下溢的过程,发生很多次,p_ccb->cont_offset就会变得很大,那么在5处,就会有一个对rsp_handles数组的越界读的产生。
下面的操作可以让这个越界读发生:
- 发送一个不带cstate的包, 而且Maximu Attribute Byte字段设置的比较大。那么结果就是rem_handles = num_rsp_handles,而由于max_replies比较大,所以num_rsp_handles会成为一个比较大的值。只要在Ⅳ中保证rem_handles > cur_handles,那么p_ccb->cont_offset就会成为一个非0值cur_handles。这一步是为了使得p_ccb->cont_offset成为一个非0值。
- 接收服务端的回应包,这个回应包里的cstate字段将会含有刚刚的p_ccb->cont_offset值,我们取得这个值。
- 发送一个带cstate的包,cont_offset指定为刚刚提取的值,而且设置Maximu Attribute Byte字段为0。那么服务端收到这个包后,就会走到rem_handles = num_rsp_handles – cont_offset 从而发生整数下溢,同时p_ccb->cont_offset又递增一个cur_handles大小。
- 重复2和3的过程,那么p_ccb->cont_offset将越来越大,从而在⑤出发生越界读,我们提取服务端返回的数据,就可以获得泄露的信息的内容。
CVE-2017-0781
BlueDroid中BNEP服务对于接受到的数据包的处理也不复杂:
- 解析得到BNEP_TYPE,得到extension位。
- 检查连接状态,如果已经连接则后续可以处理非BNEP_FRAME_CONTROL的包,如果没有建立连接,则后续只处理BNEP_FRAME_CONTROL的包。
- 去BNEP_TYPE对应的处理函数进行处理。
- 对于BNEP_TYPE不是BNEP_FRAME_CONTROL而且有extension位的,还需要对extension的数据进行处理。
- 调用pan层的回调函数。
值得注意的是,BNEP连接真正建立起来,需要先处理一个合法的BNEP_FRAME_CONTROL数据包。CVE-2017-0781正是连接还没建立起来,在处理BNEP_FRAME_CONTROL时所发生的问题:
caseBNEP_FRAME_CONTROL:
ctrl_type = *p;
p = bnep_process_control_packet (p_bcb, p, &rem_len, FALSE);
if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG &&
p_bcb->con_state != BNEP_STATE_CONNECTED &&
extension_present && p && rem_len)
{
p_bcb->p_pending_data = (BT_HDR *)osi_malloc(rem_len);
memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
p_bcb->p_pending_data->len = rem_len;
p_bcb->p_pending_data->offset = 0;
}
上述代码中,malloc了一个rem_len的大小,这个是和收到的数据包的长度相关的。可是memcpy的时候,却是从p_bcb->p_pending_data+1开始拷贝数据,那么这里会直接溢出一个sizeof(*(p_bcb->p_pending_data))大小的内容。这个大小是8.所以只要代码走到这,就会有一个8字节大小的堆溢出。而要走到这,只需要过那个if的判断条件,而这个if其实是对BNEP_SETUP_CONNECTION_REQUEST_MSG命令处理失败后的错误处理函数。那么只要发送一个错误的BNEP_SETUP_CONNECTION_REQUEST_MSG命令包,就可以进入到这段代码了触发堆溢出了。
CVE-2017-0782
这个也是由于BNEP协议引起的漏洞,首先它是个整数溢出,整数溢出导致的后果是堆溢出。
问题出在BNEP对extension字段的处理上:
上述代码中,ext_len = *p++的ext_len从数据包中获得,没有长度的检查,可为任意值。而当control_type为一个非法值的时候,会走到*rem_len -= (ext_len – 1),那么这里就很有说法了,我们如果设置ext_len比较大,那么这里就会发生一个整数下溢。从而使得rem_len变成一个很大的uint16_t的值。这个值将会影响后续的处理:
上面的代码中,bnep_process_control_packet()处将发生整数下溢出,使得rem_len成为一个很大的值(比如0xfffd),p_buf->len=rem_len处会将这个值赋值给p_buf->len。If()中,是回调函数处理这个p_buf,在BlueDroid中这个函数是pan_data_buf_ind_cb,这个函数会有一条路径调到bta_pan_data_buf_ind_cback,而在这个函数中:
memcpy用到了我们传进来的p_buf,而p_buf->len是刚刚下溢之后的很大的值,所以主要保证sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset,这里就会发生一次很大字节的堆溢出。
CVE-2017-0781和CVE-2017-0782导致了堆溢出,一般会使得com.android.bluetooth崩溃,但是这个进程崩溃系统不会有提醒,需要去logcat来找崩溃的日志。这是两个很有价值的堆溢出漏洞,结合前面的信息泄露漏洞,是完全可以进行远程代码执行的。
总结
现在关于这五个漏洞的PoC,github有很多,安装上pybluez和pwntools,嗅探到蓝牙地址,便可进行攻击,简单的演示如下:
我们使用的智能机,平板电脑,可穿戴设备大多都支持蓝牙功能。这些设备均受前面提到的几个漏洞的影响。当手机打开蓝牙时,无需任何操作,攻击者便可在我们毫无察觉的状态下,完全控制手机。Wifi芯片可能被黑,wpa2协议进行加密会被监听,现在蓝牙也不安全。普通用户,最主要的还是提高安全意识,及时更新设备的安全补丁。
总结
电脑CPU不安全,手机WIFI芯片有问题,无线上网有可能被窃听,用蓝牙也可能被攻击。用户需要警惕但也不必过度恐慌,这些都属于高级攻击方法,利用技术门槛比较高,不容易造成广泛性攻击事件。
平台安全中核心的两个问题:
- 固件安全
硬件对固件进行支持,固件对操作系统提供服务。这个“承上启下“的位置说明了他的重要性。固件中运行专有和复杂的代码库,不安全的固件会削弱设备的整体安全性,引入危及整个系统的漏洞。
- 规范的制定以及实现
规范,包括但不限于协议,格式,处理模型。这方面例如WPA2 KRACK密钥重载攻击是协议制定时,没有处理好重传帧的情况;又例如BlueBorne蓝牙漏洞是在各个平台中,规范实现时的出现的问题。
文中所讲的问题,仅仅影响到信息的安全。IoT,IoE,人工智能……一场又一场革命将我们带入智能时代。智能家居和自动驾驶这些科技产物已经融入了我们生活,如果不注意这方面的平台安全,危及的可是用户的生命和财产。所以,这些新兴科技的平台安全问题,将是我们之后关注的重点。
参考链接
https://www.intel.com/content/www/us/en/support/articles/000025619/software.html
https://googleprojectzero.blogspot.jp/2017/04/over-air-exploiting-broadcoms-wi-fi_11.html
https://papers.mathyvanhoef.com/ccs2017.pdf
https://github.com/kristate/krackinfo
https://blog.cryptographyengineering.com/2017/10/16/falling-through-the-kracks/
http://svn.dd-wrt.com/changeset/33525
http://bobao.360.cn/learning/detail/4556.html
https://www.armis.com/blueborne/
https://www.anquanke.com/post/id/86949