一般我們會認為,要確認互聯網上的任意兩臺主機設備是否建立TCP連接通訊,其實并不容易——攻擊者如果不在雙方的通訊路徑中,就更是如此了。另外如果攻擊者并不在通訊路徑中,要中途中斷雙方的這種連接,甚至是篡改連接,理論上也是不大可能的。
不過來自加州大學河濱分校,以及美國陸軍研究實驗室的6名研究人員,最近聯合發表了一篇論文,題為《Off-Path TCP Exploits: Global Rate Limite Considered Dangerous》。這篇文章提到Linux服務器的TCP連接實施方案存在高危安全漏洞,攻擊者可利用該漏洞來劫持未加密Web流量,或者破壞如Tor連接一類的加密通訊;此漏洞編號CVE-2016-5696。
這里的“高危”屬性,主要體現在幾點,其一是“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用戶而言,還是準備做升級工作吧。