端口扫描工具-python


端口扫描工具

TCP模式-socket

原理

目标主机的一个端口如果是监听状态(LISTENING或者LINSTEN),那么当我connect目标主机时就能成功,否则说明端口是关闭的。
优点: 编程简单,是需要一个API connect(),比较可靠,因为TCP是可靠协议,当丢包的时候,会重传SYN帧。
缺点: 正因为TCP的可靠性,所以当端口不存在的时候,源主机会不断尝试发SYN帧企图得到ack的应答,多次尝试后才会放弃,因此造成了扫描的时间较长。并且,connect的扫描方式可能较容易被目标主机发现。

主要是一个编程思路,代码很简单

1、定义portscan函数,创建socke对象,进行TCP端口扫描
2、启动多线程运行PortScan函数
3、记录并输出扫描结果与时间

主要还是利用了三次握手来判断目标端口是否开启:

image-20220704220447269

创建端口扫描函数

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))

image-20220704221050939

可以看到非常的慢,看下用时,50个端口用了近100秒

image-20220704221302606

加入多线程

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()

image-20220704221448827

可以看到多线程快了很多,只用了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()

image-20220704222304548

image-20220704222718402

SYN扫描

原理

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) + ' 秒')

image-20220707163857256

原创文章,作者:wdmbts,如若转载,请注明出处:https://blog.ytso.com/272728.html

(0)
上一篇 2022年7月9日
下一篇 2022年7月9日

相关推荐

发表回复

登录后才能评论