目标主机的一个端口如果是监听状态(LISTENING或者LINSTEN),那么当我connect目标主机时就能成功,否则说明端口是关闭的。 优点: 编程简单,是需要一个API connect(),比较可靠,因为TCP是可靠协议,当丢包的时候,会重传SYN帧。 缺点: 正因为TCP的可靠性,所以当端口不存在的时候,源主机会不断尝试发SYN帧企图得到ack的应答,多次尝试后才会放弃,因此造成了扫描的时间较长。并且,connect的扫描方式可能较容易被目标主机发现。
主要是一个编程思路,代码很简单
1、定义portscan函数,创建socke对象,进行TCP端口扫描 2、启动多线程运行PortScan函数 3、记录并输出扫描结果与时间
主要还是利用了三次握手来判断目标端口是否开启:
def portscan(target,port): # 定义portscan函数,进行TCP端口扫描 try: client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象 client.connect((target,port)) #建立socket连接,判断端口是否开放 print("[*] %s:%d端口开放" % (target,port)) client.close() except: pass #捕获异常,避免socket连接建立失败造成程序退出
直接测试调用函数,简单完善一次,测试100个端口:
import socket import time def portscan(target,port): # 定义portscan函数,进行TCP端口扫描 try: client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象 client.connect((target,port)) #建立socket连接,判断端口是否开放 print("[*] %s:%d端口开放" % (target,port)) client.close() except: pass #捕获异常,避免socket连接建立失败造成程序退出 start_time = time.time() for i in range(0,1001,1): print('正在进行第{}个端口'.format(i)) portscan('127.0.0.1',i) print('end') end_time = time.time() print("[*] All done in %.2f s" % (end_time - start_time))
可以看到非常的慢,看下用时,50个端口用了近100秒
for port in range(1,9999): # 启动多线程运行PortScan函数 t = Thread(target=portscan,args=(target,port)) #创建线程对象 t.start() #开始线程
扫描1-65535
import socket #创建TCP连接 from threading import Thread #多线程模块,进行多线程扫描 import time #时间模块,记录扫描所需时间 def main(): target = input("IP:") start_time = time.time() s_time = time.ctime() print("[*] Start port scan at %s" % s_time) for port in range(1,65536): #定义扫描的端口范围 # 2、启动多线程运行PortScan函数 t = Thread(target=portscan, args=(target, port)) # 创建线程对象 t.start() # 开始线程 end_time = time.time() print("[*] All done in %.2f s" % (end_time - start_time)) def portscan(target,port): # 定义portscan函数,进行TCP端口扫描 try: client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象 client.connect((target,port)) #建立socket连接,判断端口是否开放 print("[*] %s:%d端口开放" % (target,port)) client.close() except: pass #捕获异常,避免socket连接建立失败造成程序退出 if __name__ == '__main__': main()
可以看到多线程快了很多,只用了9秒钟
import socket #创建TCP连接 from threading import Thread #多线程模块,进行多线程扫描 import time #时间模块,记录扫描所需时间 def main(): target = input("IP:") start_time = time.time() s_time = time.ctime() port_tmp = int(input("选择全端口(数字1)还是指定端口(数字2):")) if port_tmp==1: print("[*] Start port scan at %s" % s_time) for port in range(1,65536): #定义扫描的端口范围 # 2、启动多线程运行PortScan函数 t = Thread(target=portscan, args=(target, port)) # 创建线程对象 t.start() # 开始线程 elif port_tmp==2: port_tmp2 = input("请输入端口列表,以逗号分割,列如80,8080,7001:") prot_list=port_tmp2.split(',') print(prot_list) for port_i in prot_list: t = Thread(target=portscan, args=(target, int(port_i))) # 创建线程对象 t.start() # 开始线程 end_time = time.time() print("[*] All done in %.2f s" % (end_time - start_time)) def portscan(target,port): # 定义portscan函数,进行TCP端口扫描 try: client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象 client.connect((target,port)) #建立socket连接,判断端口是否开放 print("[*] %s:%d端口开放" % (target,port)) client.close() except: pass #捕获异常,避免socket连接建立失败造成程序退出 if __name__ == '__main__': main()
TCP SYN 扫描也就是半开扫描(半开式扫描),这种扫描方式与全连接扫描类似,但客户端不会和服务端建立完整的连接。 扫描过程为:客户端会发送一个带有 SYN 标识和端口号的 TCP 数据包给服务器,如果服务器这个端口是开放的,则会接受这个连接并返回一个带有 SYN 和 ACK 标识的数据包给客户端,随后客户端会返回带有 RST 标识的数据包,而不是像全连接扫描一样返回一个带有 ACK和 RST 标识的数据包,这样就不会与服务端建立完整的连接了。如果目标端口处于关闭状态,则服务端会返回一个 RST 标识的数据包。
import threading,time import sys from scapy.all import * from scapy.layers.inet import IP, TCP, ICMP def get_ip(): '''从命令行参数中获取 IP''' try: parameter = sys.argv ip = parameter[1] print('The IP you test is : ', end = '') font.print_YELLOW(ip) except Exception as e: print(e) return ip def port_scan(port): '''扫描端口''' try: packet = IP(dst=ip)/TCP(dport=port,flags='S') # 构造一个 flags 的值为 S 的报文 send = sr1(packet,timeout=2,verbose=0) if send.haslayer('TCP'): if send['TCP'].flags == 'SA': # 判断目标主机是否返回 SYN+ACK send_1 = sr1(IP(dst=ip)/TCP(dport=port,flags='R'),timeout=2,verbose=0) # 只向目标主机发送 RST font.print_GREEN('[+] %d is open' % port) elif send['TCP'].flags == 'RA': pass except: pass def main(): packet_ping = IP(dst=ip)/ICMP() # 在扫描端口之前先用 ICMP 协议探测一下主机是否存活 ping = sr1(packet_ping,timeout=2,verbose=0) if ping is not None: for p in range(1,65535): # 默认扫描1-1000的端口,可以手动修改这里的端口范围 t = threading.Thread(target=port_scan,args=(p,)) t.start() elif ping is None: font.print_RED('该主机处于关闭状态或本机被该主机过滤,无法对其使用 ping 探测') if __name__ == '__main__': ip = get_ip() start_time = time.time() main() end_time = time.time() print('[time cost] : ' + str(end_time-start_time) + ' 秒')