Linux 内核报TCP SACK漏洞 CVE-2019-11477/78/79,需尽快处理

概述

在Linux内核处理TCP网络数据包时候存在缺陷导致三个漏洞,CVE编号分别为:CVE-2019-11477,CVE-2019-11478和CVE-2019-11479。最严重的漏洞CVE-2019-11477,可以让远程攻击者DDOS系统导致内核崩溃,从而影响系统的可用性。根据Redhat官方安全中心标准CVE-2019-11477为严重漏洞(Important),而CVE-2019-11478和CVE-2019-11479中等漏洞(Moderate)。

三个漏洞中前两个与数据包选择性确认(SACK)和最大段大小(MSS)相关,第三个漏洞与最大段大小(MSS)相关。

Redhat官方目前已经提供升级包和缓解参数设置措施,。

漏洞背景

Linux内核处理TCP网络数据包时候存在缺陷导致三个漏洞,CVE编号分别为:CVE-2019-11477,CVE-2019-11478和CVE-2019-11479。漏洞仅可以用于DOS拒绝攻击,不涉及信息泄露或者权限提升。

选择性确认SACK

TCP的选择性确认(Selective Acknowledgment,SACK)是一种机制,数据接收方可以通知发送方有关成功接受的数据包段的信息。这样来通知发送方重传发送包集中丢失的数据包段。禁用TCP SACK时,需要重传整个数据包完成数据传输。

最大数据包段大小MSS

最大数据包段大小(maximum segment size,MSS)是TCP报头中设置的参数,用来指定重建TCP数据包段需要的数据的大小。

由于数据包在变化的路由网络传输过程中可能会碎片化,因此主机必须将MSS指定为等于主机可以处理的最大IP数据报文的有效负载大小。MSS过大可能会导致数据包流在到达目的地的过程中碎片化,较小的数据包可以确保较少的碎片但最终会导致未使用的开销。

操作系统和传输类型默认设置了MSS大小。有特权访问权限的攻击者可以在数据包中创建特殊的MSS设置的原始数据包发送攻击。

TCP SACK

TCP是面向连接的协议。当双方希望通过TCP连接进行通信时,他们通过TCP握手交换某些信息建立连接,例如发起一个TCP请求,通过SYN发送初始序列ID,确认ID,连接使用的最大数据包段大小(MSS),认证信息和处理选择性确认(SACK)等。整体TCP连接通过我们熟知的三次握手最终建立。

TCP通过一个数据段单元发送和接收用户数据包。 TCP数据段由TCP头,选项和用户数据组成。每个TCP段都有序列号(SEQ)和确认号(ACK)。

接收方通过SEQ号和ACK号来跟踪成功接收了哪些段。ACK号下一个预期接受的段。

上图中用户A通过13个100字节的段发送1k字节的数据,每个段具有20字节的TCP头,总计是13个段。在接收端,用户B接收了段1,2,4,6,8-13,而段3,5和7丢失,B没有接收到。

通过使用ACK号,用户B告诉A,他需要段3,用户A收到B接收到2,而没有收到3,A将重新发送全部段,尽管B已经收到了4,6和8-13段。所以导致大量重复传输,性能低下。

选择性确认SACK

为了解决上面提到的问题问题,Linux在RFC-201议案中提出了选择性确认(Selective Acknowledgement,SACK)机制。通过SACK,B可以使用TCP选项字段通知A已成功接收了的所有段(1,2,4,6,8-13),A只需重传段3,5和7就可以。这样一来可以大大节省了网络带宽,提高了性能。

SACK奔溃: CVE-2019-11477

套接字缓冲区(SKB):

套接字缓冲区(Socket Buffer,SKB)是Linux TCP/IP实现中使用的核心的数据结构。它是缓冲区的链接列表,用来保存网络数据包。该列表可以用做传输队列,接收队列和SACK队列,重传队列等。SKB可以将分组数据保存成片段,Linux SKB最多可以容纳17个片段。该数在linux/include/linux/skbuff.h定义:

define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1) => 17

在x86平台上每段数据包中最多可容纳32KB的数据(PowerPC上为64KB)。数据包将发送时,它被放置在发送队列中,它的详细信息定义控制缓冲区结构中( linux/include/linux/skbuff.h):

其中,tcp_gso_segs和tcp_gso_size字段用通知设备驱动程序有关分段卸载的信息。

当Segmentation offload选项打开并且SACK机制也启用时,由于数据包丢失和某些数据包的选择性重传,SKB可能最终持有多个数据包,由tcp_gso_segs计数。列表中的多个这样的SKB被合并为一个以有效地处理的不同SACK块。它涉及将数据从一个SKB移动到列表中的另一个SKB。在此数据移动期间,SKB结构可以达到其最大限制为17个片段,并且tcp_gso_segs参数可以溢出并触发下面的BUG_ON()调用,从而导致所述内核奔溃。

远程用户可以通过将TCP连接的最大段大小(MSS)设置为48字节的最低限制并发送一系列特殊的SACK数据包来触发此问题,导致最低MSS每段仅留下8字节数据,从而增加了发送所有数据所需的TCP段数。

影响版本

影响Linux 内核2.6.29及以上版本

Centos

修复和缓解方案

及时更新补丁

可以等待发行方的补丁包,然后通过包管理器(yum,apt)等升级。

内核设置

通过设置Linux内核参数禁用SACK,方法:

echo 0 > /proc/sys/net/ipv4/tcp_sack

后者

sysctl -w net.ipv4.tcp_sack=0

可以防止CVE-2019-11477 和 CVE-2019-11478攻击。

可以防火墙设置限制MSS大小,对太小的包直接DROP:

firewall:

firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP

firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP

firewall-cmd -reload

firewall-cmd --permanent --direct --get-all-rules

iptables:

iptables -I INPUT -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP

iptables -nL -v

批量更新(Ansible)

最后提供一个Ansible cook文件用来批量更新禁止SACK:

将以上代码保存为disable_tcpsack.yml,然后ansible执行:

ansible-playbook -e HOSTS=all disable_tcpsack.yml

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();