天天看點

mapperscan掃描多個包_掃描器篇(八)之python+scapy構造TCP協定包掃描主機端口

TCP協定端口掃描

要使用TCP協定去完成端口掃描,肯定是需要了解TCP協定通信過程和原理才能完成的

TCP協定的特點

1

面向連接配接的:使用TCP協定通信的雙方必須先建立連接配接,然後才能開始資料的讀寫,TCP連接配接是

全雙工的,即雙方的資料讀寫可以通過一個連接配接進行。完成資料交換之後,通信雙方都必須斷開

連接配接以釋放資源。TCP協定的這種連接配接是一對一的,是以基于廣播和多點傳播(目标是多個主機位址)

的應用程式不能使用TCP服。而無連接配接協定UDP則非常适合于廣播和多點傳播。

流式服務:TCP的位元組流服務的表現形式就展現在,發送端執行的寫操作數和接收端執行的讀操作

次數之間沒有任何數量關系,當發送端應用程式連續執行多次寫操作的時,TCP子產品先将這些資料

放入TCP發送緩沖區中。當TCP子產品真正開始發送資料的時候,發送緩沖區中這些等待發送的資料

可能被封裝成一個或多個TCP封包段發出。

TCP通過檢驗和,序列号,确認應答,重發控制,連接配接管理以及視窗控制等機制實作可靠性傳輸。

1

TCP三向交握介紹

所謂三次握手(Three-way Handshake),是指建立一個 TCP 連接配接時,需要用戶端和伺服器總共發

送3個包。三次握手的目的是連接配接伺服器指定端口,建立 TCP 連接配接,并同步連接配接雙方的序列号和确認号,

交換 TCP 視窗大小資訊。在 socket 程式設計中,用戶端執行 connect() 時。将觸發三次握手。

第一次握手(SYN=1, seq=x):用戶端發送一個 TCP 的 SYN 标志位置1的包,指明用戶端打算連接配接的伺服器

的端口,以及初始序号 X,儲存在標頭的序列号(Sequence Number)字段裡。

發送完畢後,用戶端進入 SYN_SEND 狀态。

第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):伺服器發回确認包(ACK)應答。即 SYN 标志位和

ACK 标志位均為1。伺服器端選擇自己 ISN 序列号,放到 Seq 域裡,同時将确認序号(Acknowledgement Number)

設定為客戶的 ISN 加1,即X+1。 發送完畢後,伺服器端進入 SYN_RCVD 狀态。

第三次握手(ACK=1,ACKnum=y+1)用戶端再次發送确認包(ACK),SYN 标志位為0,ACK 标志位為1,

并且把伺服器發來ACK 的序号字段+1,放在确定字段中發送給對方,并且在資料段放寫ISN的+1發送完

畢後,用戶端進入 ESTABLISHED 狀态,當伺服器端接收到這個包時,也進入 ESTABLISHED 狀态,TCP 握手結束。

TCP協定常見标志位

FIN:斷開連接配接,對應值1

1

SYN:同步信号,用于連接配接,對應值2

1

RST:重置連接配接,對應值4

1

ACK:确認資訊,對應值位16

1

掃描原理

通過構造TCP 标志位(flags)為SYN的資料包,向目标主機端口請求連接配接

1

目标主機端口如果開放的話,收到SYN資料包請求建立三次握手,就會回複SYN+ACK同意建立連接配接。

1

判斷目标主機響應資料包中是否存在SYN+ACK标志位存在

1

代碼部分

掃描函數

構造TCP标志位為SYN的資料包,向目标主機端口發送

1

判斷響應包鐘是否存在SYN+ACK,存在即端口開放

1

def scan(ip,port):

try:

packet = IP(dst=ip)/TCP(dport=port, flags="S")# 構造标志位為syn的資料包

result = sr1(packet,timeout=0.5, verbose=0)

if int(result[TCP].flags) == 18:

# 通過判斷響應的資料包中,是否存在第二次握手Ack+syn标志位,存在即端口開放

time.sleep(0.1)

print(ip, "TCP" , port, "open")

# 注意這裡如果使用+号進行字元串拼接的話會導緻報錯,使用逗号即可拼接

return

except:

pass

參數擷取

擷取使用者輸入的參數,并執行個體化

1

判斷使用者是掃描i單個ip位址還是網段亦是讀取ip位址檔案

1

調用多線程去執行掃描函數

def main():

# 如果沒有輸出參數就會輸出幫助資訊

parser = OptionParser("Usage program -i -n -p ")

parser.add_option("-i", '--host', type="string",dest="tgtIP",help="specify target host or website")

parser.add_option("-n","--network", type="string",dest="tgtNetwork",help="specify target Network")

parser.add_option("-f", "--addressfile", type="string", dest="tgtFile", help="specify target addressfile")

parser.add_option("-p","--port", type="string",dest="tgtPorts",help="specify target port separated by comma")

options,args = parser.parse_args()# 執行個體化使用者輸入的參數

tgtIP = options.tgtIP

tgtNetwork = options.tgtNetwork # 網段

tgtFile = options.tgtFile

tgtPorts = options.tgtPorts

tgtPorts = tgtPorts.split(",") # 将使用者輸入的多個端口以逗号分割生成清單

if tgtPorts is None or tgtNetwork is None and tgtIP is None and tgtFile is None :# 判斷使用者是否輸入參數

print(parser.usage)# 如果沒有輸入參數則輸出幫助資訊,然後退出程式

exit(0)

if tgtIP:# 輸入單個ip位址時的操作

for p in tgtPorts:

port = int(p)

t = Thread(target=scan,args=(tgtIP,port))

t.start()

if tgtNetwork:# 輸入整個網段時的操作

prefix = tgtNetwork.split(".")[0] + "." + tgtNetwork.split(".")[1] + "." + tgtNetwork.split(".")[2] + "."# 将使用者輸入的網段提取提取前三位當作字首

for i in range(1,255):

ip = prefix + str(i)# 和字首結合形成網段内所有的位址

for p in tgtPorts:

port = int(p)

t = Thread(target=scan, args=(ip,port))

t.start()

if tgtFile:# 如果時位址檔案則進行的操作

if not os.path.exists(tgtFile):# 判斷檔案是否存在

print("File not founFd")

sys.exit()

with open(tgtFile,"r") as f:# 讀取位址檔案

for i in f.readlines():

ip = i.strip()# 讀取使用者位址檔案的位址,并去點換行空格

for p in tgtPorts:

port = p.strip()

port = int(port)

t = Thread(target=scan,args=(ip,port))

t.start()# 多線程掃描

整體代碼

import os

import time

from scapy.all import *

from optparse import OptionParser

from threading import Thread

def scan(ip,port):

try:

packet = IP(dst=ip)/TCP(dport=port, flags="S")# 構造标志位為syn的資料包

result = sr1(packet,timeout=0.5, verbose=0)

if int(result[TCP].flags) == 18:

# 通過判斷響應的資料包中,是否存在第二次握手Ack+syn标志位,存在即端口開放

time.sleep(0.1)

print(ip, "TCP" , port, "open")

# 注意這裡如果使用+号進行字元串拼接的話會導緻報錯,使用逗号即可拼接

return

except:

pass

def main():

# 如果沒有輸出參數就會輸出幫助資訊

parser = OptionParser("Usage program -i -n -p ")

parser.add_option("-i", '--host', type="string",dest="tgtIP",help="specify target host or website")

parser.add_option("-n","--network", type="string",dest="tgtNetwork",help="specify target Network")

parser.add_option("-f", "--addressfile", type="string", dest="tgtFile", help="specify target addressfile")

parser.add_option("-p","--port", type="string",dest="tgtPorts",help="specify target port separated by comma")

options,args = parser.parse_args()# 執行個體化使用者輸入的參數

tgtIP = options.tgtIP

tgtNetwork = options.tgtNetwork # 網段

tgtFile = options.tgtFile

tgtPorts = options.tgtPorts

tgtPorts = tgtPorts.split(",") # 将使用者輸入的多個端口以逗号分割生成清單

if tgtPorts is None or tgtNetwork is None and tgtIP is None and tgtFile is None :# 判斷使用者是否輸入參數

print(parser.usage)# 如果沒有輸入參數則輸出幫助資訊,然後退出程式

exit(0)

if tgtIP:# 輸入單個ip位址時的操作

for p in tgtPorts:

port = int(p)

t = Thread(target=scan,args=(tgtIP,port))

t.start()

if tgtNetwork:# 輸入整個網段時的操作

prefix = tgtNetwork.split(".")[0] + "." + tgtNetwork.split(".")[1] + "." + tgtNetwork.split(".")[2] + "."# 将使用者輸入的網段提取提取前三位當作字首

for i in range(1,255):

ip = prefix + str(i)# 和字首結合形成網段内所有的位址

for p in tgtPorts:

port = int(p)

t = Thread(target=scan, args=(ip,port))

t.start()

if tgtFile:# 如果時位址檔案則進行的操作

if not os.path.exists(tgtFile):# 判斷檔案是否存在

print("File not found")

sys.exit()

with open(tgtFile,"r") as f:# 讀取位址檔案

for i in f.readlines():

ip = i.strip()# 讀取使用者位址檔案的位址,并去點換行空格

for p in tgtPorts:

port = p.strip()

port = int(port)

t = Thread(target=scan,args=(ip,port))

t.start()# 多線程掃描

if __name__ == '__main__':

main()

運作效果

mapperscan掃描多個包_掃描器篇(八)之python+scapy構造TCP協定包掃描主機端口