一、端口掃描原理
?? 連接網(wǎng)絡(luò)設(shè)備時(shí),一般都會(huì)在網(wǎng)絡(luò)設(shè)備端選取0-65535之間的一個(gè)端口進(jìn)行連接,端口掃描是指:檢查網(wǎng)絡(luò)設(shè)備上0-65535號(hào)端口哪些端口是開(kāi)啟狀態(tài)。
TCP端口掃描
??TCP端口掃描過(guò)程如下:
?? 1、掃描端向目標(biāo)端發(fā)送SYN請(qǐng)求建立連接
?? 2、目標(biāo)端收到請(qǐng)求后,回復(fù)ACK同意連接并同意發(fā)送SYN請(qǐng)求建立連接
?? 3、掃描端收到后,以此來(lái)判斷端口是否存活
UDP端口掃描
??UDP掃描發(fā)送空的(沒(méi)有數(shù)據(jù))UDP報(bào)頭到每個(gè)目標(biāo)端口。 如果返回ICMP端口不可到達(dá)錯(cuò)誤(類(lèi)型3,代碼3), 該端口是closed(關(guān)閉的)。 其它ICMP不可到達(dá)錯(cuò)誤(類(lèi)型3, 代碼1,2,9,10,或者13)表明該端口是filtered(被過(guò)濾的)。 偶爾地,某服務(wù)會(huì)響應(yīng)一個(gè)UDP報(bào)文,證明該端口是open(開(kāi)放的)。
二、Python實(shí)現(xiàn)
2.1 Python腳本
??以下python腳本通過(guò)Scapy實(shí)現(xiàn)網(wǎng)絡(luò)主機(jī)發(fā)現(xiàn)、主機(jī)TCP端口掃描與主機(jī)UDP端口掃描
#!/usr/bin/python3.4
# -*- coding=utf-8 -*-
from kamene.all import *
import ipaddress
def host_scan(net):
net = ipaddress.ip_network(net)
ip_list = []
for ip in net.hosts(): # 迭代可用的主機(jī)地址
id_no = random.randint(1, 65535)
pkt = IP(dst=str(ip))/ICMP(id=id_no,seq=1)
#print(pkt.summary())
result_raw=sr1(pkt,timeout=0.2, verbose=False)
if result_raw == None:
print(str(ip)+"不在線(xiàn)")
elif result_raw != None:
ip_list.append(str(ip))# ip默認(rèn)類(lèi)型未IPv4adress,需轉(zhuǎn)換為str類(lèi)型
print(str(ip)+"在線(xiàn)")
print("在線(xiàn)主機(jī)如下:\n%s"%ip_list)
def syn_scan_final(dstip,lport,hport):
#發(fā)送SYN包,并且等待回應(yīng)##############目的端口可以為元組(lport,hport)##flag為SYN(S)#########
port_list = []
for p in range(int(lport), int(hport) + 1):
source_port = random.randint(1024, 65535)
pkt = IP(dst=dstip)/TCP(sport=source_port, dport=p,flags="S")
print(pkt.summary())
result_raw = sr1(pkt, verbose=False, timeout=0.3) # 發(fā)送三層包,等待接收一個(gè)回應(yīng)
if result_raw != None:
if result_raw.getlayer(TCP).fields["flags"] == 18:
port_list.append(str(p))
print("TCP " + str(p) + "端口可達(dá),open")
elif result_raw == None:
print("TCP " + str(p) + "端口無(wú)響應(yīng)")
print("%s 開(kāi)放的TCP端口為:%s\n" % (dstip,port_list))
def udp_port_scan(dstip,lport,hport):
port_list=[]
for p in range(int(lport),int(hport)+1):
source_port = random.randint(1024, 65535)
pkt=IP(dst=dstip)/UDP(sport=source_port,dport=p)
print(pkt.summary())
result_raw=sr1(pkt,verbose = False,timeout=0.3)#發(fā)送三層包,等待接收一個(gè)回應(yīng)
if result_raw != None:
if result_raw.haslayer(ICMP):
icmpfields=result_raw.getlayer(ICMP).fields
if icmpfields["type"] == 3 and icmpfields["code"] == 3:
print("UDP "+str(p)+"端口不可達(dá),close")
else:
print("UDP " + str(p) + "端口被過(guò)濾,filtered")
if result_raw.haslayer(UDP):
print("UDP " + str(p) + "端口open")
port_list.append(str(p))
elif result_raw == None:
print("UDP "+str(p)+"端口無(wú)響應(yīng)")
print("%s 開(kāi)放的UDP端口為:%s\n" % (dstip, port_list))
if __name__ == '__main__':
while True:
print('''
-----選擇功能-----
1.主機(jī)掃描
2.TCP端口掃描
3.UDP端口掃描
q.退出
''')
choice = input("選擇功能>>>")
try:
if choice == '1':
net = input("Net/mask>>>")
host_scan(net)
elif choice == '2':
host = input('請(qǐng)你輸入掃描主機(jī)的IP地址: ')
port_low =input('請(qǐng)你輸入掃描端口的最低端口號(hào): ')
port_high = input('請(qǐng)你輸入掃描端口的最高端口號(hào): ')
syn_scan_final(host,port_low,port_high)
elif choice == '3':
host = input('請(qǐng)你輸入掃描主機(jī)的IP地址: ')
port_low = input('請(qǐng)你輸入掃描端口的最低端口號(hào): ')
port_high = input('請(qǐng)你輸入掃描端口的最高端口號(hào): ')
udp_port_scan(host, port_low, port_high)
elif choice == 'q':
break
else:
print("輸入錯(cuò)誤?。?)
except Exception:
pass
2.2 主機(jī)掃描
??執(zhí)行腳本選擇主機(jī)掃描,輸入需要掃描的網(wǎng)段后,會(huì)發(fā)送ICMP包來(lái)探測(cè)主機(jī)是否在線(xiàn)。


2.3 TCP端口掃描
??執(zhí)行腳本選擇TCP端口掃描,輸入目標(biāo)IP,與端口范圍后開(kāi)始進(jìn)行探測(cè)。


2.4 UDP端口掃描
??執(zhí)行腳本選擇UDP端口掃描,輸入目標(biāo)IP,與端口范圍后開(kāi)始進(jìn)行探測(cè)。

