上海交通大学密码与计算机安全实验室(LoCCS)软件安全小组(GoSSIP)版权所有,转载请与作者取得联系!

著名的计算机学术安全会议CCS在2017年录用了一篇名为Key Reinstallation Attacks: Forcing Nonce Reuse in WPA2的学术论文,看起来,这和其他的上百篇同样将要在11月1日在美国达拉斯喜来登酒店会议中心一起登场报告的论文没有太大的差别,然而就在4天前,这篇论文的作者借助网站KRACK Attacks: Breaking WPA2点燃了整个网络世界,我们打开的浏览器突然被各种劲爆的新闻标题塞满了:“WPA2加密协议已被攻破”,“WiFi危机!”,“WiFi爆惊天漏洞”。随之而来的是大量的安全服务商、安全解决方案商借机狠狠地公关了一把,推出相关的安全防护产品的速度惊人。然而,我们阅读了攻击发现者的网站和他的论文,又把几乎所有的新闻报道浏览了一遍,感觉作者有意在引起所有人的注意力,而互联网世界又非常配合地把恐慌的气氛推向了高潮。作为一个学术研究团队,我们在安全危机的表象下,总是会质问这个攻击事件本身两个问题:KRACK攻击的本质到底是什么?KRACK攻击会对什么场景造成实质性的安全危险?如果不能精确地向公众去解释这两个问题,安全研究人员和安全企业就应该反省自己的失职。很遗憾,我们完全不能认同论文作者 Mathy Vanhoef 在相关网站上写下的相关言论的倾向:面向学术界的论文,可以最严谨的强迫症去研究和处理哪怕是最轻微的安全问题,因为学术研究人员会以客观冷静的态度来审视这些问题;而面向公众的宣传则需要告诉大家危害的边界和不受影响的情况,只为了一个大新闻而宣传,那还是too young too simple呐!

那么,让我们来试图回答一下这篇论文所导引到的两个问题:KRACK攻击的本质到底是什么?KRACK攻击会对什么场景造成实质性的安全危险?其实不论是论文还是诸多出现的分析文章,都用了冗长的篇幅去解释这个漏洞,但是这个漏洞可以用简单的一句话来总结:WPA协议存在一个消息重放漏洞,导致相同的密钥(Crypto Key)被反复使用在不同的会话(Session)上。这个攻击也就是作者所说的Key Reinstallation Attacks,重点就在于相同的密钥被反复用在不同的会话上。更简单一点,就是存在多组密文数据,被相同的加密密钥(包括Nonce)进行了加密。这种加密模式背后所关联的潜在安全性破坏,就是KRACK攻击的本质危害。

那么你可能要问,多组密文数据被相同的加密密钥加密,存在什么危害呢?首先我们要指出,即使在KRACK攻击的场景下,攻击者知道有多组密文数据被同一密钥加密,但是他并不知道这个密钥是什么(特殊情况即全零密钥后续会讨论)。这里之所以产生了问题,很大程度上是因为WPA加密协议在这里采用的是stream cipher加密(即用一个伪随机密钥流逐字节去异或明文),具体而言,攻击的本质是通过拦截和重放一些握手关键数据包,使得双方已经在使用的密钥被重新安装,同时伴随着相关参数的重置,就会导致用于加密明文的密钥流被重复使用。为说明方便,下面使用一个略不严谨的表达来进行阐述。

`ciphertext = plaintext xor AES(key, IV||counter)`

原本在key和iv不变的情况下,只要counter从0开始每次增加1,那么所产生的密钥流就不会重复,安全性没有任何问题。但由于重新安装密钥后,key和iv没有发生变化,counter却被重置为0,这样产生的密钥流就会与重置前的密钥流完全相同。而stream cipher加密恰好是不应该重用密钥流的,如果有两组用相同密钥加密的密文,就可以通过互相之间异或消掉密钥流,而如果其中一组密文对应的明文是已经为攻击者所知的,另一组密文对应的明文就可以通过这个运算得到。

尽管如此,这种我们称之为key reuse attack的KRACK攻击的普遍形式,由于key reuse窗口的大小受限,以及推测明文的不确定性,其造成的影响较为有限:仅仅是密钥流的重用导致的部分消息可被解密,重放及有条件的伪造。对于一些设备来说,其攻击窗口很小,重复使用的密钥流比较短,因此可以解密的数据长度受限。比如,对于一些接受重传消息为密文的设备,可行的攻击如下图所示,图中红框中是重新安装key前后使用了相同密钥流的两条消息,由于在重新安装key之前只可能发出图中所示的一条消息,因此可恢复的数据长度最多与此消息长度相同。

此外,即使重复使用的密钥流较长,受解密原理的影响,能解密出的消息内容仍旧有很大不确定性。如上所述,解密消息依靠的是使用了重复的密钥流,也就是说攻击者看到的两段密文c1,c2都是由同一密钥流加密,那么就会有c1 xor c2 = p1 xor p2,在已知c1和c2的情况下,确定p1和p2各自准确的内容,还需要一些工作。上图中的情况属于较为简单的一类,p1(也就是Msg4(r+2))是可以确定其大部分内容的,这样就可以比较容易地得出p2(也就是客户端发送的Data)中相应长度的内容。而对于其他p1和p2都无已知信息的情况下,恢复p1和p2是比较困难的。而且,由于在这种攻击场景下,攻击者只能对client或者AP某一端(根据论文中提到的两种不同的攻击模型)发出的加密数据包产生威胁,而对没有产生key reuse的另一端是无法构成任何威胁的,这就限制了攻击者只能在通讯的最初阶段动一些手脚,而无法对稍微复杂的协议的后续数据进行攻击,例如一个HTTP通讯,还没有进入到TCP握手阶段,key reuse attack已经无法生效了,更不要提威胁后续的实质内容。

KRACK攻击中真正造成较为严重后果的,是一种可被称为 zero key attack 的特殊攻击形式(也是作者在其给出的DEMO中利用的攻击),这种攻击利用了Linux上wpa_supplicant版本为2.4、2.5、2.6的wifi客户端(包括Android 6.0及以上版本和Android Wear 2.0等安卓设备)上的一个代码实现的问题。由于编程安全实践要求程序在初始化密钥后,会将之前包含密钥材料的缓冲区内存清零,可是当发生重放攻击后,程序并没有“记住”自己已经将密钥材料缓冲区清零了,又回头去读取了那一块内存区域,这时候密钥一定是由全零的数据衍生而来,也就是说,攻击者可以完全预测之后wifi加密数据包所使用的密钥,那么设备发给wifi的所有数据包都可以被解密,进而导致一个AP替换的攻击。由于这是一种代码实现和协议问题结合导致的安全漏洞,因此在Windows、iOS等诸多平台上随着实现不同,这类攻击并没有办法生效。

特别值得指出的是,即使存在这样一种特殊情况,KRACK攻击也无法威胁端到端加密(TLS协议等用于安全通讯的加密),而demo中所演示的原本的https通信被替换为http通信,则是因为挑选的演示网站http://match.com本身配置存在问题,没有做好抵抗sslstrip攻击的防护,而实际上正确配置的TLS站点,即使zero key attack也是无法完成攻击的(再次感叹下作者的用心良苦!!!)

总结一下,KRACK攻击是针对WPA协议中非常短暂的连接协商部分的攻击,在普遍情况下,对后续的通讯的影响有限,而且这种攻击完全无法推导出wifi密码,也不能获取到会话密钥,更不能利用此攻击伪造已经建立了信任的两方(AP和客户端)中的任意一方。KRCAK攻击所声称的可以窃取敏感信息,诸如信用卡号、密码、聊天消息、邮箱、照片等,其需要的满足条件包括:

* 客户端版本是Linux wpa_supplicant v2.4, v2.5, v2.6,也就是Android版本是6.0及以上,以及Android Wear 2.0的设备。(只有以上设备在重新安装后key会被置为全零)

* 包含敏感信息(如信用卡号、密码、聊天消息、邮箱、照片等)的网络请求,没有被安全保护,如直接使用http发送(这种情况无需krack攻击,只要在网络链路的其他节点,就可以直接看到明文)、使用可被strip为http的https发送(同样攻击者可以无需在客户端与Wifi间的链路上进行,而可以在网络链路的其他节点进行strip攻击)

最后,作为安全学术研究人员,我们希望安全学术研究、安全学术会议在保持对现实系统一丝不苟、不放过一点点可能威胁的同时,也能够对公众更多地发出Don't Panic的声明。没有绝对安全的系统,我们的目标是让系统更安全的同时,也让大家能更有安全感^_^

Don't Panic! KRACK 没你想象的那么糟的更多相关文章

  1. 全站 HTTPS 没你想象的那么简单

    对自己无知这件事本身的无知真的挺可怕 认知偏差现象一直存在于我们每个人身上,谁也避免不掉,不过是有的人了解这件事儿,有的人不怎么知道而已,这就产生了「无知而不自知」的认知偏差.当然,这时候你自己忽悠自 ...

  2. MVVM没你想象的那么的好

    我写过很多有关于让View Controller 更易于理解的文章,其中一种比较常见的模式就是Model-View-ViewModel(MVVM). 我认为MVVM 是一种非常容易让人混淆的 anti ...

  3. Fragment中监听onKey事件,没你想象的那么难。

    项目中越来越多的用到Fragment,在用Fragment取代TabHost的时候遇到了一个问题,我们都知道,TabHost的Tab为Activity实例,有OnKey事件,但是Fragment中没有 ...

  4. "简单"的优化--希尔排序也没你想象中那么难

    写在前边 大家好,我是melo,一名大二上软件工程在读生,经历了一年的摸滚,现在已经在工作室里边准备开发后台项目啦. 不过这篇文章呢,还是想跟大家聊一聊数据结构与算法,学校也是大二上才开设了数据结构这 ...

  5. DOMO1

    以下是Demo首页的预览图 demo下载:http://www.eoeandroid.com/forum.php?mod=attachment&aid=NjE0Njh8ZTIyZDA2M2N8 ...

  6. Objective-C中的Block(闭包)

    学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也 ...

  7. 自己实现苹果安装app动画

    最近在学习CALayer相关动画,然后某一天突然发现苹果安装app这动画就很不错啊,所以就想自己实现下. 具体效果如图: 还是不试不知道一试吓一跳啊,这看上去简单的动画没我想象的那么简单. 首先这个动 ...

  8. Javascript:一个屌丝的逆袭

    HTML负责结构, CSS负责展示, 而我(加上AJAX, JSON) 负责逻辑.于是前端编程三剑客形成了. http://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExN ...

  9. 4种必须知道的Android屏幕自适应解决方案

    文章来源:http://blog.csdn.net/shimiso/article/details/19166167 demo下载:http://www.eoeandroid.com/forum.ph ...

随机推荐

  1. linux的vi和vim编辑器操作

    vi:linux内部的文本编辑器:vim:vi的增强版,具有程序编辑的能力. vi和vim的三种常见模式: (1)正常模式(一般模式):vim一打开就是这种模式,此模式下可以使用各种快捷键,比如复制粘 ...

  2. JavaScript简单继承

    很多C#或C++开发人员习惯使用继承来开发项目,所以当他们想学习JavaScript语言时,第一个问题一般是:“我怎么在JavaScript中使用继承?”. 实际上JavaScript使用了一种不同于 ...

  3. selenium - js日历控件处理

    # 13. js处理日历控件 ''' 在web自动化的工程中,日历控制大约分为两种: 1. 可以直接输入日期 2. 通过日历控件选择日期 基本思路: 利用js去掉readonly属性,然后直接输入时间 ...

  4. RIP 路由协议

    RIP动态路由选择协议 routing information protocol     IGP   小范围   路由器限制为15台  超过可能无法收敛   收敛概念  在一个域内  各个路由器知道各 ...

  5. 02 Java 的基本类型

    Java 的基本类型 Java 包括了八种基本类型,明细如下: Java 的基本类型都有对应的值域和默认值.byte,short,int,long,float以及double的值域依次扩大,前面的值域 ...

  6. 理解Tomcat架构、启动流程及其性能优化

    PS:but, it's bullshit ! 备注:实话说,从文档上扒拉的,文档地址:在每一个Tomcat安装目录下,会有一个webapps文件夹,里面有一个docs文件夹,点击index.html ...

  7. 【bzoj2333】[SCOI2011]棘手的操作 可并堆+STL-set

    UPD:复杂度是fake的...大家还是去写启发式合并吧. 题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条 ...

  8. POJ——3264Balanced Lineup(RMQ模版水题)

    Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 44112   Accepted: 20713 ...

  9. 周赛Problem 1021: 分蛋糕(埃拉托斯特尼筛法)

    Problem 1021: 分蛋糕 Time Limits:  1000 MS   Memory Limits:  65536 KB 64-bit interger IO format:  %lld  ...

  10. 【前端学习笔记】2015-09-02~~~~ 关于filter()匹配的使用

    关于filter的使用先记录以下几点: 1.filter(':even')遍历所有元素,找到index为偶数的元素.. ps: filter(':odd')       odd----奇数   eve ...