一般我们会认为,要确认互联网上的任意两台主机设备是否建立TCP连接通讯,其实并不容易——攻击者如果不在双方的通讯路径中,就更是如此了。另外如果攻击者并不在通讯路径中,要中途中断双方的这种连接,甚至是篡改连接,理论上也是不大可能的。
不过来自加州大学河滨分校,以及美国陆军研究实验室的研究人员,最近联合发表了一篇论文,题为《Off-Path TCP Exploits: Global Rate Limite Considered Dangerous》。这篇文章提到Linux服务器的TCP连接实施方案存在高危安全漏洞,攻击者可利用该漏洞来劫持未加密Web流量,或者破坏如Tor连接一类的加密通讯;此漏洞编号CVE-2016-5696。
撰写这篇报告,以及开发针对服务器和客户端补丁的作者包括了Zhiyun Qian,Yue Cao,Zhongjie Wang,Tuan Dao,Srikanth V. Krishnamurthy以及Lisa M。值得一提的是,这其中的Yue Cao,也就是曹跃,正是GeekPwn2016澳门站的选手。当时他就因为“重现了当年世界头号黑客凯文米特尼克的TCP劫持”,摘得“最大脑洞奖”。
这里的“高危”属性,主要体现在几点,其一是“off-path”,也就是攻击者不需要处在通讯路径中——这话听起来有些费解,举个例子:传统意义上的中间人攻击就属于处在通讯路径中的典型。所以对该漏洞的利用,是不需要攻击者接入通讯双方的网络中的。
其二,如果利用该漏洞在服务器和客户端的TCP连接中进行流量劫持攻击,服务器和客户端是不需要植入任何恶意程序的。也就是说,受害者和攻击者之间根本就不需要进行互动,攻击者就可以进行这种攻击行为。从这两点来看,这个漏洞的确是相当的危险。
这个漏洞的危害极大
CVE-2016-5696漏洞说起来还是相当有趣,它主要影响的是Linux系统。具体说来,Linux内核版本在v3.6至v4.7之间的系统都受到影响,也就是过去4年间的各类Linux系统受到影响。实际上,针对该漏洞的Linux内核补丁已经开发完成,而且如上所述,研究人员也专门为客户端和服务器主机设备开发了相应的补丁,增加该漏洞的利用难度。
不是说是相关TCP连接的一个漏洞吗?怎么又跟Linux系统相关?这事儿是这样的:在TCP连接的设计中,安全原本就不是主要考量因素。所以无论是在specification层面,还是implementation层面,都有不少安全加强措施。有个标准叫RFC 5961——它具体给出了两台主机设备间建立TCP通讯的一些规定,就是为了加强安全性的。
不过悲剧的是,研究人员发现了RFC 5961的实施存在一些弱点。上述内核版本的Linux系统则严格遵守了RFC 5961规格,自然也就存在这方面的漏洞了。
常规TCP握手
那么利用CVE-2016-5696漏洞,究竟可以干嘛呢?文首提到的对连接进行劫持攻击,的确是对该漏洞利用的最坏情况。更为直接地说,利用该漏洞可以确认互联网上的任意两台主机是否通过TCP连接进行通讯(并发现端口号),以及推测出TCP报文头的序列号(sequence number),这样一来就能强制终止双方的连接,甚至在连接中插入恶意payload了。
通过该漏洞针对SSH、Tor之类的加密服务进行重置,以及DoS攻击也是可行的,而破坏这种加密连接可能会让用户转而选择相对没那么安全的通讯工具。
由于对攻击者而言,根本就不需要处在“中间人”的位置(也就是所谓的off-path),而且整个过程不需要与受害者进行互动,所以研究人员认为,该漏洞可能对互联网安全隐私产生极大影响。
究竟是怎么做到的?
一般来说,我们要破解某些加密数据,如果加密方式非常复杂令我们束手无策,则不妨转换一下思路,改用边信道攻击。针对CVE-2016-5696漏洞的利用,实际上也是采用边信道攻击方案——走的是偏门。由于整个过程还是比较复杂的,鉴于篇幅关系,我们只能简单谈一谈:
整个攻击模型如上图所示,图1的情况是进行IP地址欺骗(ISP可让“off-path”的攻击者伪装受害人的IP地址像服务器发包),图2的情况也就不用多说了。其实要满足这种攻击,攻击者发出欺骗TCP包,达到DoS或者数据注入的攻击目标,首先需要知道服务器和客户端双方TCP通讯的源IP地址、目标IP地址、源端口、目标端口,最重要的一点是需要猜测TCP序列号,只有序列号in-window,才能对连接进行重置或者注入恶意数据。
这里猜测的序列号需要满足RCV.NXT ≤ SEG.SEQ ≤ RCV.NXT + RCV.WND的条件,其中SEG.SEQ就是猜测的序列号;RCV.NXT和RCV.WND分别是指接收方预期的下一字节的序列号,以及接收windows size。攻击者可以利用大量欺骗包进行序列号猜测。为了应对这种攻击,RFC 5961登场了——没错就是前文提到的标准!RFC 5961针对TCP处理接收到的包的方法,做了一些修改。
Sequence Number在TCP报文头位置
比如说以前,某主机收到SYN握手包,判断序列号在有效windows之外,则向发送方回传ACK;如果序列号in-window,那么接收方对双方的连接进行重置。这么做的缺陷比较明显,攻击者只需要一个in-windows序列号的SYN包就能重置目标双方的TCP连接。
所以在RFC 5961中,接收方收到SYN包后,无论序列号如何,都会回传一则challenge ACK报文,以便确认先前的连接是否真的已丢失。如果说这个SYN包的确是合法对象初始化发出的,也就意味着双方的连接要进行重置。对方在收到challenge ACK之后,会发出一个RST包,其中就带有“正确的”序列号,证明先前的连接的确是丢失了。这样一来,如果SYN包是攻击者伪造的,即便有in-window序列号,那么也就不能达到终止连接的目的。
上面只是举了一个例子,RFC 5961的标准规定还有很多,比如ACK Throttling:为了减少CPU和带宽资源浪费,所以要限制challenge ACK发出的数量,RFC 5961就引入了这里的ACK Throttling机制。系统管理员也可以对challenge ACK发出的最大周期值(每秒发出多少个)进行配置。近4年来的Linux内核都遵从这一守则,系统中有个全局变量sysctl_tcp_challenge_ack_limit,就是存储challenge ACK计数器。
正是这个ACK Throttling机制,造成了边信道攻击的可行性。这里每秒发出Challenge ACK的限制是在整个连接中进行共享的(也包含建立连接的攻击者)。攻击第一步过程是这样的:攻击者首先发出一些欺骗包,制造全局challenge ACK速率限制冲突,比如说向服务器发起常规连接,触发chanllenge ACK最大值的限制,然后再计算一下连接中实际收到的challenge ACK数量。如果这个数量少于系统限制,表明有部分challenge ACK是用于回应欺骗SYN包的。
这样一来也就可以判断,双方的TCP连接是否存在了。另外根据更多信息还可以判断服务器预期的下一个序列号(TCV.NXT),下一个ACK号。具体是怎么判断的,各位可以移步点击这里查看研究者发布的PDF文档,里面进行了非常详细的阐述——甚至还提到了实际操作中可能存在的一些挑战,整个过程还是相当有趣的。
TCP劫持实操
研究人员在报告中还为此做了个实验,他们用实验室一台装了Ubuntu 14.04的计算机和USAToday站点建立连接。这个站点会建立起长期TCP连接,每30秒周期性进行新闻更新。然后再用一台同样安装Ubuntu 14.04的主机发起攻击,在完成序列号猜测过后,攻击设备通过向服务器发送欺骗包来进行所谓的去同步化攻击(de-synchronization)。
向服务器发出欺骗包之后,服务器会向受害客户端发出响应。由于欺骗包并不是客户端发出的,所以客户端不会接受该回应(带无效的ACK号)。随后,服务器也不会再接受客户端的初始化请求,因为序列号此时不对了(因为有中间攻击设备嘛)。这样一来,双方的同步就正式解除了,就不需要再担心受害者的客户端会首先收到服务器的响应了。
这次实验成功劫持了双方的连接,而且研究人员还在网页上方插入了钓鱼注册窗口,如上图所示!注意哦,这种劫持是基于攻击者根本就不在两边通讯路径的基础上,是不是感觉还挺恐怖的?下面这张图是研究人员在重复进行实验10次的成功率,结果还是挺让人满意的。
据说,整个攻击过程,到准确猜出双方交换的TCP包序列号,仅需大约10秒。Linux用户请特别留意你正在使用的内核版本号,以及最新版的更新信息。Windows和Mac用户,还有FreeBSD用户似乎完全不需要担心,它们并没有采用ACK throttling机制。
从应对策略来说,似乎消除这种边信道探测的可行性即可,就是取消对challenge ACK的限制(具体说是调整sysctl_tcp_challenge_ack_limit的值),但这么做可能对资源存在过度消耗;或者在策略上每个连接采用单独的计数器,这样就不会受到其他连接的干扰了;或者也可以对这里的“边信道”添加噪声(这是应对边信道攻击的常规策略),具体说来是加入随机值。后两种方案其实都是说给Linux社区听的,对Linux用户而言,还是准备做升级工作吧。
发表评论