摘要:滑動(dòng)窗口滑動(dòng)窗口毫無(wú)疑問(wèn)是用來(lái)加速數(shù)據(jù)傳輸?shù)?。處理程序?huì)在自己認(rèn)為的異常時(shí)刻發(fā)送包。序列號(hào)問(wèn)題是與滑動(dòng)窗口對(duì)應(yīng)的,偽造的包里需要填序列號(hào),如果序列號(hào)的值不在之前向發(fā)送時(shí)的滑動(dòng)窗口內(nèi),是會(huì)主動(dòng)丟棄的。
看Apache HttpClient的源碼時(shí),發(fā)現(xiàn)abortRequest的時(shí)候,調(diào)用到socket時(shí)代碼如下:
public void shutdown() throws IOException { Socket socket = (Socket)this.socketHolder.getAndSet((Object)null); if (socket != null) { try { socket.setSoLinger(true, 0); } catch (IOException var6) { ; } finally { socket.close(); } } }
what is so_linger?這個(gè)嘛得先從tcp三次握手與四次揮手說(shuō)起:
TCP三次握手與四次揮手三次握手建立連接:
為了能夠說(shuō)清楚后面的RST攻擊,需要結(jié)合上圖說(shuō)說(shuō):SYN標(biāo)志位、序號(hào)、滑動(dòng)窗口大小。
建立連接的請(qǐng)求中,標(biāo)志位SYN都要置為1,在這種請(qǐng)求中會(huì)告知MSS段大小,就是本機(jī)希望接收TCP包的最大大小。
發(fā)送的數(shù)據(jù)TCP包都有一個(gè)序號(hào)。它是這么得來(lái)的:最初發(fā)送SYN時(shí),有一個(gè)初始序號(hào),根據(jù)RFC的定義,各個(gè)操作系統(tǒng)的實(shí)現(xiàn)都是與系統(tǒng)時(shí)間相關(guān)的。之后,序號(hào)的值會(huì)不斷的增加,比如原來(lái)的序號(hào)是100,如果這個(gè)TCP包的數(shù)據(jù)有10個(gè)字節(jié),那么下次的TCP包序號(hào)會(huì)變成110。
滑動(dòng)窗口用于加速傳輸,比如發(fā)了一個(gè)seq=100的包,理應(yīng)收到這個(gè)包的確認(rèn)ack=101后再繼續(xù)發(fā)下一個(gè)包,但有了滑動(dòng)窗口,只要新包的seq與沒(méi)有得到確認(rèn)的最小seq之差小于滑動(dòng)窗口大小,就可以繼續(xù)發(fā)。
滑動(dòng)窗口
滑動(dòng)窗口毫無(wú)疑問(wèn)是用來(lái)加速數(shù)據(jù)傳輸?shù)摹CP要保證“可靠”,就需要對(duì)一個(gè)數(shù)據(jù)包進(jìn)行ack確認(rèn)表示接收端收到。有了滑動(dòng)窗口,接收端就可以等收到許多包后只發(fā)一個(gè)ack包,確認(rèn)之前已經(jīng)收到過(guò)的多個(gè)數(shù)據(jù)包。有了滑動(dòng)窗口,發(fā)送端在發(fā)送完一個(gè)數(shù)據(jù)包后不用等待它的ack,在滑動(dòng)窗口大小內(nèi)可以繼續(xù)發(fā)送其他數(shù)據(jù)包。
如果談到TCP攻擊就需要注意,TCP的各種實(shí)現(xiàn)中,在滑動(dòng)窗口之外的seq會(huì)被扔掉!
四次握手的正常TCP連接關(guān)閉
FIN標(biāo)志位也看到了,它用來(lái)表示正常關(guān)閉連接。圖的左邊是主動(dòng)關(guān)閉連接方,右邊是被動(dòng)關(guān)閉連接方,用netstat命令可以看到標(biāo)出的連接狀態(tài)。
FIN是正常關(guān)閉,它會(huì)根據(jù)緩沖區(qū)的順序來(lái)發(fā)的,就是說(shuō)緩沖區(qū)FIN之前的包都發(fā)出去后再發(fā)FIN包,這與RST不同。
RST表示復(fù)位,用來(lái)異常的關(guān)閉連接,在TCP的設(shè)計(jì)中它是不可或缺的。就像上面說(shuō)的一樣,發(fā)送RST包關(guān)閉連接時(shí),不必等緩沖區(qū)的包都發(fā)出去(不像上面的FIN包),直接就丟棄緩存區(qū)的包發(fā)送RST包。而接收端收到RST包后,也不必發(fā)送ACK包來(lái)確認(rèn)。
TCP處理程序會(huì)在自己認(rèn)為的異常時(shí)刻發(fā)送RST包。例如,A向B發(fā)起連接,但B之上并未監(jiān)聽(tīng)相應(yīng)的端口,這時(shí)B操作系統(tǒng)上的TCP處理程序會(huì)發(fā)RST包。
又比如,AB正常建立連接了,正在通訊時(shí),A向B發(fā)送了FIN包要求關(guān)連接,B發(fā)送ACK后,網(wǎng)斷了,A通過(guò)若干原因放棄了這個(gè)連接(例如進(jìn)程重啟)。網(wǎng)通了后,B又開(kāi)始發(fā)數(shù)據(jù)包,A收到后表示壓力很大,不知道這野連接哪來(lái)的,就發(fā)了個(gè)RST包強(qiáng)制把連接關(guān)了,B收到后會(huì)出現(xiàn)connect reset by peer錯(cuò)誤。
說(shuō)了這么多好像還沒(méi)說(shuō)so_linger.
so_lingerLinux網(wǎng)絡(luò)編程中,socket的選項(xiàng)很多.其中幾個(gè)比較重要的選項(xiàng)有:SO_LINGER(僅僅適用于TCP,SCTP), SO_REUSEADDR.
在默認(rèn)情況下,當(dāng)調(diào)用close關(guān)閉socke的使用,close會(huì)立即返回,但是,如果send buffer中還有數(shù)據(jù),系統(tǒng)會(huì)試著先把send buffer中的數(shù)據(jù)發(fā)送出去,然后close才返回.
SO_LINGER選項(xiàng)則是用來(lái)修改這種默認(rèn)操作的.于SO_LINGER相關(guān)聯(lián)的一個(gè)結(jié)構(gòu)體如下:
#includestruct linger { int l_onoff //0=off, nonzero=on(開(kāi)關(guān)) int l_linger //linger time(延遲時(shí)間) }
當(dāng)調(diào)用setsockopt之后,該選項(xiàng)產(chǎn)生的影響取決于linger結(jié)構(gòu)體中 l_onoff和l_linger的值:
0 = l_onoff
當(dāng)l_onoff被設(shè)置為0的時(shí)候,將會(huì)關(guān)閉SO_LINGER選項(xiàng),即TCP或則SCTP保持默認(rèn)操作:close立即返回.l_linger值被忽略.
l_lineoff值非0,0 = l_linger
當(dāng)調(diào)用close的時(shí)候,TCP連接會(huì)立即斷開(kāi).send buffer中未被發(fā)送的數(shù)據(jù)將被丟棄,并向?qū)Ψ桨l(fā)送一個(gè)RST信息.值得注意的是,由于這種方式,是非正常的4中握手方式結(jié)束TCP鏈接,所以,TCP連接將不會(huì)進(jìn)入TIME_WAIT狀態(tài),這樣會(huì)導(dǎo)致新建立的可能和就連接的數(shù)據(jù)造成混亂。
l_onoff和l_linger都是非0
在這種情況下,回事的close返回得到延遲。調(diào)用close去關(guān)閉socket的時(shí)候,內(nèi)核將會(huì)延遲。也就是說(shuō),如果send buffer中還有數(shù)據(jù)尚未發(fā)送,該進(jìn)程將會(huì)被休眠直到一下任何一種情況發(fā)生:
1) send buffer中的所有數(shù)據(jù)都被發(fā)送并且得到對(duì)方TCP的應(yīng)答消息(這種應(yīng)答并不是意味著對(duì)方應(yīng)用程序已經(jīng)接收到數(shù)據(jù),在后面shutdown將會(huì)具體講道)
2) 延遲時(shí)間消耗完。在延遲時(shí)間被消耗完之后,send buffer中的所有數(shù)據(jù)都將會(huì)被丟棄。
上面1),2)兩種情況中,如果socket被設(shè)置為O_NONBLOCK狀態(tài),程序?qū)⒉粫?huì)等待close返回,send buffer中的所有數(shù)據(jù)都將會(huì)被丟棄。所以,需要我們判斷close的返回值。在send buffer中的所有數(shù)據(jù)都被發(fā)送之前并且延遲時(shí)間沒(méi)有消耗完,close返回的話,close將會(huì)返回一個(gè)EWOULDBLOCK的error.
1.默認(rèn)操作的close,close立即返回
說(shuō)明:我們已經(jīng)知道write操作返回成功只能說(shuō)明數(shù)據(jù)已經(jīng)發(fā)送到套接字的發(fā)送緩沖區(qū),不能代表對(duì)端已經(jīng)成功收到數(shù)據(jù),close的默認(rèn)返回成功也只是成功發(fā)出了一個(gè)FIN分節(jié),也不代表對(duì)端已經(jīng)確認(rèn)
2.設(shè)置SO_LINGER套接字選項(xiàng)且l_linger為正值時(shí)的close:【數(shù)據(jù)ack了,并收到FIN了】 才返回
說(shuō)明:這種情況下客戶的close要到它的數(shù)據(jù)和FIN已經(jīng)被服務(wù)器的TCP確認(rèn)以后才會(huì)返回;
3.設(shè)置SO_LINGER套接字選項(xiàng)且l_linger為偏小正值時(shí)的close:時(shí)間到了 返回-1,EWOULDBLOCK錯(cuò)誤
說(shuō)明:在服務(wù)端的確認(rèn)到達(dá)之前,SO_LINGER套接字選項(xiàng)設(shè)置的延滯時(shí)間到,close將會(huì)返回EWOULDBLOCK錯(cuò)誤,且套接字發(fā)送緩沖區(qū)中的任何殘留數(shù)據(jù)被丟棄。
總結(jié):設(shè)置SO_LINGER套接字選項(xiàng)以后,close的成功返回只是告訴我們先前發(fā)送的數(shù)據(jù)的FIN已經(jīng)由對(duì)端TCP確認(rèn),而不能告訴我們對(duì)端應(yīng)用進(jìn)程是否已經(jīng)讀取數(shù)據(jù),如果不設(shè)置該套接字選項(xiàng),那么我們連對(duì)端TCP是否確認(rèn)了數(shù)據(jù)都不知道。
l_onoff 非0,l_linger為0,丟棄發(fā)送緩沖區(qū)的任何數(shù)據(jù),并發(fā)送rst給對(duì)端,沒(méi)有四分組連接終止序列--沒(méi)有fin,這樣一來(lái)避免了TIME_WAIT狀態(tài),但是在2MSL秒內(nèi)創(chuàng)建該連接的新化身,導(dǎo)致來(lái)自剛剛終止的連接上的舊數(shù)據(jù)被不正確的傳送到新的化身上
回到這段代碼
public void shutdown() throws IOException { Socket socket = (Socket)this.socketHolder.getAndSet((Object)null); if (socket != null) { try { socket.setSoLinger(true, 0); } catch (IOException var6) { ; } finally { socket.close(); } } }
設(shè)置的是上述第三點(diǎn):設(shè)置SO_LINGER套接字選項(xiàng)且l_linger為偏小正值時(shí)的close:時(shí)間到了 返回-1,EWOULDBLOCK錯(cuò)誤. 為0立即返回,然后收到FIN之后發(fā)送RST,不會(huì)進(jìn)入TIME_WAIT狀態(tài)。
附:RST攻擊A和服務(wù)器B之間建立了TCP連接,此時(shí)C偽造了一個(gè)TCP包發(fā)給B,使B異常的斷開(kāi)了與A之間的TCP連接,就是RST攻擊了。實(shí)際上從上面RST標(biāo)志位的功能已經(jīng)可以看出這種攻擊如何達(dá)到效果了。
那么偽造什么樣的TCP包可以達(dá)成目的呢?我們至頂向下的看。
假定C偽裝成A發(fā)過(guò)去的包,這個(gè)包如果是RST包的話,毫無(wú)疑問(wèn),B將會(huì)丟棄與A的緩沖區(qū)上所有數(shù)據(jù),強(qiáng)制關(guān)掉連接。
如果發(fā)過(guò)去的包是SYN包,那么,B會(huì)表示A已經(jīng)發(fā)瘋了(與OS的實(shí)現(xiàn)有關(guān)),正常連接時(shí)又來(lái)建新連接,B主動(dòng)向A發(fā)個(gè)RST包,并在自己這端強(qiáng)制關(guān)掉連接。
這兩種方式都能夠達(dá)到復(fù)位攻擊的效果。似乎挺恐怖,然而關(guān)鍵是,如何能偽造成A發(fā)給B的包呢?這里有兩個(gè)關(guān)鍵因素,源端口和序列號(hào)。
一個(gè)TCP連接都是四元組,由源IP、源端口、目標(biāo)IP、目標(biāo)端口唯一確定一個(gè)連接。所以,如果C要偽造A發(fā)給B的包,要在上面提到的IP頭和TCP頭,把源IP、源端口、目標(biāo)IP、目標(biāo)端口都填對(duì)。這里B作為服務(wù)器,IP和端口是公開(kāi)的,A是我們要下手的目標(biāo),IP當(dāng)然知道,但A的源端口就不清楚了,因?yàn)檫@可能是A隨機(jī)生成的。當(dāng)然,如果能夠?qū)ΤR?jiàn)的OS如windows和linux找出生成source port規(guī)律的話,還是可以搞定的。
序列號(hào)問(wèn)題是與滑動(dòng)窗口對(duì)應(yīng)的,偽造的TCP包里需要填序列號(hào),如果序列號(hào)的值不在A之前向B發(fā)送時(shí)B的滑動(dòng)窗口內(nèi),B是會(huì)主動(dòng)丟棄的。所以我們要找到能落到當(dāng)時(shí)的AB間滑動(dòng)窗口的序列號(hào)。這個(gè)可以暴力解決,因?yàn)橐粋€(gè)sequence長(zhǎng)度是32位,取值范圍0-4294967296,如果窗口大小像上圖中我抓到的windows下的65535的話,只需要相除,就知道最多只需要發(fā)65537(4294967296/65535=65537)個(gè)包就能有一個(gè)序列號(hào)落到滑動(dòng)窗口內(nèi)。RST包是很小的,IP頭+TCP頭也才40字節(jié),算算我們的帶寬就知道這實(shí)在只需要幾秒鐘就能搞定。
那么,序列號(hào)不是問(wèn)題,源端口會(huì)麻煩點(diǎn),如果各個(gè)操作系統(tǒng)不能完全隨機(jī)的生成源端口,或者黑客們能通過(guò)其他方式獲取到source port,RST攻擊易如反掌,后果很嚴(yán)重。
參考:http://blog.csdn.net/russell_...
https://www.cnblogs.com/my_li...
http://blog.csdn.net/le119126...
《UNIX Network ProgrammingVolume 1, Third Edition: TheSockets Networking API》
http://blog.csdn.net/yusiguyu...
http://blog.csdn.net/yusiguyu...
http://www.cs.northwestern.ed...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70740.html
摘要:我們知道通過(guò)三次握手建立可靠連接,通過(guò)四次揮手?jǐn)嚅_(kāi)連接,連接是比較昂貴的資源。從上分析,安全可靠的斷開(kāi)連接至少需要四次,再多一次的意義不大。連接的異常斷開(kāi)以上都是在理想的情況下發(fā)生的,理想狀態(tài)下,一個(gè)連接可以被長(zhǎng)期保持。 我們知道TCP通過(guò)三次握手建立可靠連接,通過(guò)四次揮手?jǐn)嚅_(kāi)連接,TCP連接是比較昂貴的資源。為什么TCP需要通過(guò)三次握手才能建立可靠的連接??jī)纱尾恍忻??斷開(kāi)連接為什么需...
摘要:上,數(shù)據(jù)按有限大小的包傳輸,這些包成為數(shù)據(jù)報(bào),每個(gè)數(shù)據(jù)報(bào)包含一個(gè)首部和一個(gè)有效載荷。不過(guò),由于數(shù)據(jù)報(bào)長(zhǎng)度有限,通常必須將數(shù)據(jù)分解為多個(gè)包,再在目的地重新組合。這兩個(gè)構(gòu)造函數(shù),在返回之前會(huì)與遠(yuǎn)程主機(jī)建立一個(gè)活動(dòng)的網(wǎng)絡(luò)連接。 Internet上,數(shù)據(jù)按有限大小的包傳輸,這些包成為數(shù)據(jù)報(bào)(datagram),每個(gè)數(shù)據(jù)報(bào)包含一個(gè)首部(header)和一個(gè)有效載荷(payload)。首部包含包發(fā)...
摘要:超簡(jiǎn)單深度睡眠模式下遠(yuǎn)程采集溫濕度信息項(xiàng)目背景相關(guān)技術(shù)深度睡眠模式溫濕度采集數(shù)據(jù)收發(fā)前后端實(shí)現(xiàn)后端前端項(xiàng)目背景自己用收納箱做了一個(gè)用于存放打印耗材的干燥箱,想用閑置的開(kāi)發(fā)板和溫濕度傳感器做一個(gè)遠(yuǎn)程溫濕度監(jiān)測(cè)的小項(xiàng)目。 ...
閱讀 3159·2021-11-23 10:02
閱讀 3129·2021-11-16 11:53
閱讀 3105·2021-09-23 11:21
閱讀 3379·2019-08-30 13:02
閱讀 1638·2019-08-29 16:18
閱讀 1569·2019-08-29 12:55
閱讀 1467·2019-08-26 12:24
閱讀 2095·2019-08-26 10:36