* 本文原創(chuàng)作者:Leon不會(huì)玩QEMU,本文屬FreeBuf原創(chuàng)獎(jiǎng)勵(lì)計(jì)劃,未經(jīng)許可禁止轉(zhuǎn)載
在這篇文章中,我們要討論一個(gè)最新的TCP側(cè)信道的漏洞(CVE-2016-5696)。這個(gè)標(biāo)準(zhǔn)是在Linux 3.6版本之前提出的,并且影響眾多的設(shè)備和主機(jī)。簡(jiǎn)單地說,只要是兩臺(tái)主機(jī)之間通過TCP協(xié)議去通信,那么就很容易遭受到一個(gè)盲目的Off-Path攻擊。此外,如果這個(gè)連接存在,攻擊者通過這種Off-Path攻擊也可以從連接的兩側(cè)推斷出這個(gè)序列號(hào)是不是正在使用,這樣一來反過來,攻擊者可以導(dǎo)致連接終止和進(jìn)行數(shù)據(jù)注入攻擊。
001 簡(jiǎn)介
其實(shí)在TCP協(xié)議設(shè)計(jì)的時(shí)候并沒有考慮安全性。然而最近似乎大家都開始關(guān)心起TCP的安全性來的,比較搞笑的是,大家都在為TCP裝各種各樣的補(bǔ)丁的時(shí)候,新的安全問題也隨之出現(xiàn)。
那什么是側(cè)信道攻擊呢?
信息論創(chuàng)始人香農(nóng)(Shannon)對(duì)信息的定義是:“減少隨機(jī)不定性的東西。”加密的本質(zhì)也是打破原有的確定性,使得明文數(shù)據(jù)變?yōu)椴豢山庾x密文亂碼。但是,側(cè)信道的出現(xiàn),就是越過加密算法增加的隨機(jī)不定性,從其他的渠道獲取數(shù)據(jù)標(biāo)簽,確定信息內(nèi)容的。側(cè)信道最早的實(shí)踐是通過采集加密電子設(shè)備在運(yùn)行過程中的時(shí)間消耗、功率消耗或者電磁輻射消耗等邊緣信息的差異性進(jìn)行攻擊的手段。而隨著研究的深入,也逐漸從加密設(shè)備延伸到計(jì)算機(jī)內(nèi)部CPU、內(nèi)存等之間的信息傳遞等方面,并在Web應(yīng)用交互信息傳遞越來越頻繁時(shí),延伸到了網(wǎng)絡(luò)加密數(shù)據(jù)流的破解方面。側(cè)信道攻擊對(duì)數(shù)據(jù)加密甚至加密Web流量的威脅早就被納入了信息安全研究的范疇之中了,但是直到2010年,美國印第安納大學(xué)王曉峰教授等人的研究發(fā)現(xiàn)側(cè)信道攻擊對(duì)Web應(yīng)用的威脅是與生俱來的問題。
首先思考一下Web應(yīng)用的特點(diǎn),一個(gè)Web服務(wù)通常在一個(gè)客戶端(Client)和一個(gè)服務(wù)器端(Server)之間進(jìn)行,他們之前的請(qǐng)求與應(yīng)答信息一般是通過互聯(lián)網(wǎng)進(jìn)行的,這就會(huì)把他們之間的交互數(shù)據(jù)暴漏給了攻擊者。而通過這些數(shù)據(jù),攻擊者就能夠推斷出他們的狀態(tài)轉(zhuǎn)變以及觸發(fā)這些轉(zhuǎn)換的用戶數(shù)據(jù)。更糟糕的是, Web2.0的發(fā)展使得Web應(yīng)用的交互性能越來越好,尤其像Ajax這類編程技術(shù)的出現(xiàn),能夠讓用戶甚至在文本框中輸入一個(gè)字母或者從一個(gè)選項(xiàng)列表中選擇一個(gè)選項(xiàng)之后,就從服務(wù)器查詢做出一個(gè)應(yīng)答,而這些應(yīng)答信息的熵一般很低,因此很容易通過枚舉與對(duì)比猜測(cè)出用戶的輸入請(qǐng)求。
回歸到正題,針對(duì)TCP側(cè)信道攻擊,可以進(jìn)行如下的威脅建模分析:
如圖1所示,偏離路徑攻擊是TCP攻擊基于現(xiàn)實(shí)的一個(gè)威脅模型。有三臺(tái)主機(jī)涉及:受害者的客戶端,受害者服務(wù)器和攻擊者。任何機(jī)器可能會(huì)在這個(gè)模型中,只要其ISP允許攻擊者將數(shù)據(jù)包發(fā)送到服務(wù)器并且成功偽造成攻擊者的IP即可成功。可替代地的攻擊模型如圖2所示,攻擊者能夠?qū)?shù)據(jù)包發(fā)送到客戶端并且受害者服務(wù)器的欺騙IP地址。
圖1-威脅模型1
圖2-可替代攻擊模型
In-window盲攻擊:
在上述的模型下,最普通的攻擊情況也就是In-window盲攻擊,也就是off-path的攻擊者企圖將猜出來的并且可以引發(fā)數(shù)據(jù)注入和拒絕服務(wù)的序列號(hào)綁定進(jìn)偽造TCP數(shù)據(jù)包來實(shí)現(xiàn)攻擊。要想攻擊得手,這個(gè)攻擊者必須的知道準(zhǔn)確這個(gè)服務(wù)器和客戶端之間建立連接的四元組(也就是原目的端口、IP地址)。一旦偽造的序列號(hào)落到了窗口上,攻擊者就可以去注入惡意鏈接或者直接重置連接。
讓我們來更精確的描述一下:一個(gè)能夠滿足攻擊條件的序列號(hào)必須要具備以下條件才能成功。
RCV.NXT≤SEG.SEQ≤RCV.NXT + RCV.WND
如果SEG.SEQ是被猜到的序列號(hào),那么RCV.NXT就是接收方下一個(gè)想要接收的字節(jié),RCV.WND就是下一個(gè)想要接收的窗口大小。
為了要能承載這個(gè)攻擊,攻擊者需要偽造一個(gè)序列號(hào)遠(yuǎn)大于正常值的數(shù)據(jù)包來讓整個(gè)序列號(hào)空間爆炸。在這個(gè)序列中,數(shù)據(jù)包的序列號(hào)是一定大于他前面的一個(gè)窗口的大小。
圖3-ACK窗口插圖
為了防止這種攻擊,RFC5961提出了幾點(diǎn)關(guān)于建議在TCP如何處理傳入的數(shù)據(jù)包的修訂。
(1)減少盲目利用SYN位進(jìn)行重置鏈接的攻擊:
攻擊者利用強(qiáng)制發(fā)送TCP-SYN包對(duì)TCP鏈接進(jìn)行強(qiáng)制重置,當(dāng)SYN包發(fā)送的時(shí)候,TCP鏈接則會(huì)被重置。
在前者(預(yù)RFC5961)的Linux內(nèi)核版本,傳入的SYN數(shù)據(jù)包的處理過程如下:
l如果該序列號(hào)是超出了有效的接收窗口,接收器將發(fā)送一個(gè)ACK回發(fā)送方。
l如果該序列號(hào)是在窗口中,接收器將復(fù)位此連接。
顯而易見的是,攻擊者只需要一個(gè)單一的SYN數(shù)據(jù)包與在窗口序列號(hào)重置持續(xù)TCP連接。
所以,RFC5961建議在處理SYN數(shù)據(jù)包如下修改:
l如果一個(gè)接收機(jī)看到一個(gè)輸入SYN分組,忽略該序列號(hào),發(fā)回一個(gè)ACK(稱為挑戰(zhàn)ACK)給發(fā)送者,以確認(rèn)先前的連接的丟失。
l如果數(shù)據(jù)包確實(shí)是從合法的遠(yuǎn)程端發(fā)起,它必須有真正的失去了以前的連接,然后現(xiàn)在正在嘗試啟動(dòng)一個(gè)新的。收到Challenge ACK,對(duì)端會(huì)發(fā)送一個(gè)RST包具有正確的序列號(hào)(從挑戰(zhàn)ACK包的ACK域而來),以證明以前的連接確實(shí)終止。
這樣的話,如果SYN序列號(hào)是假的,就不會(huì)強(qiáng)制重置TCP會(huì)話。
(2)減少盲目利用ACK位進(jìn)行重置鏈接的攻擊:
攻擊者可能還偽造一個(gè)RST包(其中RST標(biāo)記被設(shè)定TCP包),然后注入到一個(gè)持續(xù)的TCP連接。
在預(yù)發(fā)布的RFC5961中,就像上文的SYN的情況一樣,一個(gè)RST包只要能成功地為它的序列號(hào)是在窗口終止連接。
所以RFC5961建議以下變化:
l如果序列號(hào)超出有效的接收窗口,接收器簡(jiǎn)單地丟棄該數(shù)據(jù)包。不會(huì)對(duì)該窗口進(jìn)行修改。
l如果序列號(hào)的下一個(gè)預(yù)期序號(hào)(RCV.NXT)精確匹配,那么就會(huì)連接復(fù)位。
l如果該序列號(hào)是在窗口,但不完全匹配RCV.NXT,接收機(jī)必須發(fā)送一個(gè)Challenge ACK分組的發(fā)送者,并丟棄不可接受RST分組。
在最后的情況下,如果發(fā)送者是合法的,它發(fā)回具有正確序列號(hào)的RST分組(從Challenge ACK號(hào)碼ack衍生),以重置連接。另一方面,如果RST被偽造,挑戰(zhàn)ACK分組將不會(huì)關(guān)斷攻擊者可觀察到的路徑。因此,攻擊者必須得非常幸運(yùn)- 只因?yàn)橹挥?/2^32的序列號(hào)將被接受。(直接說概率小的可憐不行么?!)
(3)減少數(shù)據(jù)盲注攻擊:
攻擊者可能會(huì)通過數(shù)據(jù)盲注來實(shí)現(xiàn)破壞傳輸內(nèi)容,當(dāng)分組到達(dá)時(shí),接收器首先檢查序列號(hào)來確保它處在in-window狀態(tài)下。另外,該ACK號(hào)碼將被檢查。預(yù)發(fā)布的RFC5961中,ACK號(hào)碼被認(rèn)為是有效的,只要它落在[SND.UNA-(2^31-1),SND.NXT]這么大一個(gè)區(qū)間內(nèi); 實(shí)際上這是ACK號(hào)空間的一半。這里,SND.UNA是第一未確認(rèn)字節(jié)的序列號(hào)。 SND.NXT是將要被發(fā)送的下一個(gè)字節(jié)的序列號(hào)。
RFC 5961建議做法是[SND.UNA-MAX.SND.WND,SND.NXT]。
其中MAX.SND.WND是接收機(jī)曾經(jīng)從它的對(duì)等見到的最大窗口尺寸的一個(gè)更小的有效ACK編號(hào)范圍。這在圖3插圖的是唯一有效的ACK號(hào)碼是那些不是太舊(字節(jié)被最近發(fā)送)和不是太新(接收器可以在不ACK字節(jié)還能夠被寄出)的原因。其余的ACK值將是在[SND.UNA的范圍 -(2^31 - 1),SND.UNA -MAX.SND.WND]區(qū)間內(nèi),表示為Challenge ACK窗口。即使這個(gè)窗口內(nèi)的ACK號(hào)碼仍然被認(rèn)為是無效的, 該規(guī)范要求接收機(jī)響應(yīng)于與這樣的ACK編號(hào)的數(shù)據(jù)包,以產(chǎn)生傳出挑戰(zhàn)的ACK??傮w來說,這更嚴(yán)格的ACK號(hào)檢查不消除,而且有利于極大地減少了無效數(shù)據(jù)成功注入的可能性。具體地說,如果MAX.SND.WND很?。ㄍǔ榇蠖鄶?shù)連接的情況下),則可以接受的ACK窗口會(huì)比ACK號(hào)空間的一半(如在圖3中示出)要小得多。
(4)ACK節(jié)流(Throttling)
在一般情況下,如前面所解釋的,RFC5961強(qiáng)制對(duì)傳入的TCP分組的更嚴(yán)格的檢查;例如,它要求RST包具有一個(gè)確切的序列號(hào)來實(shí)際重置連接,而“足夠好”的窗口值僅觸發(fā)一個(gè)挑戰(zhàn)的ACK。為了減少浪費(fèi)CPU和帶寬資源Challenge ACK數(shù)據(jù)包的數(shù)量,一個(gè)ACK節(jié)流機(jī)構(gòu)還被提出。
具體地,系統(tǒng)管理員可以配置可在給定的時(shí)間間隔(例如,1秒)被發(fā)送出去Challenge ACK的最大數(shù)量。
該RFC明確指出“實(shí)現(xiàn)應(yīng)該包括一個(gè)ACK節(jié)流機(jī)制是保守的。”因此,Linux內(nèi)核通過存儲(chǔ)在所有TCP連接共享的全局變量的挑戰(zhàn)ACK柜臺(tái)忠實(shí)地執(zhí)行此功能。這種方法,不幸的是,創(chuàng)建一個(gè)壓根就不需要的副信道,如將要詳細(xì)闡述。我們強(qiáng)調(diào),RFC規(guī)定ACK限制僅適用于挑戰(zhàn)ACK和不正規(guī)的ACK。這意味著它們面臨的挑戰(zhàn)的ACK計(jì)數(shù)器不大可能由合法的ACK交通的影響作為觸發(fā)挑戰(zhàn)的ACK的條件都被認(rèn)為是罕見的或由于攻擊。
002 漏洞預(yù)覽
在2012年9月發(fā)布的3.6版本,Linux內(nèi)核的首次實(shí)現(xiàn)了所有在RFC5961建議功能,這些變化全部回遷到了這個(gè)版本以及先前的版本上。一個(gè)全局系統(tǒng)變量sysctl_tcp_challenge_ack_limit被引入到控制每秒生成Challenge ACK的最大數(shù)量。它默認(rèn)設(shè)置為100。由于此限制所有連接(可能包括與攻擊者建立的連接)共享,共享狀態(tài)可以被利用作為一個(gè)側(cè)通道。
假設(shè)我們按照?qǐng)D 1 中的威脅模型,其基本思想是重復(fù)以下步驟︰
1) 發(fā)送偽造包用來測(cè)試鏈接(用一個(gè)具體的四個(gè)元組),
2) 創(chuàng)建一個(gè)超過sysctl_tcp_challenge_ack_limit限制的TCP鏈接,即通過常規(guī)的連接從攻擊者創(chuàng)建到服務(wù)器并故意觸發(fā)允許每秒最大的ChallengeACK的數(shù)量。
3) 算Challenge ACK在該連接收到的確認(rèn)實(shí)際的數(shù)。如果這個(gè)數(shù)字小于系統(tǒng)限制,通過連接下測(cè)試,作為對(duì)偽造的數(shù)據(jù)包作出反應(yīng)必須有發(fā)送Challenge ACK。
根據(jù)步驟1發(fā)送偽造類型的數(shù)據(jù)包,Off-Path的攻擊者可以推斷出以下幾點(diǎn):
1)如果存在由其四個(gè)元組指定連接
2)下一個(gè)預(yù)期的服務(wù)器 (或客戶端)上的序列編號(hào) (RCV.NXT)
3) 下一個(gè)預(yù)期的服務(wù)器 (或客戶端) 上的ACK 編號(hào) (SND.UNA)。
這就有意思了,這樣的話前面的前三個(gè)攻擊都可以觸發(fā)了。然后我們精心構(gòu)造一個(gè)看看。
計(jì)算用來連接的四元組: 圖4顯示了一個(gè)關(guān)斷路徑攻擊者可以發(fā)送(i)存在下,或(ii)不存在正在進(jìn)行的連接的情況下,區(qū)分?jǐn)?shù)據(jù)包的序列。在這兩種情況下,攻擊者發(fā)送的分組的順序相同。虛線代表與欺騙性IP地址的數(shù)據(jù)包。 在
該圖中,初始SYN-ACK分組被偽造,以便它似乎來自客戶端。為Challenge ACK的可發(fā)出(最初100個(gè)數(shù)據(jù)包)時(shí),計(jì)數(shù)器跟蹤和描繪的服務(wù)器的時(shí)間軸上。
圖4-四元組連接測(cè)試
我們的期望是最初欺騙SYN-ACK分組將擊中對(duì)應(yīng)于客戶端和服務(wù)器之間的有效連接一個(gè)正確的四元組。在這種情況下(圖4的左側(cè))的服務(wù)器將是一個(gè)Challenge ACK2(按照對(duì)策建議防范Blind SYN數(shù)據(jù)包注入,這個(gè)在后面會(huì)有說明)答復(fù)。同時(shí),這會(huì)從100這一全局的Challenge ACK數(shù)減少到99.在那里的欺騙性SYN-ACK不打正確的四元組(上圖右)的情況下,服務(wù)器將簡(jiǎn)單地回復(fù)一個(gè)RST回相應(yīng)的客戶機(jī)(每個(gè)TCP標(biāo)準(zhǔn))。
然后,攻擊者會(huì)發(fā)送100個(gè)非欺騙IN-WindowRST包用盡Challenge ACK計(jì)數(shù)(這種行為我們?cè)谇懊嬗性敿?xì)描述)。在活動(dòng)的連接的情況下,由于挑戰(zhàn)的ACK計(jì)數(shù)為99,攻擊者現(xiàn)在可以觀察只有99挑戰(zhàn)的ACK。在沒有連接的情況下,攻擊者可以觀察100在挑戰(zhàn)ACK的數(shù)量的差異,從而有效的泄漏有關(guān)測(cè)試四元組是否對(duì)應(yīng)于活動(dòng)連接與否的信息。
推算序列號(hào):假設(shè)攻擊者已經(jīng)確定對(duì)應(yīng)于該客戶機(jī)和服務(wù)器之間的有效連接一個(gè)四元組,偏離路徑攻擊者現(xiàn)在需要猜測(cè)由服務(wù)器認(rèn)為可接受的有效序列號(hào)。圖 –URE5示出了攻擊者可以發(fā)送的(i)該情況之間進(jìn)行區(qū)分的分組的在窗口和(ii)外的窗口序列號(hào)的序列。在那里的欺騙性RST分組具有在窗口序列號(hào)(而不是下一個(gè)預(yù)期的序列號(hào)),如每對(duì)策提出了抵御Blind RST分組注射如在前面(2)中描述,一個(gè)Challenge ACK被觸發(fā),并且第一殼體這減少了從100到99的全局ACK Request計(jì)數(shù)在將序列號(hào)落在窗口之外的第二情況下,沒有Challenge ACK將生成(全局的Challenge ACK計(jì)數(shù)保持在100)。
以連接推論類似,攻擊者現(xiàn)在將派遣100名非欺騙的窗口RST包用盡Challenge ACK計(jì)數(shù)。再一次,根據(jù)有多少接收Challenge ACK,攻擊者能知道在欺騙性RST猜測(cè)的序列號(hào),是在此窗口或外的窗口。
圖5-序列號(hào)測(cè)試
ACK序列推斷:活動(dòng)連接的一個(gè)在窗的序列號(hào)被識(shí)別后,攻擊者現(xiàn)在需要猜測(cè)由該服務(wù)器認(rèn)為可接受有效的ACK號(hào)碼。圖6顯示了攻擊者可以發(fā)送來區(qū)分的挑戰(zhàn)的ACK窗口和(ii)其它的ACK編號(hào)(?。┑腁CK的情況下,分組的序列。在欺騙性ACK分組具有Challenge ACK窗口(但具有在窗口序列號(hào))的ACK編號(hào)第一種情況下,服務(wù)器將具有Challenge ACK應(yīng)答,根據(jù)該對(duì)策提出了抵御盲數(shù)據(jù)包注入(在前面有描述)。按照與之前相同的方法,如果該猜測(cè)ACK號(hào)落在挑戰(zhàn)ACK窗口的攻擊者可以推斷。如將在后面描述的那樣,這有助于攻擊最終識(shí)別服務(wù)器上SND.NXT。
圖6-ACK序列號(hào)測(cè)試
值得注意的是,一旦雙方的順序號(hào)和ACK號(hào)由服務(wù)器上可接受的被推斷,攻擊者能夠確定由客戶端上可接受的順序號(hào)和ACK號(hào)為好。這是因?yàn)镽CV.NXT和SND.NXT服務(wù)器上基本上等同于SND.NXT和RCV.NXT在客戶端[25,18]上。在實(shí)踐中,如果受害者連接具有正在進(jìn)行的信息流,推斷序列和ACK號(hào)可能會(huì)改變作為攻擊正在進(jìn)行。我們§6討論了這樣的情況。
另一種推理序列號(hào)的方法:
在某些情況下,大量的在一個(gè)短的時(shí)間內(nèi)觀察到的RST包的可以考慮AB-正常。防火墻甚至可能對(duì)每個(gè)連接速率限制RST包。為了緩解這一點(diǎn),其實(shí)是可以與ACK包,這很可能會(huì)留在雷達(dá)之下RST更換包。正如圖3所示,當(dāng)ACK號(hào)是在挑戰(zhàn)ACK窗口而序列號(hào)是IN-窗口一個(gè)挑戰(zhàn)的ACK將被發(fā)送。由于挑戰(zhàn)ACK窗口空間是號(hào)碼ack空間的整個(gè)4G的至少1/4,可以發(fā)送4個(gè)包與ACK號(hào)碼0,1G,2G和3G分別與至少一個(gè)分組將觸發(fā)一個(gè)挑戰(zhàn)的ACK如果猜測(cè)的序列號(hào)是在窗口。要明白為什么挑戰(zhàn)ACK窗口至少是這么大,我們首先指出,最大接收窗口的大小為1G的TCP窗口縮放。
選項(xiàng) (RFC 7323),這意味著SND.MAX.WIN不能超過1G大。因此,根據(jù)在上文中描述的挑戰(zhàn)的ACK窗口的定義,它是至少1G為好。鑒于此,對(duì)于前面的序列號(hào)發(fā)送推斷每欺騙RST包由四個(gè)ACK包,這是效率較低,但仍然是有效的放置重。我們已經(jīng)實(shí)施和測(cè)試序列號(hào)推斷這種替代方法。然而,為了簡(jiǎn)化說明,我們假定使用與在后續(xù)部分RST包原始序列號(hào)推斷。
* 本文原創(chuàng)作者:Leon不會(huì)玩QEMU,本文屬FreeBuf原創(chuàng)獎(jiǎng)勵(lì)計(jì)劃,未經(jīng)許可禁止轉(zhuǎn)載