- A+
摘要
我们分析了802.11组秘钥的生成和管理。这些秘钥是用来保护WiFi通信的广播和多播。我们发现了几个问题,并通过解密一个典型的Wi-Fi网络的所有组(和单播)流量来说明它们的重要性。
首先我们来讨论一下802.11随机数生成器的设计缺陷,并提供了足够的熵量。通过在多个平台上预测随机生成的组密钥,证实了这一点。我们还检测了组秘钥在传输过程中的安全性。在这里我们发现了在四路握手机制中,可以使用降级攻击的方法来破解RC4加密的组密钥。RC4每个秘钥流包含了包含了带有16字节密钥的公共16字节初始化向量,初始的256字节的密钥流也缩减了。
我们研究了这种RC4独特的用法,发现只要捕获231次的握手信息就足够恢复128位的组秘钥。我们 也检测了组通信是否和单点通信隔离了。我们发现并没有这回事,事实是组秘钥也可以用来注入和加密单点通信。最后,我们提出了一种针对802.11协议的一种新的随机数生成器。
1、介绍
在过去十年,WiFi逐渐成为了公认的中线程无线通信标准。不仅是因为它被广泛应用,一些新的加强功能也让它的表现更加出色。不过有一个缺点是(加密的)流量很容易被截获。所以,WiFi的安全已得到业界的重视。例如,WEP加密协议可以被完全破解,攻击WPA-TKIP加密协议的展示,AES-CCMP加密协议的安全分析,四路握手安全性的研究等。然而,大多数研究只关注于成对秘钥和单播通信。组秘钥和组通信往往被忽视。
在这篇文章中,我们想说明在现代的Wi-Fi网络中,生成和管理密钥是一个关键但被低估的部分。特别地,我们研究了组密钥的生成及其对客户机的传输,以及组通信与单播通信之间的隔离。我们发现了在组密钥有效期内,这些阶段都存在问题。为了解决我们的一些发现,我们提出并实现了一种新的,从物理Wi-Fi信道中提取随机数的随机数发生器。
首先,我们先来看一下802.11标准中提出的随机数生成器。除其他事项外,接入点(AP)会使用它来生成组密钥。令人惊讶的是,我们发现在设计中就有缺陷--参考的算法运算速度很慢。我们检测过的实际运用这套算法的设备,都加强了生成器算法来提高它的速度。我们也证实了这些实际运用中随机数生成器可以通过预测来破解,在几分钟之内就能够算出组秘钥。
生成的组密钥会在四路握手期间传递给客户端。我们发现可以在四路握手期间进行降级攻击,迫使AP使用RC4算法来加密需要传输的组秘钥。我们分析了每条信息的RC4秘钥,和它对秘钥流中的重定向的影响。这表明,攻击者可以通过滥用重定向捕捉230到 232加密的组密钥数据包,来恢复128位密钥,准确的数目取决于网络配置。
FC | Addr1 | Addr2 | Addr3 | KeyID/PN | Data |
图1:简化的802.11数据帧,带有WAP2头部
组秘钥应该只能被用来加密广播和多播的数据帧,换句话说,成对秘钥和组密钥应该被正确地隔离,单播数据包不应该用组密钥加密。AP可以通过只发送,但从不接收组寻址帧来强制执行此操作。然而,我们测试的所有AP都没有提供这种隔离。这样就允许攻击者使用组秘钥来进行注入攻击,并反过来对Wi-Fi网络中发送的任何数据进行解密。
最后,我们提出了一种针对802.11标准的新型随机数生成器算法。它通过收集接收信号强度指示(RSSI)的测量数据来提取随机量。这些常用的无线设备上就有这些测量数据,而且即使没有背景流量也可以经行。我们算法生成自由量的速度大概是每秒3000位。即使攻击者能够以高概率预测个别RSSI测量量,但生成器的输出仍然保持高度的随机性。我们的主要贡献是:
- 我们证明了802.11标准中的随机数生成算法是有缺陷的,通过预测算法的输出,在实际应用中破解了算法,并得到组秘钥。
- 我们展示了在4次握手期间进行降级攻击,通过RC4加密算法的弱点解密出了组秘钥。
- 我们证明了组秘钥可以用来实现注入攻击,对Wi-Fi网络中发送的任何数据进行解密。
- 我们提出并实现了从无线信道中提取随机量的随机数生成器。
本文的其余部分组织如下。第2节介绍了802.11标准的相关部分。我们破解了802.11的随机数生成器。在第3节,第4节展示了对四路握手的降级攻击,并对其使用RC4加密情况下进行攻击。
第五节,我们使用组秘钥进行注入攻击和解密数据帧,包括单播帧。第六节,我们提出了一种新的随机数生成算法。最后在第七节中回顾了相关的工作,在第八节中进行了总结。
2、背景
这一些提供了一些802.11协议,四路握手机制,RC4密钥流
-
2.1、802.11 协议
当站点需要传输数据,它需要在数据包头部添加一个有效的802.11头部(详见图1)
这个头部包含了必要的MAC地址,用来路由数据帧。
addr1 = 接收方MAC 地址
addr2 = 发送方MAC 地址
addr3 = 目标 MAC 地址
图2:从搜索AP到四路握手流程
接入点(AP)向目的地收发数据帧,这个目的地可能是有线网络中的一个节点,或是WIFI中的客户端。如果是客户端手到的数据帧addr1 应该等于 addr3,因此,这次通信就会终止。例如,当客户端发送一个出站IP数据包,addr1等于AP的MAC地址,addr2包含了客户端自己的MAC地址。Addr3应该是路由器的MAC地址。
如果客户端希望发送一个广播或多播帧,例如组寻址帧,它首先应该将这个数据帧以单播的通信方式发给AP。这就意味着addr1中就是AP的MAC地址,addr3等于多播或者广播的目的地址。如果需要的话,AP会用组秘钥加密这个数据帧,然后向所有连接该AP的站点广播这个数据帧。
这个Frame Control (FC)域包含了ToDS 和 FromDS的标志位。如果数据帧是从客户端发送到AP上,则ToDS 标志位置1,反之,则FromDS标志位置1.如果数据帧经过加密,在图1的第5个域中只 会包含Key ID 和 Packet Number (PN)。
-
2.2、发现 APs 和协商秘钥
通过监听信标,客户端可以搜索附近的AP,AP会周期性地广播信标(详见图2).这些信标包含了AP支持的加密算法。当客户端希望连接到AP,而且已经选好加密算法,它会开始向AP发送连接请求。
图3:EAPOL-Key数据帧结构
这个请求包含了选好的加密算法。为了防止降级攻击,客户端和AP会将接收到的IE痛四路握手中选择的IE做一次验证。在这次握手中,客户端和AP也会相互验证,并协议生成成对秘钥Pairwise Temporal Key (PTK)。这个PTK是重要的协商秘钥。PTK的第一部分是Key Confirmation Key (KCK),它是用来验证握手信息。
第二部分叫做the Key Encryption Key (KEK),它是用来加密在握手期间的一些敏感信息。第三部分称为Temporal Key (TK),它是用在握手认证之后加密需要传输的数据帧。为了确保每次建立连接PTK都是新生成的,客户端和AP都会先生成一个随机数分别称为SNonce 和 ANonce。根据共享的密码,ANonce 和 SNonce、客户端和AP各自的MAC 地址,会生成衣蛾PTK。
在四路握手的第一次,AP 会发送ANonce到客户端(见图2)。在收到这条消息之后哦,客户端就会计算出PTK。在第二次握手时,客户端会发送SNonce,IE中也说明了所选择的加密算法,还有根据整条信息算出的Message Integrity Code (MIC)。注意MIC是用PTK秘钥中的KCK算出来的。在收到Msg2和SNonce之后,AP也会生成一个PTK。这样通信双方有一个相同的PTK,所有的数据包都会用MIC验证。
使用KCK和接受到的MIC,AP就可以验证Msg2的完整性。然后AP就可以检查Msg2中包含的IE是否与初始连接请求中的AP是否相匹配。如果不匹配,握手进程将终止。否则AP就会在应答中发送e Group Temporal Key (GTK),在IEs中列出AP所支持的加密协议。客户端会先验证Msg3的完整性,然后将其中的IEs与先前在信标中接收到的IEs 相比较。如果不同,握手将终止。否则客户端会向AP发送Msg4来结束这次握手认证。
四路握手的消息都使用EAPOL-Key帧格式,它最重要的域在图3中有介绍。Key Info域中包含了这个数据包是握手中的第几次进程的标志位。它也说明了是用什么算法来计算MIC,还有用什么算法来加密Key Data field(在第四章中有详细描述)。注意KCK秘钥是用来计算MIC,KEK是用来加密Key Data 域
图4:RC4在Python的伪代码实现
最后,Key IV域包含了初始化向量(IV),来确保Key Data域是用独一无二的秘钥加密。Key Data通常是用来传输组秘钥(GTK),和转化IEs。
-
2.3、RC4密钥流
RC4于1987年提出,和DES算法一样,是一种对称加密算法,也就是说使用的密钥为单钥(或称为私钥)。但不同于DES的是,RC4不是对明文进行分组处理,而是字节流的方式依次加密明文中的每一个字节,解密的时候也是依次对密文中的每一个字节进行解密。
RC4算法的特点是算法简单,运行速度快,而且密钥长度是可变的,可变范围为1-256字节(8-2048比特),在如今技术支持的前提下,当密钥长度为128比特时,用暴力法搜索密钥已经不太可行,所以可以预见RC4的密钥范围任然可以在今后相当长的时间里抵御暴力搜索密钥的攻击。实际上,如今也没有找到对于128bit密钥长度的RC4加密算法的有效攻击方法。
在介绍RC4算法原理之前,先看看算法中的几个关键变量:
1、密钥流:RC4算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节,因为密文第i字节=明文第i字节^密钥流第i字节;
2、状态向量S:长度为256,S[0],S[1].....S[255]。每个单元都是一个字节,算法运行的任何时候,S都包括0-255的8比特数的排列组合,只不过值的位置发生了变换;
3、临时向量T:长度也为256,每个单元也是一个字节。如果密钥的长度是256字节,就直接把密钥的值赋给T,否则,轮转地将密钥的每个字节赋给T;
4、密钥K:长度为1-256字节,注意密钥的长度keylen与明文长度、密钥流的长度没有必然关系,通常密钥的长度为16字节(128比特)。
清单1:基于Python的802.11标准随机数生成器[21, xM.5]
3、破解802.11RNG
在这一节,我们将验证802.11中随机数生成器的设计缺陷,我们通过预测组秘钥来破解一些无线产品以验证我们的看法。
-
3.1、802.11中提出的RNG
802.11标准的安全功能修正版本称为802.11i协议,同时包括基于软件的RNG [22, xH.5.2]。它从时钟和数据帧到达的时间中提取自由量。然而标准中提出的算法只起参考作用,实际应用中应该从更多来源提取自由量。而我们却发现在实际应用都是直接引用这个算法,甚至简化了它。
表一是将推荐的RNG算法写成GenRandom函数。第一个循环的输出是根据站点MAC地址、实时时间、局部变量、循环计数器计算出hash值。为了收集足够数量的数据帧接收时间来作为自由量,它会多次调用NetworkJitter函数。这就是LSB返回时间戳的底位字节。第20行标记的内容几乎就是照抄标准的内容。它表明了需要运行外循环32次,或者直到局部变量是“随机量足够”。没有具体地说明这到底是什么意思。标准中还提到了如果当前时间无效的话“currtime”这个变量可以置0,。然而却并没有说这样做到底会对RNG产生怎样的影响。另外,标准中也没有指明使用的时间戳最小分辨率应该是多少。它只提到发送和接收的数据帧时间戳应该尽量使用最高的分辨率,最后是1ms或者更高。最后,在指令中执行RNG时,两次调用GenRandom期间也都没有状态保存。
-
3.2、Analysis
在认真检查了RNG算法之后发现它有一些地方定义不明确,也会导致漏洞出现。其中的一个问题就在NetworkJitter函数上,GenRandom会调用这个函数256次。首先,第10行的 if语句就有一些歧义,这条IF 语句是检测在X秒内是否有通信数据,这样就可以在同一个网络数据包上重复调用,函数也就会返回相同的值。
另一方面,如果这条IF语句执行一次的时间是X秒,那么这个指令就会占用256*X秒的时间。而且,这个时间X也没有给出。在任何情况下,调用NetworkJitter 都要等待很长的时间,直到接受到新的数据包,或者重复调用返回相同的值。
当第10行的IF语句条件不满足,执行ELSE语句时,4次握手期间的数据帧到达时间就会被记录并使用。具体地说,它提到发起的四路握手。这是只有在客户端需要连接到AP上时,AP才可以执行的功能(看图 2)。因此,推荐的算法只适用于AP。
我们还注意到,如果AP在收到握手消息2之后经常中止进程(参见第13行),大多数客户端将在一定时间内将该AP列入黑名单。在此期间,客户端将不再试图连接到这个网络。因此不可以初始化和终止256 4次握手,这是随机数生成器是需要做的。我们得出这样的结论:函数NetworkJitter是在实践中无法使用。在此基础上我们猜想,在3.4节和经验证实,厂商不会应用这个函数。
另一个设计缺陷是调用GenRandom之后没有状态保存。因此,它的输出只依赖少量的网络流量和时间戳样本。一个好的设计是在一个集合中收集的随机参数,并定期补种这集合新的随机参数。如果处理得当,这可以防止RNG免受迭代猜测攻击,回溯攻击,等等。
所以我们认为这个参考的RNG算法是有问题的,它返回的字节熵值太低,而且调用这个算法会引起很严重的延时。在第3节和第4节中我们将证明,在实践中这种结构导致随机数生成器存在有缺陷,还有生成的随机数是可预测的。
-
3.3、生成组秘钥
802.11标准定义了,但没有强制,一个秘钥树来生成组秘钥[21, x11.6.1].
这个秘钥树在目录2中有描述,macaddr是代表AP的MAC地址,currtime可以是当前时间或者是0. on startup函数在启动时就会执行,并且生成一个随机辅助秘钥称为Group Master Key (GMK)。
另外,它会将主要的计数器变量初始化为伪随机值[21, x11.6.5]。真正的组秘钥,称为Group Temporal Keys (GTKs),是使用new_gtk中的Pseudo-Random Function (PRF)函数,根据GMK and 秘钥计数器生成的。
GTK生成的长度是根据保护组通信的加密算法来确定的。如果使用的是TKIP,那么GTK就是32字节。如果使用的是CCMP,GTK就是16字节。这意味着PRF必须生成128或256位密钥材料,这取决于网络的配置。因此我们使用PRF-X函数,X的值取决于请求的键控材料的数量。
注意PRF-256的实现如清单1所示,这个函数和PRF- 128相似。最新的标准还规定:
“GMK是一个辅助秘钥,有时可以用来生成GTK。这可以在AP中配置,当GMK被破解时,可以来减少数据曝光”
如果密钥本身泄漏,引入一个新的密钥来减少影响是没有意义的。奇怪的是,我们发现,老版本的标准并不包含这种描述的GMK。相反,旧版本上说明,在当前的GMK值被泄露的情况下,可以重新初始化GMK来减少数据的曝光。
大多数实际应用都会通过调用一个和new _gtk类似的函数来每个小时都更新GTK。更重要的是,秘钥计数器也被用来初始化EAPOL-Key数据帧中的Key IV域(详见图 3)。初始化后,计数器就会加一。因为这些IV是公开数据,那么计数器的值就很容易被攻击者获取。我们发现一些实际应用中还将这个计数器在四路握手期间用来生成一些特定的值,这个显然是不推荐这么做的。
这个推荐的秘钥树一个主要的缺点是在new_gtk生成新的组秘钥时,新的熵值往往不会被采用。因此,一旦GMK的值被泄露,或者被攻击者覆盖,接下来所有的组秘钥都会很容易被预测到。
因为在标准中是假设GenRandom提供的是加密型的随机数。所以这样看来使用这个秘钥树是没有什么优势的。相反,AP可以直接调用GenRandom来生成组密钥。一些人认为这个密钥树是基于旧802.11标准的一个加强,而且还不要求设备必须要有一个强大的RNG。
也许这个结构唯一的优势是第一个组密钥会调用两次GenRandom,而以前只用一次。因此,一个攻击者如果想攻击GenRandom执行漏洞,他就必须两次准确预测这个函数的输出(详见 3.4)。目前在实际应用中允许直接生成自由值来计算出GTK。
目录2:基于Python的秘钥树实现
-
3.4、实际验证
我们现在研究实际802.11平台的RNG。首先,我们研究了一些比较热门的无线设备。为了评估某个品牌的知名度,我们调查了两个比利时城市的无线网络。我们能够根据信标中特定于供应商的信息元素识别特定的品牌。我们检测了6803个网络,发现MediaTek- and Broadcombased这两个牌子仅AP就覆盖了所有Wi-Fi网络的至少22%。另外,我们还检测了Linux系统中的 Hostapd,还有嵌入式系统中的 Open Firmware 项目。我们发现,除了Hostapd之外,其他平台生成的都是一些可预测的随机数。
3.4.1 基于MediaTek的路由器
接入点使用的是MediaTek发射器,并采用内核之外的Linux驱动来控制radio1。这些驱动可以直接管理四路握手和秘钥生成。他们采用如目录1所示的802.11 RNG,但没有调用NetworkJitter。这进一步验证了这个函数在实际中是没法用的。这也意味着自由量的来源是实时时间,它是来自Linux 内核中的瞬间计数器。
这个计数器在初始化时会被赋予一个固定值,在CPU每次执行时间中断时都会加一。每秒执行时间中断的次数可以在编译时设置,正常都在100 到 1000之间。因此它是一个底精度的时间戳,这就意味着currtime这个变量可能每次从GenRandom中获取的值都是一样的。也就是说,实时时间是随机数的唯一来源,可是熵值很小。
组密钥树的实现是参考802.11标准,但有一个改动。目录2中的第七行是将key_counter赋给gnonce,而实际应用是从GenRandom中生成一个新值赋给gnonce。
我们使用Asus RT-AC51U预测出组秘钥来说明RNG的设计是有缺陷的。只要是使用MediaTek 发射器的路由器都可以实现。第一步就是在启动时去预测GMK。通过重新编译固件,导出jiffies值。这个值是用在开始和结束调用GenRandom,我们观察到它使用到最多两个不同的值。注意,我们都是在结束调用GenRandom后才导出这个值,为了确保我们没有影响使用jiffies值。
在执行GenRandom后jiffies值最多加一。因为这个递增可能发生在32个循环中,在jiffies 初始值已知的情况下,GenRandom调用之后可能导致32种不同结果。如果用AES-CCMP来加密组通信,在生成GMK时jiffies值可能就会在[232-72889;232-72884]范围之中。
如果使用WPA-TKIP加密协议那它的范围应该就是[232 -73067;232 -73061]。连接的USB或以太网设备、以太网流量或其他Wi-Fi选项的数量没有影响这些估计。这些设备没必要去看到底是用AES 或TKIP加密协议,因为这两个协议用到的初始值只有10个左右。
第二步是估计在GTK中jiffies的计数,例如,组秘钥的生成。默认情况下,每小时生成一个新的组密钥。因此,如果我们知道路由器的正常运行时间,我们可以确定当前的组密钥是何时生成的。很方便地,信标通常都会在时间域中泄露设备的运行时间。这个时间域是用来在两个站点间同步时间[21, x10.1],启动时初始化通常是0。因此它的值就可以反应路由器的运行时间。从这里我们就能估计出在生成组秘钥是jiffies计数值。
然而,机器的时钟都会有偏差,这样会影响我们的预测。通过记录jiffies的值,我们观察到因为时钟的偏差,我们预测的jiffies会最多偏差4500。因此,即使运行一个月,我们预测的jiffies值和实际的大概只相差50000。
我们写了一个OpenCL程序来搜索GPU中的组秘钥。通过解码每个数据包的其实8个字节,检查它们是否与LLC/SNAP头部相匹配,以此来确定是与组秘钥相关的数据包。如果目标路由器已经运行了一年,那就必须测试320 _ 50000 _ 32 _ 22相关的数据包来恢复组密钥。
然而,检查每个数据包是相当耗时的,它需要计算33 _ 4个SHA-1哈希值来得出密钥,我们必须再解密每个数据包的前8个字节来核实是否使我们想要的数据包。而且,在我们的NVIDIA GeForce GTX 950M中,它大概需要2分钟来测试229个可疑对象和恢复GTK。我们通过预测由Asus RT-AC51U生成的秘钥成功证明了这个结论,而且这个设备运行了一个月。MediaTek驱动的设备生成的组秘钥可以被暴力破解,只要用到普通的设备,很容易就能实现。
3.4.2 Broadcom 网络认证
网络访问服务器Broadcom中用到了4次握手机制,包括生成一些必要的密钥。它在实际中应用了802.11标准提出的密钥树(详见目录 7)。另外,它使用key_counter 这个变量来初始化EAPOL-Key帧中的Key IV域。然而,它并没有按照802.11标准中提出的方法来实现RNG,相反,它采用RNG取决于设备所使用的内核。
当程序在VxWorks 或 eCos内核上运行时,随机数是以当前微秒时间内的MD5校验和来生成的。既然是用到MD5,那么每个调用中只生成16字节的猜想随机数据。在第5版或者更高WRT54G路由器中,VxWorks内核应用的范围会更加广。而且Apple AirPort也是用VxWorks内核。
为了预测这些设备生成的组秘钥,我们只能先去预测GMK的值。这就回到刚刚提到的key_counter的值会在Key IV域中泄露,而这个很容易就能被嗅探到。因为GMK是一个32字节的值,它通过调用随机数生成器两次来进行初始化。为了预测出这两次调用的输出值,我们就要先确定路由器开始运行后多久会生成组秘钥。这个和MediaTek的例子很像,开始时间可以在信标的时间戳区间找到。
假设我们可以预测出组秘钥的生成时间,并且误差在一秒之内,那么下次调用RNG的时间最多不超过10ms,那我们就必须去检测1000000 -10000 ≈233个秘钥。我们写出一个程序叫做OpenCL来模拟这样的查找,是在GeForce GTX 950M平台上,大概花了4分钟检测完了所有可疑的秘钥。因此只要用普通的硬件就能预测出RNG生成的组秘钥。
而对于Linux内核,自由字节可以在/dev/urandom伪随机设备中读到,而在路由器和嵌入式系统中这个伪随机设备在设备是可预测的,这再次说明组秘钥可能会被预测出来。
目录3:Open Firmware project 中的随机数生成器
3.4.3 Linux的Hostapd Daemon
Hostapd中实现802.11的组秘钥树可以在目录2中看到。然而,使用一个类似于new_gtk函数生成一个新的组秘钥,它也采样和合并新的熵。另外,Hostapd没有采用802.11中的RNG。相反,它通过读取伪随机设备中的值来生成秘钥。如果没有足够的熵,当第一个客户机试图连接时,它将重新采样。如果仍然没有足够的熵可用,客户端不允许连接所有的组合,这意味着hostapd使用的秘钥应该是安全的。
3.4.4 开源的 Firmware项目
Open Firmware的项目,以前被称为Open-Boot,是一个基于forth语言的免费和开源的引导装载程序。有趣的是,它在启动过程的早期阶段提供了基本但安全的Wi-Fi功能。因为在这个阶段没有加载操作系统,这是观察厂商在嵌入式环境中实现随机数生成再不能理想的环境了。
现在,Open Firmware的WIFI模式只提供客户端功能。因此我们只关注在四路握手期间随机数的生成。目录3说明了Open Firmware是如何生成自由数的。总结一下,加载Wi-Fi模块时,生成一个随机的初始随机数,这个随机数递增,无论何时使用。在这方面,该算法遵循802.11标准。然而,最初生成的随机数是非常弱的。它通过在线性同余发生器中运行这个函数两次,结合自己的MAC地址,最后使用伪随机函数(PRF)拓展这个数据生成随机数。所有这些信息都可以被攻击者预测或暴力破解。
我们把这个薄弱的结构归结为一个粗心应用,这也表明了一个好的设计应该是由WIFI芯片内部自己生成随机数。当需要新的随机性时,用户可以查询Wi-Fi芯片。
(待续)