1.1、网络端口扫描的定义
网络端口扫描是一种探测远程或本地主机安全弱点的方法。使用网络端口扫描,可以对目标主机的端口进行扫描,探察到各个端口的服务信息以及各个端口所具有的版本号等,进而间接或直观的了解到目标主机所存在的安全问题。
1.2、端口扫描技术的原理
1、向目标主机的TCP/IP服务端口发送探测数据包,记录目标主机的响应。
2、分析响应,判断服务端口是打开还是关闭,得知端口提供的服务或信息。
端口扫描也可以通过捕获本地主机或服务器的流入流出IP数据包对本地主机的运行情况进行监视,查找内在弱点。
1.3、端口扫描技术的发展
如今各种端口扫描的软件层出不穷,大多利用向规定范围内的常用端口逐个发送并返还数据包的方式对端口进行探测,进而发现端口的运行状态,然后根据扫描结果对网络的数据进行分析,来获得目标机器的很多有用信息,有效的理解和使用端口扫描的原理和技术,能够为网络环境带来重要的防御作用。
编写一个主机系统扫描程序,可以获取主机的网络信息,系统信息,端口信息。
创建一个新线程,用socket网络编程连接目标主机,判断服务器端口是否打开,如果服务端口打开,输出端口号,否则不输出,因为它端口未开放,打印出来没有意义。
进入扫描端口程序,第一步输入主机的IP地址,第二步输入所要扫描端口的范围,点击开始扫描,下面就会出现开放的端口号,点击暂停扫描就会停止,你再点击开始扫描会继续扫描,直到把这个范围内的所有端口扫描完成。
from tkinter import *
import socket, re
import threading
import time
import queue
import tkinter.messagebox as msgbox
from tkinter.filedialog import askopenfilename
class MyGui():
#初始化参数
def __init__(self, init_window_name):
self.init_window_name = init_window_name
def set_init_window(self):
self.k = 0
#初始化窗口
self.init_window_name.title("主机端口扫描器")
self.window_center(400, 520)
#固定窗口,禁止放大缩小
self.init_window_name.resizable(0,0)
# 定义区域,把全局分为上中下部分
self.frame_top = Frame(self.init_window_name, width=400, height=200)
self.frame_center = Frame(self.init_window_name, width=400, height=300)
self.frame_foot = Frame(self.init_window_name, width=400, height=10)
self.frame_top.grid(row=0, column=0)
self.frame_center.grid(row=1, column=0)
self.frame_foot.grid(row=2, column=0, pady="20")
# 上部分布局
self.ip_lb_top = Label(self.frame_top, text="IP地址", font="楷体")
self.port_lb_top = Label(self.frame_top, text="端口范围", font="楷体")
#将要输入的ip和端口范围存入
self.ip_input = StringVar()
self.port_input = StringVar()
self.ip_input.set('例如:127.0.0.1')
self.port_input.set('例如:1-65535')
self.ip_content = Entry(self.frame_top, textvariable=self.ip_input, font="楷体")
self.port_content = Entry(self.frame_top, textvariable=self.port_input, font="楷体")
self.PortScan = Button(self.frame_top, text="开始扫描", command=self.runing, font="楷体")
self.StopScan = Button(self.frame_top, text="停止扫描", command=self.stop, font="楷体",fg='red')
#用坐标定位,设置布局
self.ip_lb_top.place(x=30, y=20)
self.ip_content.place(x=105, y=20)
self.port_lb_top.place(x=13, y=60)
self.port_content.place(x=105, y=60)
self.PortScan.place(x=32, y=110)
self.StopScan.place(x=190, y=110)
# 中间部分布局
self.porttext = Text(self.frame_center, width=41, height=18,font="楷体",fg='blue')
self.scroll = Scrollbar(self.frame_center)
self.scroll.pack(side=RIGHT, fill=Y)
self.porttext.pack(side=RIGHT, fill=Y)
self.scroll.config(command=self.porttext.yview)
self.porttext.config(yscrollcommand=self.scroll.set)
# 下部分布局
# 窗口居中
def window_center(self, width, height):
screenwidth = self.init_window_name.winfo_screenwidth()
screenheight = self.init_window_name.winfo_screenheight()
size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
self.init_window_name.geometry(size)
# 获取当前时间
def get_current_time(self):
current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
return current_time
#进程对象
class MyThread(threading.Thread):
def __init__(self, func, *args):
super().__init__()
self.func = func
self.args = args
self.setDaemon(True)
self.start() # 在这里开始
def run(self):
self.func(*self.args)
def intofile(self):
filenameReading = askopenfilename()
infile = open(filenameReading, 'r')
self.porttext.delete(1.0, END)
self.porttext.insert(END, infile.read())
infile.close()
def stop(self):
if self.k == 0:
msgbox.showinfo(title='提示', message='扫描未开始 或 已停止')
else:
self.k = 0
self.porttext.insert(END, '\n' + '扫描已暂停......')
#错误提示
def runing(self):
self.k = 1
self.porttext.delete(1.0, END)
if re.match(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", self.ip_content.get()):
self.ip = self.ip_content.get()
else:
msgbox.showerror(title="Error", message="ip格式错误或不合法,请重新输入")
return
if re.match(r"^(?:[0-9]{1,5}-){1}[0-9]{1,5}$", self.port_content.get()):
ports = self.port_content.get()
else:
msgbox.showerror(title="Error", message="端口范围·格式错误,格式为:xxx-xxx")
return
ports = ports.split('-')
startport = ports[0]
endport = ports[1]
p=0
#打印当前时间,扫描的主机ip和端口范围
self.porttext.insert(END, "当前时间为: "+self.get_current_time()+"\nIP地址:"+self.ip+"\n端口范围:"+self.port_content.get()+"\n\n扫描结果\n\n")
self.portslist = list(range(int(startport), int(endport) + 1))
port_queue = queue.Queue()
for port in self.portslist:
port_queue.put(port)
p+=1
for i in range(0, 3000):
self.MyThread(self.scan, port_queue)
if p==int(endport):
self.porttext.insert(END, '耗时:'+'\n')
def scan(self, port_queue):
while self.k == 1:
if port_queue.empty():
break
port = port_queue.get()
timeout = 3
s = socket.socket()
s.settimeout(timeout)
#打印开放的端口号
try:
s.connect((self.ip, port))
string = " 开放的端口:" + str(port) + "\n"
self.porttext.insert(END, string)
self.porttext.see(END)
except Exception as e:
pass
finally:
#关闭套接字
s.close()
if __name__ == "__main__":
pygui=Tk()
init_window = MyGui(pygui)
init_window.set_init_window()
pygui.mainloop()
运行程序,点击运行,会进入主机端口扫描器的主界面
输入要扫码的IP地址和端口范围
本次扫码是我的本机,端口范围:1-4000,结果如下:
其中第一个开放的端口:135,开放服务为用于远程的打开对方的telnet服务 ,用于启动与远程计算机的 RPC 连接。
第二个开放的端口:443,开放的服务为HTTPS,提供加密和通过安全端口传输的另一种HTTP。
第三个开放的端口:445,开放的服务为TCP端口,主要提供局域网中的文件或打印机共享服务。
最后一个开放端口:3306,开放的服务为MySql数据库系统服务。
1、该程序扫描结束,没有一个提示,不知道具体什么时间结束,但可以通过扫描出的端口号的大小来判断大概位置。
2、本机开放端口:135,很容易被人入侵电脑,带来损失。
3、像20,21,80,443,3306这样常用的开放端口。