手把手教你写一个图形化的端口扫描工具

前言

关于学习群

由于我使用masscan进行纯端口扫描的时候,遇到扫描不出结果的情况,我就考虑了自己写一个端口扫描脚本,还挺好用。

image-20240805144645079

库介绍

1、asyncio

asyncio 是 Python 的一个库,用于编写单线程并发代码。使用 asyncio,你可以使用异步函数 (async def) 来编写协程。协程可以被调度执行,执行过程中可以等待其他协程完成,而不必阻塞整个程序的运行。

2、ipaddress

ipaddress 是 Python 的一个标准库模块,主要用于检查和操作 IP 地址。该模块提供了创建、操作和表示 IPv4 和 IPv6 地址及网络的功能。

3、tkinter

Tkinter是Python标准库中的一个模块,专门用于创建图形用户界面(GUI)应用程序。

可以使用nmap扫描,也可以使用该脚本定制自己的图形界面,和其他功能,比如网站目录扫描,本代码仅供参考

import asyncio
import ipaddress


# 异步扫描指定IP和端口的函数
async def scan_port(ip, port, semaphore):
    async with semaphore:  # 使用信号量限制并发数量
        try:
            # 尝试连接到指定的IP和端口,设置超时为3秒
            reader, writer = await asyncio.wait_for(asyncio.open_connection(ip, port), timeout=3)
            print(f"端口 {port} 在 {ip} 开启")  # 如果连接成功,打印端口开启的信息
            writer.close()  # 关闭连接
        except (ConnectionRefusedError, OSError):
            # 如果连接被拒绝或发生其他OS错误,则不执行任何操作
            pass
        except asyncio.TimeoutError:
            # 如果连接超时,则不执行任何操作
            pass

        # 解析IP范围的函数


def parse_ip_range(ip_range):
    if '/' in ip_range:
        # 如果IP范围使用CIDR表示法
        return [str(ip) for ip in ipaddress.ip_network(ip_range).hosts()]  # 返回CIDR范围内的所有IP地址
    elif '-' in ip_range:
        # 如果IP范围使用起始-结束表示法
        start_ip, end_ip = ip_range.split('-')  # 分割起始和结束IP
        start_int = int(ipaddress.IPv4Address(start_ip))  # 将起始IP转换为整数
        end_int = int(ipaddress.IPv4Address(end_ip))  # 将结束IP转换为整数
        return [str(ipaddress.IPv4Address(i)) for i in range(start_int, end_int + 1)]  # 返回范围内的所有IP地址
    else:
        # 如果使用单个IP表示法
        return [ip_range]  # 返回单个IP地址的列表


# 主函数,用于执行端口扫描
async def main(ip_range, ports):
    ips = parse_ip_range(ip_range)  # 解析IP范围

    semaphore = asyncio.Semaphore(500)  # 创建一个信号量,限制并发连接的数量
    tasks = []  # 创建一个任务列表

    # 遍历IP范围和端口范围,为每个IP和端口创建一个扫描任务
    for ip in ips:
        for port in ports:
            task = asyncio.create_task(scan_port(ip, port, semaphore))  # 创建扫描任务
            tasks.append(task)  # 将任务添加到任务列表中

    # 等待所有任务完成,并捕获可能的异常
    try:
        await asyncio.wait(tasks)  # 等待所有任务完成
    except Exception as e:
        print(f"An error occurred: {e}")  # 如果发生错误,打印错误信息


# 程序入口点
if __name__ == "__main__":
    # 设置IP范围和要扫描的端口范围
    ip_range = "192.168.3.155"  # 指定单个IP或IP范围
    target_ports = range(80, 60000)  # 指定要扫描的端口范围
    # 运行主函数,开始端口扫描
    asyncio.run(main(ip_range, target_ports))

执行结果

image-20240805150702536

那么添加一个ui界面呢

image-20240805154953735

多个ip扫描

image-20240805155216447

代码如下:

import asyncio
import ipaddress
import tkinter as tk
from tkinter import scrolledtext


# 异步扫描指定IP和端口的函数
async def scan_port(ip, port, semaphore, result_queue):
    async with semaphore:
        try:
            reader, writer = await asyncio.wait_for(asyncio.open_connection(ip, port), timeout=3)
            await result_queue.put(f"端口 {port} 在 {ip} 开启")
            writer.close()
        except (ConnectionRefusedError, OSError, asyncio.TimeoutError):
            pass


def parse_ip_range(ip_range):
    if '/' in ip_range:
        return [str(ip) for ip in ipaddress.ip_network(ip_range).hosts()]
    elif '-' in ip_range:
        start_ip, end_ip = ip_range.split('-')
        start_int = int(ipaddress.IPv4Address(start_ip))
        end_int = int(ipaddress.IPv4Address(end_ip))
        return [str(ipaddress.IPv4Address(i)) for i in range(start_int, end_int + 1)]
    else:
        return [ip_range]


async def main(ip_range, ports, result_queue):
    ips = parse_ip_range(ip_range)
    semaphore = asyncio.Semaphore(500)
    tasks = []
    for ip in ips:
        for port in ports:
            task = asyncio.create_task(scan_port(ip, port, semaphore, result_queue))
            tasks.append(task)
    await asyncio.wait(tasks)


class PortScannerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("端口扫描器")

        self.ip_label = tk.Label(root, text="IP范围:")
        self.ip_label.grid(row=0, column=0)

        self.ip_entry = tk.Entry(root)
        self.ip_entry.grid(row=0, column=1)

        self.port_label = tk.Label(root, text="端口范围:")
        self.port_label.grid(row=1, column=0)

        self.port_entry = tk.Entry(root)
        self.port_entry.grid(row=1, column=1)

        self.start_button = tk.Button(root, text="开始扫描", command=self.start_scan)
        self.start_button.grid(row=2, column=0, columnspan=2)

        self.result_text = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=40, height=10)
        self.result_text.grid(row=3, column=0, columnspan=2)

        self.result_queue = asyncio.Queue()

    def start_scan(self):
        ip_range = self.ip_entry.get()
        port_range = self.port_entry.get()

        if '-' in port_range:
            start_port, end_port = map(int, port_range.split('-'))
            ports = range(start_port, end_port + 1)
        else:
            ports = [int(port_range)]

        asyncio.run(main(ip_range, ports, self.result_queue))
        self.process_results()

    def process_results(self):
        while not self.result_queue.empty():
            result = self.result_queue.get_nowait()
            self.result_text.insert(tk.END, result + "\n")
            self.result_text.yview(tk.END)


if __name__ == "__main__":
    root = tk.Tk()
    app = PortScannerApp(root)
    root.mainloop()

开始打包

pip install pyinstaller  
pyinstaller your_script.py

开始扫描

image-20240805160052094

当然使用nmap的-sS参数syn扫描,速度也比较快,但是也得指定端口,不指定端口的话呢就像这样,使用默认的1-10000范围内的端口号(大致范围)

image-20240805145421710

指定范围就可以使用了

image-20240805145530386

后期我会把他写成一个多功能的工具,大家敬请期待

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小羽网安

公众号【小羽网安】

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值