從TCP協議的原理來談談rst復位攻擊

在談RST攻擊前,必須先了解TCP:如何經過三次握手創建TCP鏈接、四次握手怎樣把全雙工的鏈接關閉掉、滑動窗口是怎麼傳輸數據的、TCP的flag標誌位裏RST在哪些狀況下出現。下面我會畫一些儘可能簡化的圖來表達清楚上述幾點,以後再瞭解下RST攻擊是怎麼回事。linux

一、TCP是什麼?

TCP是在IP網絡層之上的傳輸層協議,用於提供port到port面向鏈接的可靠的字節流傳輸。我來用土語解釋下上面的幾個關鍵字:golang

port到port:IP層只管數據包從一個IP到另外一個IP的傳輸,IP層之上的TCP層加上端口後,就是面向進程了,每一個port均可以對應到用戶進程。windows

可靠:TCP會負責維護實際上子虛烏有的鏈接概念,包括收包後的確認包、丟包後的重發等來保證可靠性。因爲帶寬和不一樣機器處理能力的不一樣,TCP要能控制流量。緩存

字節流:TCP會把應用進程傳來的字節流數據切割成許多個數據包,在網絡上發送。IP包是會失去順序或者產生重複的,TCP協議要能還原到字節流原本面目。服務器

從TCP協議的原理來談談rst復位攻擊

從上面的TCP協議圖能夠看到,標誌位共有六個,其中RST位就在TCP異常時出現,也是我這篇文章重點關注的地方。網絡

二、經過三次握手創建鏈接

下面我經過A向B創建TCP鏈接來講明三次握手怎麼完成的。架構

從TCP協議的原理來談談rst復位攻擊

爲了可以說清楚下面的RST攻擊,須要結合上圖說說:SYN標誌位、序號、滑動窗口大小。學習

創建鏈接的請求中,標誌位SYN都要置爲1,在這種請求中會告知MSS段大小,就是本機但願接收TCP包的最大大小。spa

發送的數據TCP包都有一個序號。它是這麼得來的:最初發送SYN時,有一個初始序號,根據RFC的定義,各個操做系統的實現都是與系統時間相關的。以後,序號的值會不斷的增長,好比原來的序號是100,若是這個TCP包的數據有10個字節,那麼下次的TCP包序號會變成110。操作系統

滑動窗口用於加速傳輸,好比發了一個seq=100的包,理應收到這個包的確認ack=101後再繼續發下一個包,但有了滑動窗口,只要新包的seq與沒有獲得確認的最小seq之差小於滑動窗口大小,就能夠繼續發。

三、滑動窗口

滑動窗口毫無疑問是用來加速數據傳輸的。TCP要保證「可靠」,就須要對一個數據包進行ack確認表示接收端收到。有了滑動窗口,接收端就能夠等收到許多包後只發一個ack包,確認以前已經收到過的多個數據包。有了滑動窗口,發送端在發送完一個數據包後不用等待它的ack,在滑動窗口大小內能夠繼續發送其餘數據包。舉個例子來看吧。

從TCP協議的原理來談談rst復位攻擊

你們看上圖,標誌位爲.表示全部的flag都爲0。標誌位P表示flag爲PSH的TCP包,用於快速傳輸數據。

前三個包是三次握手,客戶端表示本身的滑動窗口大小是65535(個人XP機器),服務器端表示滑動窗口是5840(屏幕寬了,沒截出來)。從第四個包開始,客戶端向服務器發送PSH包,數據長度是520字節,服務器發了ack確認包。注意此時win窗口大小發生了改變哈。以此類推。

倒數第2、三包,服務器在滑動窗口內連續向客戶端發包,客戶端發送的ack 124同時確認了以前的兩個包。這就是滑動窗口的功能了。

若是談到TCP攻擊就須要注意,TCP的各類實現中,在滑動窗口以外的seq會被扔掉!下面會講這個問題。

須要C/C++ Linux服務器架構師學習資料加羣812855908(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享

從TCP協議的原理來談談rst復位攻擊

四、四次握手的正常TCP鏈接關閉

先畫張簡單的正常關閉鏈接狀態變遷圖。

從TCP協議的原理來談談rst復位攻擊

FIN標誌位也看到了,它用來表示正常關閉鏈接。圖的左邊是主動關閉鏈接方,右邊是被動關閉鏈接方,用netstat命令能夠看到標出的鏈接狀態。

FIN是正常關閉,它會根據緩衝區的順序來發的,就是說緩衝區FIN以前的包都發出去後再發FIN包,這與RST不一樣。

五、RST標誌位

RST表示復位,用來異常的關閉鏈接,在TCP的設計中它是不可或缺的。就像上面說的同樣,發送RST包關閉鏈接時,沒必要等緩衝區的包都發出去(不像上面的FIN包),直接就丟棄緩存區的包發送RST包。而接收端收到RST包後,也沒必要發送ACK包來確認。

TCP處理程序會在本身認爲的異常時刻發送RST包。例如,A向B發起鏈接,但B之上並未監聽相應的端口,這時B操做系統上的TCP處理程序會發RST包。

又好比,AB正常創建鏈接了,正在通信時,A向B發送了FIN包要求關鏈接,B發送ACK後,網斷了,A經過若干緣由放棄了這個鏈接(例如進程重啓)。網通了後,B又開始發數據包,A收到後表示壓力很大,不知道這野鏈接哪來的,就發了個RST包強制把鏈接關了,B收到後會出現connect reset by peer錯誤。

六、RST攻擊

A和服務器B之間創建了TCP鏈接,此時C僞造了一個TCP包發給B,使B異常的斷開了與A之間的TCP鏈接,就是RST攻擊了。實際上從上面RST標誌位的功能已經能夠看出這種攻擊如何達到效果了。

那麼僞造什麼樣的TCP包能夠達成目的呢?咱們至頂向下的看。

假定C假裝成A發過去的包,這個包若是是RST包的話,毫無疑問,B將會丟棄與A的緩衝區上全部數據,強制關掉鏈接。

若是發過去的包是SYN包,那麼,B會表示A已經發瘋了(與OS的實現有關),正常鏈接時又來建新鏈接,B主動向A發個RST包,並在本身這端強制關掉鏈接。

這兩種方式都可以達到復位攻擊的效果。彷佛挺恐怖,然而關鍵是,如何能僞形成A發給B的包呢?這裏有兩個關鍵因素,源端口和序列號。

一個TCP鏈接都是四元組,由源IP、源端口、目標IP、目標端口惟一肯定一個鏈接。因此,若是C要僞造A發給B的包,要在上面提到的IP頭和TCP頭,把源IP、源端口、目標IP、目標端口都填對。這裏B做爲服務器,IP和端口是公開的,A是咱們要下手的目標,IP固然知道,但A的源端口就不清楚了,由於這多是A隨機生成的。固然,若是可以對常見的OS如windows和linux找出生成source port規律的話,仍是能夠搞定的。

序列號問題是與滑動窗口對應的,僞造的TCP包裏須要填序列號,若是序列號的值不在A以前向B發送時B的滑動窗口內,B是會主動丟棄的。因此咱們要找到能落到當時的AB間滑動窗口的序列號。這個能夠暴力解決,由於一個sequence長度是32位,取值範圍0-4294967296,若是窗口大小像上圖中我抓到的windows下的65535的話,只須要相除,就知道最多隻須要發65537(4294967296/65535=65537)個包就能有一個序列號落到滑動窗口內。RST包是很小的,IP頭+TCP頭也才40字節,算算咱們的帶寬就知道這實在只須要幾秒鐘就能搞定。

那麼,序列號不是問題,源端口會麻煩點,若是各個操做系統不能徹底隨機的生成源端口,或者黑客們能經過其餘方式獲取到source port,RST攻擊易如反掌,後果很嚴重。

相關文章
相關標籤/搜索