近日,RedHat官方發布公告,研究人員在Linux內核處理TCP網絡時發現了三個重大漏洞。最嚴重的一個漏洞允許遠程攻擊者在受影響軟體的系統中觸發漏洞造成內核崩潰,從而影響系統的可用性。
三個漏洞的CVE編號為CVE-2019-11477(高危)、CVE-2019-11478和CVE-2019-11479。
前兩個漏洞與選擇性確認(SACK)數據包和最大段大小(MSS)有關,第三個僅與最大段大小(MSS)有關。
漏洞分析TCP選擇性確認(SACK)機制
數據接收方可以通知發送方已成功接受的所有段。這允許發送方重新傳輸從其已知集中丟失的段。當禁用TCP SACK時,需要更大的重傳集來重新傳輸完整的數據流。
最大段大小(MSS)
是在分組的TCP報頭中設置的參數,其指定重構的TCP段中包含的數據總量。
由於數據包在跨不同路由傳輸時可能會被碎片化,因此主機必須將MSS指定為等於主機可以處理的最大IP數據報有效負載大小。非常大的MSS大小會導致數據包在到達目的地的路上被碎片化,而較小的數據包可以確保較少的碎片但最終會導致未使用的開銷。
作業系統和傳輸類型可以默認為指定的MSS大小。具有特權訪問權限的攻擊者可以在數據包中創建具有精心設計的MSS選項的原始數據包,來進行攻擊。
TCP是面向連接的協議
當雙方希望通過TCP連接進行通信時,他們通過交換信息建立連接,例如請求發起(SYN)連接,初始序列號,確認號,通過此連接使用的最大段大小(MSS),權限發送和處理選擇性確認(SACK)等。此連接建立過程稱為3次握手。
TCP通過稱為Segment的單元發送和接收用戶數據。一個TCP段包括TCP報頭,選項和用戶數據的。
每個TCP段具有序列號(SEQ)和確認號(ACK)。
這些SEQ和ACK號用於跟蹤接收器成功接收哪些段。ACK號表示接收器的下一個預期段。
示例:上面的用戶'A'通過13個100位元組的段發送1千字節的數據,13是因為每個段具有20位元組的TCP頭。在接收端,用戶'B'接收段1,2,4,6,8-13,段3,5和7丟失,不會被用戶'B'接收。
通過使用ACK號碼,用戶'B'將指示它正在期望段號3,用戶'A'讀取為用戶'B'接收到2之後沒有段,並且用戶'A'將重新發送全部即使用戶'B'成功接收到第4,6和8-13段,從3開始的段也是如此。用戶'B'無法向用戶'A'表明。這會導致網絡的低效使用。
選擇性確認:SACK為了克服上述問題,選擇性確認(SACK)機制由RFC-2018設計和定義。通過選擇性確認(SACK),上面的用戶'B'使用其TCP選項欄位向用戶'A'通知它已成功接收的所有段(1,2,4,6,8-13),因此用戶'A'需要僅重傳段3,5和7,從而大大節省了網絡帶寬並避免了進一步的擁塞。
CVE-2019-11477 SACK Panic
套接字緩衝區(SKB)是Linux TCP / IP實現中使用的最核心的數據結構。它是緩衝區的連結列表,用於保存網絡數據包。這樣的列表可以充當傳輸隊列,接收隊列,SACK'd隊列,重傳隊列等.SKB可以將分組數據保存成片段。Linux SKB最多可以容納17個片段。
linux / include / linux / skbuff.h
定義MAX_SKB_FRAGS(65536 / PAGE_SIZE + 1)=> 17
每個片段在x86(PowerPC上為64KB)的數據中最多可容納32KB。當數據包將被發送時,它被放置在發送隊列中,它的詳細信息保存在控制緩衝區結構中
linux / include / linux / skbuff.h
struct tcp_skb_cb {
__ u32 seq; / *起始序列號* /
__u32 end_seq; / * SEQ + FIN + SYN +
datalen * / __u32 tcp_tw_isn;
struct {
u16 tcp_gso_segs;
u16 tcp_gso_size;
};
__u8 tcp_flags; / 2 * TCP標頭標誌。(tcp [13])* /
...
}
其中,' tcp_gso_segs '和' tcp_gso_size '欄位用於告知設備驅動程序有關分段卸載的信息。
當Segmentation offload打開並且SACK機制也被啟用時,由於數據包丟失和某些數據包的選擇性重傳,SKB可能最終持有多個數據包,由' tcp_gso_segs ' 計數。列表中的多個這樣的SKB被合併為一個以有效地處理不同的SACK塊。它涉及將數據從一個SKB移動到列表中的另一個SKB。在此數據移動期間,SKB結構可以達到其最大限制為17個片段,並且' tcp_gso_segs '參數可以溢出並觸發下面的BUG_ON()調用,從而導致所述內核崩潰問題。
static bool tcp_shifted_skb(struct sock * sk,...,unsigned int pcount,...)
{
...
tcp_skb_pcount_add(prev,pcount);
BUG_ON(tcp_skb_pcount(skb)<pcount); <= SACK panic
tcp_skb_pcount_add(skb,-pcount);
...
}
遠程用戶可以通過將TCP連接的最大段大小(MSS)設置為48位元組的最低限制並發送一系列特製的SACK數據包來觸發此問題。最低MSS每段僅留下8位元組數據,因此增加了發送所有數據所需的TCP段數。
漏洞危害高危
影響Linux 內核2.6.29及以上版本
安全建議1.請儘快更新補丁
https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-001/PATCH_net_1_4.patch
Linux內核版本>=4.14需要打第二個補丁
https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-001/PATCH_net_1a.patch
2.以下腳本檢查系統是否存在漏洞
https://access.redhat.com/sites/default/files/cve-2019-11477--2019-06-17-1629.sh
https://access.redhat.com/security/vulnerabilities/tcpsack
如需幫助請諮詢 hscert@hillstonenet.com