def vuln_ShowPlugins(self): self.widget = Ui_Form() self.dialog = QtWidgets.QDialog(self) self.widget.setupUi(self.dialog) self.dialog.setFixedSize(self.dialog.width(), self.dialog.height()) # 设置宽高不可变 #设置查看插件表格属性 列宽度 self.widget.show_Plugins.setColumnWidth(0, 100) self.widget.show_Plugins.setColumnWidth(1, 350) self.widget.show_Plugins.setColumnWidth(2, 350) self.widget.show_Plugins.setColumnWidth(3, 383) self.widget.show_Plugins.setColumnWidth(4, 218) conn2 = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn2.cursor() self.Ui.textEdit_log.append( "[%s]Info:正在查询数据..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) # 列出所有数据 sql = "SELECT * from POC" cursor.execute(sql) values = cursor.fetchall() self.Ui.textEdit_log.append( "[%s]Success:数据查询成功!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) i = 0 self.widget.show_Plugins.setRowCount(len(values)) sql2 = "SELECT distinct cmsname from POC" cursor.execute(sql2) cms_name_data = cursor.fetchall() #添加查询列表 for cms_name in cms_name_data: self.widget.show_Plugins_comboBox.addItem(cms_name[0]) # print(cms_name[0]) for single in values: vuln_name = QTableWidgetItem(str(single[1])) vuln_url = QTableWidgetItem(str(single[3])) vuln_payload = QTableWidgetItem(str(single[4])) vuln_result = QTableWidgetItem(str(single[5])) vuln_motheds = QTableWidgetItem(str(single[2])) self.widget.show_Plugins.setItem(i, 0, vuln_name) self.widget.show_Plugins.setItem(i, 1, vuln_url) self.widget.show_Plugins.setItem(i, 2, vuln_payload) self.widget.show_Plugins.setItem(i, 3, vuln_result) self.widget.show_Plugins.setItem(i, 4, vuln_motheds) i = i + 1 conn2.close() self.dialog.show() self.widget.show_Plugins_comboBox.currentIndexChanged.connect( self.show_plugins_go) # comboBox事件选中触发刷新
def vuln_ShowPlugins(self): self.widget = Ui_Form() self.dialog = QtWidgets.QDialog(self) self.widget.setupUi(self.dialog) self.dialog.setFixedSize(self.dialog.width(), self.dialog.height()) # 设置宽高不可变 # 设置查看插件表格属性 列宽度 self.widget.show_Plugins.setColumnWidth(0, 120) self.widget.show_Plugins.setColumnWidth(1, 200) self.widget.show_Plugins.setColumnWidth(2, 320) self.widget.show_Plugins.setColumnWidth(3, 360) self.widget.show_Plugins.setColumnWidth(4, 218) self.widget.show_Plugins.setColumnWidth(5, 218) sql = "SELECT * from POC" values = self.sql_search(sql) i = 0 self.widget.show_Plugins.setRowCount(len(values)) sql2 = "SELECT distinct cmsname from POC" cms_name_data = self.sql_search(sql2) # 添加查询列表 for cms_name in cms_name_data: self.widget.show_Plugins_comboBox.addItem(cms_name[0]) # print(cms_name[0]) for single in values: # print(single) cms_name = QTableWidgetItem(str(single[1])) poc_file_name = QTableWidgetItem(str(single[2])) exp_file_name = QTableWidgetItem(str(single[3])) poc_name = QTableWidgetItem(str(single[4])) poc_referer = QTableWidgetItem(str(single[5])) poc_descr = QTableWidgetItem(str(single[6])) self.widget.show_Plugins.setItem(i, 0, cms_name) self.widget.show_Plugins.setItem(i, 1, poc_name) self.widget.show_Plugins.setItem(i, 2, poc_referer) self.widget.show_Plugins.setItem(i, 3, poc_descr) self.widget.show_Plugins.setItem(i, 4, poc_file_name) self.widget.show_Plugins.setItem(i, 5, exp_file_name) i = i + 1 self.dialog.show() self.widget.show_Plugins_comboBox.currentIndexChanged.connect( self.show_plugins_go) # comboBox事件选中触发刷新
class MainWindows(QtWidgets.QMainWindow, Ui_MainWindow): # 主窗口 def __init__(self, parent=None): super(MainWindows, self).__init__(parent) # self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) #去掉标题栏 self.Ui = Ui_MainWindow() self.Ui.setupUi(self) self.setWindowIcon(QtGui.QIcon('main.ico')) # self.setFixedSize(self.width(), self.height()) # 设置宽高不可变 # self.Ui.exit.clicked.connect(QtCore.QCoreApplication.instance().quit) #退出 self.Ui.action_vuln_start.triggered.connect(self.vuln_Start) # 开始扫描 self.Ui.action_vuln_import.triggered.connect( self.vuln_import_file) # 导入文件列表 self.Ui.pushButton_vuln_file.clicked.connect( self.vuln_import_file) # 导入地址 self.Ui.action_vuln_export.triggered.connect( self.vuln_export_file) # 导出扫描结果 self.Ui.pushButton_vuln_export.clicked.connect( self.vuln_export_file) # 导出结果 self.Ui.action_vuln_reload.triggered.connect( self.vuln_reload_Plugins) # 重新加载插件 self.Ui.action_vuln_showplubins.triggered.connect( self.vuln_ShowPlugins) # 查看插件 self.Ui.pushButton_vuln_showplugins.clicked.connect( self.vuln_ShowPlugins) # 查看插件 self.Ui.pushButton_vuln_start.clicked.connect(self.vuln_Start) # 开始扫描\ self.Ui.action_about.triggered.connect(self.about) # 关于 self.Ui.action_update.triggered.connect(self.version_update) # 更新 self.Ui.action_ideas.triggered.connect(self.ideas) # 意见反馈 self.Ui.pushButton_vuln_all.clicked.connect(self.vuln_all) # 全选 self.Ui.pushButton_vuln_noall.clicked.connect(self.vuln_noall) # 反选 # 虚拟终端右键菜单 self.Ui.tableWidget_vuln.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.Ui.tableWidget_vuln.customContextMenuRequested['QPoint'].connect( self.createtableWidget_vulnMenu) self.timer = QTimer() # 设定一个定时器用来显示时间 self.timer.timeout.connect(self.showtime) self.timer.start() self.loadplugins() self.url_list = [] self.stop_flag = 0 # 设置漏洞扫描表格属性 列宽度 # self.Ui.tableWidget_vuln.setColumnWidth(0, 222) # self.Ui.tableWidget_vuln.setColumnWidth(1, 325) # self.Ui.tableWidget_vuln.setColumnWidth(2, 370) # self.Ui.tableWidget_vuln.setColumnWidth(3, 91) def createtableWidget_vulnMenu(self): ''''' 创建右键菜单 ''' # 必须将ContextMenuPolicy设置为Qt.CustomContextMenu # 否则无法使用customContextMenuRequested信号 self.Ui.tableWidget_vuln.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.Ui.tableWidget_vuln.customContextMenuRequested.connect( self.showContextMenu) # 创建QMenu self.contextMenu = QtWidgets.QMenu(self) self.copy_textEdit = self.contextMenu.addAction(u'复制') self.clear_textEdit = self.contextMenu.addAction(u'清空') # 将动作与处理函数相关联 # 这里为了简单,将所有action与同一个处理函数相关联, # 当然也可以将他们分别与不同函数关联,实现不同的功能 self.copy_textEdit.triggered.connect(self.Copy_tableWidget_vuln) self.clear_textEdit.triggered.connect(self.Clear_tableWidget_vuln) # 右键点击时调用的函数,移动鼠标位置 def showContextMenu(self, pos): # 菜单显示前,将它移动到鼠标点击的位置 self.contextMenu.move(QtGui.QCursor.pos()) self.contextMenu.show() def Copy_tableWidget_vuln(self): try: data = self.Ui.tableWidget_vuln.selectedItems()[0].text() # print(data) # 访问剪切板,存入值 wincld.OpenClipboard() wincld.EmptyClipboard() wincld.SetClipboardData(win32con.CF_UNICODETEXT, data) wincld.CloseClipboard() except: pass def Clear_tableWidget_vuln(self): for i in range(0, self.Ui.tableWidget_vuln.rowCount()): # 循环行 self.Ui.tableWidget_vuln.removeRow(0) # 显示时间 def showtime(self): datetime = QDateTime.currentDateTime() text = datetime.toString("yyyy-MM-dd hh:mm:ss") self.setWindowTitle("FrameScan V1.2.2 测试版 20200508 %s" % text) # 得到选中的方法 def get_methods(self): poc_methods = [] # 保存的所有方法。 item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if not item.value().parent(): # 判断有没有父节点 pass else: # 输出所有子节点 if item.value().checkState(0) == QtCore.Qt.Checked: # 参考网上的方法,判断有无父母结点后再分别操作的那个,实在找不到更直接的 poc_methods.append(item.value().text(0)) item = item.__iadd__(1) return poc_methods # 开始扫描 def vuln_Start(self): threadnum = int(self.Ui.threadsnum.currentText()) portQueue = queue.Queue() # 待检测端口队列,会在《Python常用操作》一文中更新用法 self.Ui.textEdit_log.clear() target = [] # 存放扫描的URL if self.url_list: target = self.url_list else: url = self.Ui.lineEdit_vuln_url.text() if 'http://' in url or 'https://' in url: target.append(url.strip()) if not target: self.Ui.textEdit_log.append( "[%s]Info:未获取到URL地址。" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return 0 poc_methods = self.get_methods() # print(poc_methods) if not poc_methods: self.Ui.textEdit_log.append( "[%s]Info:未选择插件。" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return 0 else: self.Ui.textEdit_log.append("[%s]Info:共加载%s个插件。" % ((time.strftime( '%H:%M:%S', time.localtime(time.time()))), len(poc_methods))) self.Ui.textEdit_log.append( "[%s]Info:正在创建队列..." % ((time.strftime('%H:%M:%S', time.localtime(time.time()))))) for u in target: for p in poc_methods: portQueue.put(u + '$$$' + p) self.Ui.textEdit_log.append( "[%s]Start:扫描开始..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) # 限制线程数小于队列大小 if threadnum > portQueue.qsize(): threadnum = portQueue.qsize() # print(threadnum) self.Ui.action_vuln_import.setEnabled(False) self.Ui.pushButton_vuln_file.setEnabled(False) self.Ui.action_vuln_start.setEnabled(False) self.Ui.pushButton_vuln_start.setEnabled(False) for i in range(threadnum): thread = threading.Thread(target=self.vuln_scan, args=(portQueue, threadnum)) # thread.setDaemon(True) # 设置为后台线程,这里默认是False,设置为True之后则主线程不用等待子线程 thread.start() # 调用脚本 def vuln_scan(self, portQueue, threadnum): while 1: if portQueue.empty(): # 队列空就结束 self.stop_flag = self.stop_flag + 1 # print(self.stop_flag,threadnum) if self.stop_flag == threadnum: self.Ui.action_vuln_import.setEnabled(True) self.Ui.pushButton_vuln_file.setEnabled(True) self.Ui.action_vuln_start.setEnabled(True) self.Ui.pushButton_vuln_start.setEnabled(True) self.stop_flag = 0 break all = portQueue.get() # 从队列中取出 url = all.split('$$$')[0] poc = all.split('$$$')[1] try: result = eval(poc)(url).run() # print(result) result_url = url.replace("http://", "").replace("https://", "") # print(result) # print(result_url) self.Ui.textEdit_log.append( "[%s]Info:%s----%s----%s。" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), result_url, result[0], result[2])) if result[2] != '不存在' and result[2] != '': row = self.Ui.tableWidget_vuln.rowCount() # 获取行数 self.Ui.tableWidget_vuln.setRowCount(row + 1) urlItem = QTableWidgetItem(result_url) nameItem = QTableWidgetItem(result[0]) payloadItem = QTableWidgetItem(result[1]) resultItem = QTableWidgetItem(result[2]) self.Ui.tableWidget_vuln.setItem(row, 0, urlItem) self.Ui.tableWidget_vuln.setItem(row, 1, nameItem) self.Ui.tableWidget_vuln.setItem(row, 3, payloadItem) self.Ui.tableWidget_vuln.setItem(row, 2, resultItem) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:%s脚本执行错误!\n[Exception]:\n%s" % ((time.strftime( '%H:%M:%S', time.localtime(time.time()))), poc, e)) # 初始化加载插件 def loadplugins(self): if os.path.isfile(DB_NAME): conn = sqlite3.connect(DB_NAME) else: box = QtWidgets.QMessageBox() box.warning(self, "提示", "数据文件不存在,正在重新加载数据库!") self.vuln_reload_Plugins() return 0 try: # 创建一个游标 curson cursor = conn.cursor() # 列出所有数据 sql = "SELECT cmsname,pocmethods from POC" cursor.execute(sql) values = cursor.fetchall() except Exception as e: box = QtWidgets.QMessageBox() box.warning(self, "提示", "数据文件错误:\n%s" % e) return 0 # 将查询的值组合为字典包含列表的形式 cms_name = {} for cms in values: cms_name[cms[0]] = [] for cms in values: if cms[0] in cms_name.keys(): cms_name[cms[0]].append(cms[1]) for cms in cms_name: # 设置root为self.treeWidget_Plugins的子树,故root是根节点 root = QTreeWidgetItem(self.Ui.treeWidget_Plugins) root.setText(0, cms) # 设置根节点的名称 root.setCheckState(0, Qt.Unchecked) # 开启复选框 for poc in cms_name[cms]: # 为root节点设置子结点 child1 = QTreeWidgetItem(root) child1.setText(0, poc) child1.setCheckState(0, Qt.Unchecked) self.Ui.treeWidget_Plugins.itemChanged.connect(self.handleChanged) self.Ui.textEdit_log.append( "[%s]Success:插件加载完成,共%s个。" % (time.strftime( '%H:%M:%S', time.localtime(time.time())), len(values))) # 父节点关联子节点 def handleChanged(self, item, column): count = item.childCount() # print dir(item) if item.checkState(column) == Qt.Checked: # print "checked", item, item.text(column) for f in range(count): item.child(f).setCheckState(0, Qt.Checked) if item.checkState(column) == Qt.Unchecked: # print "unchecked", item, item.text(column) for f in range(count): item.child(f).setCheckState(0, Qt.Unchecked) # self.Ui.treeWidget_Plugins.setSelectionMode(QAbstractItemView.ExtendedSelection) # 设置item可以多选 # self.tree.itemChanged.connect(self.handleChanged) # self.Ui.treeWidget_Plugins.addTopLevelItem(root) # 导入文件列表 def vuln_import_file(self): self.url_list = [] filename = self.file_open(r"Text Files (*.txt);;All files(*.*)") if os.path.isfile(filename): self.Ui.textEdit_log.append( "[%s]Info:正在从文件中读取URL..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) f = open(filename, 'r', encoding='utf-8') for line in f.readlines(): if 'http' in line: self.url_list.append(line.replace('\n', '').strip()) self.Ui.textEdit_log.append( "[%s]Info:读取完成,共加载%s条。" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), len(self.url_list))) self.Ui.lineEdit_vuln_url.setText(filename) # 导出扫描结果 def vuln_export_file(self): data = [] comdata = [] for i in range(0, self.Ui.tableWidget_vuln.rowCount()): # 循环行 for j in range(0, self.Ui.tableWidget_vuln.columnCount()): # 循环列 if self.Ui.tableWidget_vuln.item(i, j) != None: # 有数据 data.append(self.Ui.tableWidget_vuln.item( i, j).text()) # 空格分隔 comdata.append(list(data)) data = [] if len(comdata) > 0: path = (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '.csv').replace(' ', '-').replace('-', '').replace(':', '') # print(path) file_name = self.file_save(path) if file_name != "": with open(file_name, 'w', newline='') as f: writer = csv.writer(f) for row in comdata: writer.writerow(row) f.close() # 显示插件 def vuln_ShowPlugins(self): self.widget = Ui_Form() self.dialog = QtWidgets.QDialog(self) self.widget.setupUi(self.dialog) self.dialog.setFixedSize(self.dialog.width(), self.dialog.height()) # 设置宽高不可变 # 设置查看插件表格属性 列宽度 self.widget.show_Plugins.setColumnWidth(0, 100) self.widget.show_Plugins.setColumnWidth(1, 350) self.widget.show_Plugins.setColumnWidth(2, 350) self.widget.show_Plugins.setColumnWidth(3, 383) self.widget.show_Plugins.setColumnWidth(4, 218) conn2 = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn2.cursor() # self.Ui.textEdit_log.append("[%s]Info:正在查询数据..."%(time.strftime('%H:%M:%S', time.localtime(time.time())))) # 列出所有数据 sql = "SELECT * from POC" cursor.execute(sql) values = cursor.fetchall() # self.Ui.textEdit_log.append("[%s]Success:数据查询成功!"%(time.strftime('%H:%M:%S', time.localtime(time.time())))) i = 0 self.widget.show_Plugins.setRowCount(len(values)) sql2 = "SELECT distinct cmsname from POC" cursor.execute(sql2) cms_name_data = cursor.fetchall() # 添加查询列表 for cms_name in cms_name_data: self.widget.show_Plugins_comboBox.addItem(cms_name[0]) # print(cms_name[0]) for single in values: vuln_name = QTableWidgetItem(str(single[1])) vuln_url = QTableWidgetItem(str(single[3])) vuln_payload = QTableWidgetItem(str(single[4])) vuln_result = QTableWidgetItem(str(single[5])) vuln_motheds = QTableWidgetItem(str(single[2])) self.widget.show_Plugins.setItem(i, 0, vuln_name) self.widget.show_Plugins.setItem(i, 1, vuln_url) self.widget.show_Plugins.setItem(i, 2, vuln_payload) self.widget.show_Plugins.setItem(i, 3, vuln_result) self.widget.show_Plugins.setItem(i, 4, vuln_motheds) i = i + 1 conn2.close() self.dialog.show() self.widget.show_Plugins_comboBox.currentIndexChanged.connect( self.show_plugins_go) # comboBox事件选中触发刷新 # 单击列表刷新显示控件 def show_plugins_go(self): self.widget.show_Plugins.clearContents() conn2 = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn2.cursor() cms_name = self.widget.show_Plugins_comboBox.currentText() # 获取文本 if cms_name == "ALL": sql = "SELECT * from POC " else: sql = "SELECT * from POC where cmsname = '%s'" % cms_name cursor.execute(sql) cms_data = cursor.fetchall() i = 0 self.widget.show_Plugins.setRowCount(len(cms_data)) for single in cms_data: vuln_name = QTableWidgetItem(str(single[1])) vuln_url = QTableWidgetItem(str(single[3])) vuln_payload = QTableWidgetItem(str(single[4])) vuln_result = QTableWidgetItem(str(single[5])) vuln_motheds = QTableWidgetItem(str(single[2])) self.widget.show_Plugins.setItem(i, 0, vuln_name) self.widget.show_Plugins.setItem(i, 1, vuln_url) self.widget.show_Plugins.setItem(i, 2, vuln_payload) self.widget.show_Plugins.setItem(i, 3, vuln_result) self.widget.show_Plugins.setItem(i, 4, vuln_motheds) i = i + 1 conn2.close() # for rowNum in range(i, self.widget.show_Plugins.rowCount())[::-1]: # 逆序删除,正序删除会有一些删除不成功 # self.widget.show_Plugins.removeRow(rowNum) # 重新加载插件 def vuln_reload_Plugins(self): self.Ui.treeWidget_Plugins.clear() # 删除数据库,重新建立 if os.path.isfile(DB_NAME): try: # print(DB_NAME) os.remove(DB_NAME) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:数据库文件删除失败!\n[Exception]:\n%s" % ((time.strftime( '%H:%M:%S', time.localtime(time.time()))), e)) return 0 self.Ui.textEdit_log.append( "[%s]Success:删除数据库完成!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) else: self.Ui.textEdit_log.append( "[%s]Success:数据库文件不存在,尝试创建数据库!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) try: # 连接数据库。如果数据库不存在的话,将会自动创建一个 数据库 conn = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn.cursor() # 执行一条语句,创建 user表 如不存在创建 sql = "create table IF NOT EXISTS POC (id integer primary key autoincrement , cmsname varchar(30),pocfilename varchar(40),pocname varchar(30),pocreferer varchar(50),pocdescription varchar(200),pocmethods varchar(40))" cursor.execute(sql) self.Ui.textEdit_log.append( "[%s]Success:创建数据库完成!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:数据框创建失败!\n[Exception]:\n%s" % (time.strftime('%H:%M:%S', time.localtime(time.time())), e)) return 0 try: cms_path = "Plugins" cms_path = cms_path.replace("\\", "/") # 创建一个文件来存储引入的模块 cmsmain_file = open(cms_path + "/Plugins.py", "w", encoding="utf-8") except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:打开Plugins.py文件失败!\n[Exception]:\n%s" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), e)) return 0 try: cmsmain_file.write(r"#!/usr/bin/env python" + '\n' r"# -*- coding: utf-8 -*-" + '\n' r"'''" + '\n' r"name: cms漏洞库" + '\n' r"referer: unknow" + '\n' r"author: qianxiao996" + '\n' r"'''" + '\n') for cms_name in os.listdir(cms_path): # 遍历目录名 cmsmain_file.write("#" + cms_name + "\n") poc_path = os.path.join(cms_path, cms_name) for path, dirs, poc_methos_list in os.walk( poc_path): # 遍历poc文件,得到方法名称 for poc_file_name in poc_methos_list: # self.Ui.textEdit_log.append(poc_file_name[-3:]) # self.Ui.textEdit_log.append(poc_file_name) poc_name_path = cms_path + "\\" + cms_name + "\\" + poc_file_name poc_name_path = poc_name_path.replace("\\", "/") # print(poc_name_path) # 判断是py文件在打开 文件存在 if os.path.isfile(poc_name_path ) and poc_file_name.endswith('.py'): # 判断py文件不包含. if '.' not in poc_file_name.replace(".py", ""): # print(poc_name_path) f = open(poc_name_path, "r", encoding="utf-8") # 获取poc的中文名称 # printSkyBlue(cms_name) poc_methos = "" # 定义局部变量 存放poc方法 poc_name = "" # 定义局部变量 存放poc名称 poc_referer = "" if cms_name[0:2] != "__": # 判断文件夹的前两位不是下划线 for name in f.readlines(): # print(name) # 得到中文poc_name if "name:" in name: poc_name = name.split( ":")[1].replace(" ", "") poc_name = poc_name.replace( "\n", "").replace("\r", "").replace( "\r\n", "") # print(poc_name) # 得到调用的poc_methos if "class " in name: # print(name) poc_methos = name.replace( ":", "").split(" ")[1].replace( "\n", "").replace( "\r", "").replace( "\r\n", "").replace( "()", "") # self.Ui.textEdit_log.append(poc_methos) # 得到调用的poc_referer if "referer" in name: poc_referer = name.replace( ":", "").split(" ")[1].replace( "\n", "").replace("\r", "").replace( "\r\n", "") # self.Ui.textEdit_log.append(poc_referer) # 读取文件光标恢复到初始位置 f.seek(0) condata = f.read() ##所有数据 # print(condata) # 匹配描述 comment = re.compile( r"description:(.*?)'''", re.DOTALL) poc_description = str( comment.findall(condata)[0]).replace( "\"", "").replace(" ", "") if poc_name != "" and poc_methos != "": # 将数据插入到表中 cursor.execute( 'insert into POC (cmsname, pocname,pocfilename,pocreferer,pocdescription,pocmethods) values ("%s","%s","%s","%s","%s","%s")' % (cms_name, poc_name, poc_file_name, poc_referer, poc_description, poc_methos)) data = "from Plugins." + cms_name + "." + poc_file_name.replace( ".py", "" ) + " import " + poc_methos + "\n" cmsmain_file.write(data) f.close() else: self.Ui.textEdit_log.append( "[%s]Error:%s文件加载失败,文件名中不允许包含英文符号点!" % ((time.strftime( '%H:%M:%S', time.localtime( time.time())))(cms_name + "/" + poc_file_name))) return 0 else: pass cmsmain_file.write("\n") conn.commit() # 提交 result = cursor.fetchall() if not len(result): cursor.execute("select count(*) from POC") values = cursor.fetchall() self.Ui.textEdit_log.append( "[%s]Success:共写入%s个插件" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), values[0][0])) self.loadplugins() # 调用加载插件 else: self.Ui.textEdit_log.append( "[%s]Error:数据更新失败,原因:" % (time.strftime('%H:%M:%S', time.localtime(time.time()))), str(result)) return 0 conn.close() cmsmain_file.close() box = QtWidgets.QMessageBox() box.information(self, "End", "数据更新完成!\n插件数量:%s,重新启动!" % values[0][0]) reboot = sys.executable os.execl(reboot, reboot, *sys.argv) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:数据写入失败!\n[Exception]:\n%s" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), e)) return 0 # 关于 def about(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about( self, "About", "\t\t\tAbout\n 此程序为一款CMS扫描工具,可自行选择扫描的插件进行漏洞检查,请勿非法使用!\n\t\t\t Powered by qianxiao996" ) # 更新 def version_update(self): webbrowser.open( "https://github.com/qianxiao996/FrameScan-GUI/releases") # 版本 def version(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about(self, "版本", "FrameScan\nV1.2测试版") # 意见反馈 def ideas(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about(self, "意见反馈", "作者邮箱:[email protected]\n作者主页:http://blog.qianxiao996.cn") # 全选 def vuln_all(self): item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if item.value().checkState(0) != QtCore.Qt.Checked: item.value().setCheckState(0, Qt.Checked) item = item.__iadd__(1) # 反选 def vuln_noall(self): item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if item.value().checkState(0) == QtCore.Qt.Checked: item.value().setCheckState(0, Qt.Unchecked) item = item.__iadd__(1) # 文件打开对话框 def file_open(self, type): fileName, selectedFilter = QFileDialog.getOpenFileName( self, (r"上传文件"), (r"C:\windows"), type) return (fileName) # 返回文件路径 # 保存文件对话框 def file_save(self, filename): fileName, filetype = QFileDialog.getSaveFileName( self, (r"保存文件"), (r'C:\Users\Administrator\\' + filename), r"All files(*.*)") # print(fileName) return fileName
class MainWindows(QtWidgets.QMainWindow, Ui_MainWindow): # 主窗口 def __init__(self, parent=None): super(MainWindows, self).__init__(parent) # self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) #去掉标题栏 self.Ui = Ui_MainWindow() self.Ui.setupUi(self) self.setWindowIcon(QtGui.QIcon('main.ico')) # self.setFixedSize(self.width(), self.height()) # 设置宽高不可变 # self.Ui.exit.clicked.connect(QtCore.QCoreApplication.instance().quit) #退出 self.poc_cms_name_dict = {} self.exp_cms_name_dict = {} # 漏洞扫描 self.Ui.pushButton_vuln_file.clicked.connect( self.vuln_import_file) # 导入地址 self.Ui.pushButton_vuln_start.clicked.connect(self.vuln_Start) # 开始扫描 self.Ui.action_vuln_expstart.triggered.connect(self.vuln_exp) # 一键利用 self.Ui.pushButton_vuln_expstart.clicked.connect(self.vuln_exp) # 一键利用 self.Ui.pushButton_vuln_all.clicked.connect(self.vuln_all) # 全选 self.Ui.pushButton_vuln_noall.clicked.connect(self.vuln_noall) # 反选 #插件管理 self.Ui.action_vuln_reload.triggered.connect( self.vuln_reload_Plugins) # 重新加载插件 self.Ui.action_vuln_showplubins.triggered.connect( self.vuln_ShowPlugins) # 查看插件 #选项 self.Ui.action_about_start.triggered.connect(self.about) # 关于 self.Ui.action_update_start.triggered.connect( self.version_update) # 更新 self.Ui.action_ideas_start.triggered.connect(self.ideas) # 意见反馈 #漏洞利用 self.Ui.vuln_exp_button_cmd.clicked.connect( lambda: self.exp_send('cmd')) self.Ui.vuln_exp_button_shell.clicked.connect( lambda: self.exp_send('shell')) self.Ui.vuln_type.activated[str].connect(self.change_exp_list) self.Ui.vuln_name.activated[str].connect(self.change_exp_name_change) # 漏洞扫描右键菜单 self.Ui.tableWidget_vuln.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.Ui.tableWidget_vuln.customContextMenuRequested['QPoint'].connect( self.createtableWidget_vulnMenu) #初始化加载插件 self.loadplugins() self.url_list = [] self.load_config() # 设置漏洞扫描表格属性 列宽度 self.Ui.tableWidget_vuln.setColumnWidth(0, 200) self.Ui.tableWidget_vuln.setColumnWidth(1, 200) self.Ui.tableWidget_vuln.setColumnWidth(2, 300) self.Ui.tableWidget_vuln.setColumnWidth(3, 80) #选项 othersmenubar = self.menuBar() # 获取窗体的菜单栏 others = othersmenubar.addMenu("选项") for i in ["关于", '更新', '意见反馈']: sub_action = QAction(QIcon(''), i, self) others.addAction(sub_action) impMenu = QMenu("皮肤风格", self) # print(type(config_setup)) for z in config_setup.options('QSS_List'): sub_action = QAction(QIcon(''), z, self) impMenu.addAction(sub_action) #漏洞利用 for z in config_setup.options('Shell'): self.Ui.comboBox_type.addItem(z) others.addMenu(impMenu) others.triggered[QAction].connect(self.show_others) def load_config(self): try: global config_setup # 实例化configParser对象 config_setup = configparser.ConfigParser() # -read读取ini文件 config_setup.read('config.ini', encoding='utf-8') if 'QSS_Setup' not in config_setup: # 如果分组type不存在则插入type分组 config_setup.add_section('QSS_Setup') config_setup.set("QSS_Setup", "QSS", 'default.qss') config_setup.write(open('config.ini', "r+", encoding="utf-8")) # r+模式 qss_Setup = 'default.qss' else: qss_Setup = config_setup.get('QSS_Setup', 'QSS') with open("QSS/" + qss_Setup, 'r', encoding='utf-8') as f: qss_style = f.read() f.close() MainWindows.setStyleSheet(self, qss_style) f.close() except Exception as e: QMessageBox.critical(self, 'Error', str(e)) pass def createtableWidget_vulnMenu(self): ''''' 创建右键菜单 ''' # 必须将ContextMenuPolicy设置为Qt.CustomContextMenu # 否则无法使用customContextMenuRequested信号 self.Ui.tableWidget_vuln.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.Ui.tableWidget_vuln.customContextMenuRequested.connect( self.showContextMenu) # 创建QMenu self.contextMenu = QtWidgets.QMenu(self) self.daochu = self.contextMenu.addAction(u'导出') self.second = self.contextMenu.addMenu(u'复制') self.copy_url = self.second.addAction(u'URL') self.copy_vuln_name = self.second.addAction(u'漏洞名称') self.copy_path = self.second.addAction(u'脚本路径') self.copy_payload = self.second.addAction(u'Payload') self.copy_all = self.second.addAction(u'全部') self.delete_textEdit = self.contextMenu.addAction(u'删除') self.clear_textEdit = self.contextMenu.addAction(u'清空') # 将动作与处理函数相关联 # 这里为了简单,将所有action与同一个处理函数相关联, # 当然也可以将他们分别与不同函数关联,实现不同的功能 self.daochu.triggered.connect(self.vuln_export_file) self.copy_url.triggered.connect( lambda: self.Copy_tableWidget_vuln('url')) self.copy_vuln_name.triggered.connect( lambda: self.Copy_tableWidget_vuln('vuln_name')) self.copy_path.triggered.connect( lambda: self.Copy_tableWidget_vuln('vuln_path')) self.copy_payload.triggered.connect( lambda: self.Copy_tableWidget_vuln('payload')) self.copy_all.triggered.connect( lambda: self.Copy_tableWidget_vuln('all')) self.clear_textEdit.triggered.connect(self.Clear_tableWidget_vuln) self.delete_textEdit.triggered.connect(self.Delete_tableWidget_vuln) # 右键点击时调用的函数,移动鼠标位置 def showContextMenu(self, pos): # 菜单显示前,将它移动到鼠标点击的位置 self.contextMenu.move(QtGui.QCursor.pos()) self.contextMenu.show() def Copy_tableWidget_vuln(self, type): try: data = '' if type == 'url': data = self.Ui.tableWidget_vuln.selectedItems()[0].text() if type == 'vuln_name': data = self.Ui.tableWidget_vuln.selectedItems()[1].text() if type == 'vuln_path': data = self.Ui.tableWidget_vuln.selectedItems()[2].text() if type == 'payload': data = self.Ui.tableWidget_vuln.selectedItems()[4].text() if type == 'all': # data = self.Ui.tableWidget_vuln.selectedItems() for i in self.Ui.tableWidget_vuln.selectedItems(): data += str(i.text()) + ' ' # 访问剪切板,存入值 wincld.OpenClipboard() wincld.EmptyClipboard() wincld.SetClipboardData(win32con.CF_UNICODETEXT, data) wincld.CloseClipboard() except: pass def Clear_tableWidget_vuln(self): for i in range(0, self.Ui.tableWidget_vuln.rowCount()): # 循环行 self.Ui.tableWidget_vuln.removeRow(0) def Delete_tableWidget_vuln(self): self.Ui.tableWidget_vuln.removeRow( self.Ui.tableWidget_vuln.currentRow()) #删除选中的行 # 得到选中的方法 def get_methods(self): all_data = [] item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if not item.value().parent(): # 判断有没有父节点 pass else: # 输出所有子节点 if item.value().checkState(0) == QtCore.Qt.Checked: # print(item.value().text(0)) for cms in self.poc_cms_name_dict: for poc in self.poc_cms_name_dict[cms]: if poc['pocname'] == item.value().text(0): poc['pocmethods'] = poc['pocfilename'].replace( '.py', '') all_data.append(poc) item = item.__iadd__(1) # print(all_data) #返回所有选中的数据 return all_data # 开始扫描 def vuln_Start(self): threadnum = int(self.Ui.threadsnum.currentText()) self.Ui.textEdit_log.clear() target = [] # 存放扫描的URL if self.url_list: target = self.url_list else: url = self.Ui.lineEdit_vuln_url.text() if 'http://' in url or 'https://' in url: target.append(url.strip()) if not target: self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:未获取到URL地址。</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return 0 poc_data = self.get_methods() #得到选中的数据 # print(poc_data) if not poc_data: self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:未选择插件。</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return 0 else: self.Ui.textEdit_log.append("[%s]Info:共加载%s个插件。" % ((time.strftime( '%H:%M:%S', time.localtime(time.time()))), len(poc_data))) self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:共获取到%s个URL地址。</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), len(target))) self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:正在创建队列...</p>" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))))) thread = threading.Thread(target=self.add_queue, args=(target, poc_data, threadnum)) thread.setDaemon(True) # 设置为后台线程,这里默认是False,设置为True之后则主线程不用等待子线程 thread.start() def add_queue(self, target, poc_data, threadnum): # print(poc_data) portQueue = queue.Queue() # 待检测端口队列,会在《Python常用操作》一文中更新用法 num = 0 if self.Ui.jump_url.checkState() != Qt.Checked: num = len(target) for u in target: for xuanzhong_data in poc_data: # print(poc_data) filename = plugins_dir_name + '/' + xuanzhong_data[ 'cmsname'] + '/' + xuanzhong_data['pocmethods'] + '.py' poc_methods = plugins_dir_name + '/' + xuanzhong_data[ 'cmsname'] + '/' + xuanzhong_data['pocmethods'] portQueue.put(u + '$$$' + filename + '$$$' + poc_methods + '$$$' + xuanzhong_data['pocname']) self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:共请求%s个URL地址。</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), num)) if self.Ui.jump_url.checkState() == Qt.Checked: self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:正在进行地址存活检测...</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) false_url = [] for u in target: headers = { 'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0' } try: if u not in false_url: time22 = int(self.Ui.comboBox_timeout.currentText()) dara = requests.get(u, timeout=time22, headers=headers, verify=False) else: continue except Exception as e: false_url.append(u) row = self.Ui.tableWidget_vuln.rowCount() # 获取行数 self.Ui.tableWidget_vuln.setRowCount(row + 1) urlItem = QTableWidgetItem(u) resultItem = QTableWidgetItem('无法访问') self.Ui.tableWidget_vuln.setItem(row, 0, urlItem) self.Ui.tableWidget_vuln.setItem(row, 3, resultItem) self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:%s----无法访问。</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), u)) continue else: for xuanzhong_data in poc_data: # print(poc_data) filename = plugins_dir_name + '/' + xuanzhong_data[ 'cmsname'] + '/' + xuanzhong_data[ 'pocmethods'] + '.py' poc_methods = plugins_dir_name + '/' + xuanzhong_data[ 'cmsname'] + '/' + xuanzhong_data['pocmethods'] portQueue.put(u + '$$$' + filename + '$$$' + poc_methods + '$$$' + xuanzhong_data['pocname']) num += 1 # 限制线程数小于队列大小 self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:共获取到%s个有效URL地址。</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), num)) if threadnum > portQueue.qsize(): threadnum = portQueue.qsize() # print(portQueue.qsize()) if num == 0: self.Ui.textEdit_log.append( "[%s]End:扫描结束。" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return else: self.Ui.textEdit_log.append( "[%s]Start:扫描开始..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) self.Ui.action_vuln_import.setEnabled(False) self.Ui.pushButton_vuln_file.setEnabled(False) self.Ui.action_vuln_start.setEnabled(False) self.Ui.pushButton_vuln_start.setEnabled(False) for i in range(threadnum): thread = threading.Thread(target=self.vuln_scan, args=(portQueue, threadnum)) thread.setDaemon( True) # 设置为后台线程,这里默认是False,设置为True之后则主线程不用等待子线程 thread.start() # 调用脚本 def vuln_scan(self, portQueue, threadnum): # print(portQueue.queue) #输出所有队列 while 1: try: if portQueue.empty(): # 队列空就结束 time.sleep(int(self.Ui.comboBox_timeout.currentText())) self.Ui.pushButton_vuln_file.setEnabled(True) self.Ui.pushButton_vuln_start.setEnabled(True) return else: all = portQueue.get().split( '$$$' ) # 从队列中取出 #0 url 1 filename 2 pocmethods 3 pocname url = all[0] filename = all[1] poc_methods = all[2] # nnnnnnnnnnnn1 = importlib.import_module(poc_methods) eventlet.monkey_patch(thread=False) #超时限制 try: timeout = int(self.Ui.comboBox_timeout.currentText()) with eventlet.Timeout(timeout, True): # print(timeout) # time.sleep(6) try: nnnnnnnnnnnn1 = importlib.machinery.SourceFileLoader( poc_methods, filename).load_module() nnnnnnnnnnnn1.run(self, url, all) except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:%s脚本执行错误!<br>[Exception]:<br>%s</p>" % ((time.strftime( '%H:%M:%S', time.localtime( time.time()))), filename, e)) continue except: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:%s----%s----%s。</p>" % ((time.strftime( '%H:%M:%S', time.localtime( time.time()))), url, all[3], '脚本运行超时')) self.Ui.pushButton_vuln_file.setEnabled(True) self.Ui.pushButton_vuln_start.setEnabled(True) pass except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:%s脚本执行错误!<br>[Exception]:<br>%s</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), filename, e)) pass # 初始化加载插件 def loadplugins(self): if not os.path.isfile(DB_NAME): box = QtWidgets.QMessageBox() box.warning(self, "提示", "数据文件不存在,正在重新加载数据库!") self.vuln_reload_Plugins() return 0 #加载漏洞扫描模块 try: # 列出所有数据 sql_poc = "SELECT cmsname,pocname,pocfilename from POC where pocfilename !=''" poc_dict = self.sql_search(sql_poc, 'dict') # print(self.poc_dict) sql_exp = "SELECT cmsname,pocname,pocfilename,expdescription from POC where expfilename !=''" exp_dict = self.sql_search(sql_exp, 'dict') # print(values) except Exception as e: box = QtWidgets.QMessageBox() box.warning(self, "提示", "数据文件错误:\n%s" % e) return 0 # 将查询的值组合为字典包含列表的形式 self.poc_cms_name_dict = {} for cms in poc_dict: self.poc_cms_name_dict[cms['cmsname']] = [] # print(cms_name) for cms in poc_dict: # print(cms['cmsname'] ) # if cms['cmsname'] in cms_name.keys(): poc_cms_sing = {} poc_cms_sing['cmsname'] = cms['cmsname'] poc_cms_sing['pocname'] = cms['pocname'] poc_cms_sing['pocfilename'] = cms['pocfilename'] self.poc_cms_name_dict[cms['cmsname']].append(poc_cms_sing) for cms in self.poc_cms_name_dict: # 设置root为self.treeWidget_Plugins的子树,故root是根节点 root = QTreeWidgetItem(self.Ui.treeWidget_Plugins) root.setText(0, cms) # 设置根节点的名称 root.setCheckState(0, Qt.Unchecked) # 开启复选框 # print(cms_name[cms]) for cms_single in self.poc_cms_name_dict[cms]: # 为root节点设置子结点 child1 = QTreeWidgetItem(root) child1.setText(0, cms_single['pocname']) child1.setCheckState(0, Qt.Unchecked) self.Ui.treeWidget_Plugins.itemChanged.connect(self.handleChanged) self.Ui.treeWidget_Plugins.doubleClicked.connect( self.Show_Plugins_info) self.Ui.textEdit_log.append( "<p style=\"color:green\">[%s]Success:插件加载完成,共%s个。</p>" % (time.strftime('%H:%M:%S', time.localtime( time.time())), len(poc_dict))) #加载exp # print(self.exp_dict) # 将查询的值组合为字典包含列表的形式 self.exp_cms_name_dict = {} for cms in exp_dict: self.exp_cms_name_dict[cms['cmsname']] = [] # print(exp_cms_name_dict) for exp_cms in exp_dict: # print(cms['cmsname'] ) # if cms['cmsname'] in cms_name.keys(): exp_cms_sing = {} exp_cms_sing['cmsname'] = exp_cms['cmsname'] exp_cms_sing['pocname'] = exp_cms['pocname'] exp_cms_sing['pocfilename'] = exp_cms['pocfilename'] exp_cms_sing['expdescription'] = exp_cms['expdescription'] self.exp_cms_name_dict[exp_cms['cmsname']].append(exp_cms_sing) # print(exp_cms_name_dict) self.Ui.vuln_name.clear() self.Ui.vuln_type.clear() for cms in self.exp_cms_name_dict: self.Ui.vuln_type.addItem(cms) for exp_methods in list(self.exp_cms_name_dict.values())[0]: # print(exp_methods) self.Ui.vuln_name.addItem(exp_methods['pocname']) self.Ui.vuln_exp_textEdit_info.setText( exp_methods['expdescription']) def Show_Plugins_info(self): poc_name = self.Ui.treeWidget_Plugins.currentItem().text(0) # 列出所有数据 sql = "SELECT * from POC where pocname='%s'" % poc_name values = self.sql_search(sql) # print(values) try: self.dialog.close() except: pass if len(values) != 0: self.WChild_info = Ui_Plugins_information() self.dialog = QtWidgets.QDialog(self) self.WChild_info.setupUi(self.dialog) self.dialog.show() # print(values) self.WChild_info.vuln_name.setText(values[0][4]) self.WChild_info.cms_name.setText(values[0][1]) self.WChild_info.poc_file_path.setText("Plugins/" + values[0][1] + '/' + values[0][2]) if values[0][3] == '': self.WChild_info.exp_file_path.setText("暂无EXP") else: self.WChild_info.exp_file_path.setText("Plugins/" + values[0][1] + '/' + values[0][3]) self.WChild_info.vuln_url.setText('<a href="' + values[0][5] + '">' + values[0][5] + '</a>') self.WChild_info.vuln_miaoshu.setText(values[0][6]) return 0 else: return # 父节点关联子节点 def handleChanged(self, item, column): count = item.childCount() # print dir(item) if item.checkState(column) == Qt.Checked: # print "checked", item, item.text(column) for f in range(count): item.child(f).setCheckState(0, Qt.Checked) if item.checkState(column) == Qt.Unchecked: # print "unchecked", item, item.text(column) for f in range(count): item.child(f).setCheckState(0, Qt.Unchecked) # self.Ui.treeWidget_Plugins.setSelectionMode(QAbstractItemView.ExtendedSelection) # 设置item可以多选 # self.tree.itemChanged.connect(self.handleChanged) # self.Ui.treeWidget_Plugins.addTopLevelItem(root) # 导入文件列表 def vuln_import_file(self): self.url_list = [] filename = self.file_open(r"Text Files (*.txt);;All files(*.*)") try: if os.path.isfile(filename): self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:正在从文件中读取URL...</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) f = open(filename, 'r', encoding='utf-8') for line in f.readlines(): if 'http' in line: line = line.replace('\n', '').strip() self.url_list.append(line) self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:读取完成,共加载%s条。</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), len(self.url_list))) self.Ui.lineEdit_vuln_url.setText(filename) except: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:文件打开失败!</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) pass # 导出扫描结果 def vuln_export_file(self): data = [] comdata = [] for i in range(0, self.Ui.tableWidget_vuln.rowCount()): # 循环行 for j in range(0, self.Ui.tableWidget_vuln.columnCount()): # 循环列 if self.Ui.tableWidget_vuln.item(i, j) != None: # 有数据 data.append(self.Ui.tableWidget_vuln.item( i, j).text()) # 空格分隔 comdata.append(list(data)) data = [] if len(comdata) > 0: path = (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '.csv').replace(' ', '-').replace('-', '').replace(':', '') # print(path) file_name = self.file_save(path) if file_name != "": with open(file_name, 'w', newline='') as f: writer = csv.writer(f) for row in comdata: writer.writerow(row) f.close() box = QtWidgets.QMessageBox() box.information(self, "Success", "导出成功!\n文件位置:" + file_name) else: # box2= QtWidgets.QMessageBox() # box2.warning(self, "Error", "保存失败!文件名错误!" ) pass else: self.Ui.textEdit_log.append( "[%s]Faile:没有扫描结果!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) # 显示插件 def vuln_ShowPlugins(self): self.widget = Ui_Form() self.dialog = QtWidgets.QDialog(self) self.widget.setupUi(self.dialog) self.dialog.setFixedSize(self.dialog.width(), self.dialog.height()) # 设置宽高不可变 # 设置查看插件表格属性 列宽度 self.widget.show_Plugins.setColumnWidth(0, 120) self.widget.show_Plugins.setColumnWidth(1, 200) self.widget.show_Plugins.setColumnWidth(2, 320) self.widget.show_Plugins.setColumnWidth(3, 360) self.widget.show_Plugins.setColumnWidth(4, 218) self.widget.show_Plugins.setColumnWidth(5, 218) sql = "SELECT * from POC" values = self.sql_search(sql) i = 0 self.widget.show_Plugins.setRowCount(len(values)) sql2 = "SELECT distinct cmsname from POC" cms_name_data = self.sql_search(sql2) # 添加查询列表 for cms_name in cms_name_data: self.widget.show_Plugins_comboBox.addItem(cms_name[0]) # print(cms_name[0]) for single in values: # print(single) cms_name = QTableWidgetItem(str(single[1])) poc_file_name = QTableWidgetItem(str(single[2])) exp_file_name = QTableWidgetItem(str(single[3])) poc_name = QTableWidgetItem(str(single[4])) poc_referer = QTableWidgetItem(str(single[5])) poc_descr = QTableWidgetItem(str(single[6])) self.widget.show_Plugins.setItem(i, 0, cms_name) self.widget.show_Plugins.setItem(i, 1, poc_name) self.widget.show_Plugins.setItem(i, 2, poc_referer) self.widget.show_Plugins.setItem(i, 3, poc_descr) self.widget.show_Plugins.setItem(i, 4, poc_file_name) self.widget.show_Plugins.setItem(i, 5, exp_file_name) i = i + 1 self.dialog.show() self.widget.show_Plugins_comboBox.currentIndexChanged.connect( self.show_plugins_go) # comboBox事件选中触发刷新 # 单击列表刷新显示控件 def show_plugins_go(self): self.widget.show_Plugins.clearContents() cms_name = self.widget.show_Plugins_comboBox.currentText() # 获取文本 if cms_name == "ALL": sql = "SELECT * from POC " else: sql = "SELECT * from POC where cmsname = '%s'" % cms_name cms_data = self.sql_search(sql) i = 0 self.widget.show_Plugins.setRowCount(len(cms_data)) for single in cms_data: cms_name = QTableWidgetItem(str(single[1])) poc_file_name = QTableWidgetItem(str(single[2])) exp_file_name = QTableWidgetItem(str(single[3])) poc_name = QTableWidgetItem(str(single[4])) poc_referer = QTableWidgetItem(str(single[5])) poc_descr = QTableWidgetItem(str(single[6])) self.widget.show_Plugins.setItem(i, 0, cms_name) self.widget.show_Plugins.setItem(i, 1, poc_name) self.widget.show_Plugins.setItem(i, 2, poc_referer) self.widget.show_Plugins.setItem(i, 3, poc_descr) self.widget.show_Plugins.setItem(i, 4, poc_file_name) self.widget.show_Plugins.setItem(i, 5, exp_file_name) i = i + 1 # 重新加载插件 def vuln_reload_Plugins(self): self.Ui.treeWidget_Plugins.clear() self.Ui.textEdit_log.setText( "[%s]Start:正在重新加载插件..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) # 删除数据库,重新建立 if os.path.isfile(DB_NAME): try: os.remove(DB_NAME) except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:数据库文件删除失败!<br>[Exception]:<br>%s</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), e)) return 0 self.Ui.textEdit_log.append( "<p style=\"color:green\">[%s]Success:删除数据库完成!</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) else: self.Ui.textEdit_log.append( "<p style=\"color:black\">[%s]Info:数据库文件不存在,尝试创建数据库!</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) try: # 连接数据库。如果数据库不存在的话,将会自动创建一个 数据库 conn = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn.cursor() # 执行一条语句,创建 user表 如不存在创建 sql = "create table IF NOT EXISTS POC (id integer primary key autoincrement , cmsname varchar(30),pocfilename varchar(50),expfilename varchar(50),pocname varchar(30),pocreferer varchar(50),pocdescription varchar(200),expdescription varchar(9000))" cursor.execute(sql) self.Ui.textEdit_log.append( "<p style=\"color:green\">[%s]Success:创建数据库完成!</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:数据框创建失败!<br>[Exception]:<br>%s</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())), e)) return 0 try: plugins_path = "Plugins" plugins_path = plugins_path.replace("\\", "/") for cms_name in os.listdir(plugins_path): # 遍历目录名 cms_path = os.path.join(plugins_path, cms_name).replace("\\", "/") for poc_file_dir, poc_dirs_list, poc_file_name_list in os.walk( cms_path): # 遍历poc文件,得到方法名称 # print(path,dirs,poc_methos_list) # print(poc_file_name_list) for poc_file_name in poc_file_name_list: poc_name_path = poc_file_dir + "\\" + poc_file_name poc_name_path = poc_name_path.replace("\\", "/") # 判断是py文件在打开 文件存在 if os.path.isfile( poc_name_path) and poc_file_name.endswith( '.py') and poc_file_name[-7:] == '_poc.py': # print(poc_name_path) try: nnnnnnnnnnnn1 = importlib.machinery.SourceFileLoader( poc_name_path[:-3], poc_name_path).load_module() vuln_info = nnnnnnnnnnnn1.vuln_info() # 将数据插入到表中 cursor.execute( 'insert into POC (cmsname, pocname,pocfilename,expfilename,pocreferer,pocdescription,expdescription) values ("%s","%s","%s","%s","%s","%s","%s")' % (cms_name, vuln_info['name'], poc_file_name, '', vuln_info['referer'], vuln_info['description'], '')) except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:%s脚本执行错误!<br>[Exception]:<br>%s</p>" % ((time.strftime( '%H:%M:%S', time.localtime( time.time()))), poc_file_name, e)) continue conn.commit() # 提交 for poc_file_name in poc_file_name_list: poc_name_path = poc_file_dir + "\\" + poc_file_name poc_name_path = poc_name_path.replace("\\", "/") if os.path.isfile( poc_name_path) and poc_file_name.endswith( '.py') and poc_file_name[-7:] == '_exp.py': try: nnnnnnnnnnnn1 = importlib.machinery.SourceFileLoader( poc_name_path[:-3], poc_name_path).load_module() exp_info = nnnnnnnnnnnn1.vuln_info() # print(exp_info) # 将数据插入到表中 sql = "select * from POC where pocname='%s'" % ( exp_info['name']) # print(sql) # 判断是否已有poc 有则修改 无则添加 exp_result = self.sql_search(sql) if exp_result: cursor.execute( "UPDATE POC SET expfilename='%s' ,expdescription='%s' where pocname='%s'" % (poc_file_name, exp_info['description'], exp_info['name'])) else: cursor.execute( 'insert into POC (cmsname, pocname,pocfilename,expfilename,pocreferer,pocdescription,expdescription) values ("%s","%s","%s","%s","%s","%s","%s")' % (cms_name, exp_info['name'], '', poc_file_name, exp_info['referer'], '', exp_info['description'])) except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:%s脚本执行错误!<br>[Exception]:<br>%s</p>" % ((time.strftime( '%H:%M:%S', time.localtime( time.time()))), poc_file_name, e)) continue else: pass conn.commit() # 提交 # print(result) cursor.execute("select count(*) from POC where pocfilename !=''") poc_num = cursor.fetchall() cursor.execute( "select count(expfilename) from POC where expfilename !=''") exp_num = cursor.fetchall() conn.close() self.Ui.textEdit_log.append( "<p style=\"color:green\">[%s]Success:共写入%s个POC</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), poc_num[0][0])) self.Ui.textEdit_log.append( "<p style=\"color:green\">[%s]Success:共写入%s个EXP</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), exp_num[0][0])) self.loadplugins() # 调用加载插件 box = QtWidgets.QMessageBox() box.information( self, "Load Plugins", "数据更新完成!\nPOC数量:%s\nEXP数量:%s" % (poc_num[0][0], exp_num[0][0])) # reboot = sys.executable # os.execl(reboot, reboot, *sys.argv) except Exception as e: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:数据写入失败!\n[Exception]:\n%s</p>" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), e)) return 0 def show_others(self, q): if q.text() == "关于": self.about() return if q.text() == "更新": self.version_update() return if q.text() == "意见反馈": self.ideas() return else: try: filename = config_setup.get('QSS_List', q.text()) # print(filename) config_setup.set("QSS_Setup", "QSS", filename) config_setup.write(open('config.ini', "r+", encoding="utf-8")) # r+模式 with open('QSS/' + filename, 'r', encoding='utf-8') as f: qss_style = f.read() f.close() MainWindows.setStyleSheet(self, qss_style) # python = sys.executable # os.execl(python, python, *sys.argv) except Exception as e: QMessageBox.critical(self, 'Error', str(e)) pass def vuln_exp(self): if self.Ui.tableWidget_vuln.selectedItems(): url = self.Ui.tableWidget_vuln.selectedItems()[0].text() poc_name = self.Ui.tableWidget_vuln.selectedItems()[1].text() sql = "select * from POC where pocname='%s'" % (poc_name) exp_data = self.sql_search(sql, 'dict') #print(exp_data) if len(exp_data): # 根据文本查找索引设置选中 cms_index = self.Ui.vuln_type.findText( exp_data[0]['cmsname'], QtCore.Qt.MatchFixedString) if cms_index >= 0: # print(2) self.Ui.vuln_type.setCurrentIndex(cms_index) self.change_exp_list(exp_data[0]['cmsname']) exp_index = self.Ui.vuln_name.findText( exp_data[0]['pocname'], QtCore.Qt.MatchFixedString) if cms_index >= 0: self.Ui.vuln_name.setCurrentIndex(exp_index) else: box = QtWidgets.QMessageBox() box.warning(self, "提示", "该漏洞暂时没有利用工具!") else: box = QtWidgets.QMessageBox() box.warning(self, "提示", "该漏洞暂时没有利用工具!") self.Ui.tabWidget.setCurrentIndex(1) self.Ui.vuln_lineEdit_url.setText(url) else: box = QtWidgets.QMessageBox() box.warning(self, "提示", "该漏洞暂时没有利用工具!") else: self.Ui.textEdit_log.append( "<p style=\"color:red\">[%s]Error:请选择一个结果!</p>" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) def exp_send(self, exp_type): url = self.Ui.vuln_lineEdit_url.text() if not url: box = QtWidgets.QMessageBox() box.warning(self, "提示", "目标地址不能为空!") return cms_name = self.Ui.vuln_type.currentText() exp_name = self.Ui.vuln_name.currentText() exp_file_name = self.sql_search( "select expfilename from POC where pocname='%s' and cmsname='%s'" % (exp_name, cms_name)) # print(exp_file_name) exp_path = plugins_dir_name + '/' + cms_name + '/' + exp_file_name[0][0] cookie = self.Ui.vuln_lineEdit_cookie.text() heads = self.Ui.plainTextEdit_heads.toPlainText() heads_dict = {} heads = heads.split('\n') for head in heads: head = head.split(':') heads_dict[head[0].strip()] = head[1].strip() if exp_type == 'cmd': cmd = self.Ui.vuln_exp_input_cmd.text() self.Ui.vuln_exp_textEdit_log.append("[%s]命令执行:%s" % ( (time.strftime('%H:%M:%S', time.localtime(time.time()))), cmd)) try: nnnnnnnnnnnn1 = importlib.machinery.SourceFileLoader( exp_path[:-3], exp_path).load_module() nnnnnnnnnnnn1.run(self, url, heads_dict, cookie, cmd) except Exception as e: self.Ui.textEdit_result.append( "[%s]Error:%s脚本执行错误!\n[Exception]:\n%s" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), exp_path, e)) return if exp_type == 'shell': ip = self.Ui.vuln_exp_input_ip.text() port = self.Ui.vuln_exp_input_port.text() shelltype = self.Ui.comboBox_type.currentText() shellcmd = config_setup.get('Shell', shelltype) shellcmd = shellcmd.replace('127.0.0.1', ip).replace('8888', port) if not 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]?)$", ip): box = QtWidgets.QMessageBox() box.warning(self, "提示", "请输入合法的IP地址!") return try: if port == '' or int(port) not in range(1, 65535): box = QtWidgets.QMessageBox() box.warning(self, "提示", "请输入合法的端口!") return except: box = QtWidgets.QMessageBox() box.warning(self, "提示", "请输入合法的端口!") return try: self.Ui.vuln_exp_textEdit_log.append( "[%s]反弹Shell:%s:%s %s" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), ip, port, shelltype)) nnnnnnnnnnnn1 = importlib.machinery.SourceFileLoader( exp_path[:-3], exp_path).load_module() nnnnnnnnnnnn1.run(self, url, heads_dict, cookie, shellcmd, ip, int(port)) except Exception as e: self.Ui.textEdit_result.append( "[%s]Error:%s脚本执行错误!\n[Exception]:\n%s" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), exp_path, e)) return # 关于 def about(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about( self, "About", "\t\t\tAbout\n 此程序为一款CMS扫描利用工具,可自行选择插件进行漏洞检查或利用,请勿非法使用!\n\t\t\t Powered by qianxiao996" ) # 更新 def version_update(self): webbrowser.open( "https://github.com/qianxiao996/FrameScan-GUI/releases") # 意见反馈 def ideas(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about(self, "意见反馈", "作者邮箱:[email protected]\n作者主页:http://blog.qianxiao996.cn") # 全选 def vuln_all(self): item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if item.value().checkState(0) != QtCore.Qt.Checked: item.value().setCheckState(0, Qt.Checked) item = item.__iadd__(1) # 反选 def vuln_noall(self): item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if item.value().checkState(0) == QtCore.Qt.Checked: item.value().setCheckState(0, Qt.Unchecked) item = item.__iadd__(1) # 文件打开对话框 def file_open(self, type): fileName, selectedFilter = QFileDialog.getOpenFileName( self, (r"上传文件"), '', type) return (fileName) # 返回文件路径 # 保存文件对话框 def file_save(self, filename): fileName, filetype = QFileDialog.getSaveFileName( self, (r"保存文件"), (filename), r"All files(*.*)") return fileName def vuln_scanner_log(self, type, text='', payload='', all=['', '', '', ''], color='black'): # print(type,text) if type == "Debug" and self.Ui.vuln_scanner_debug.checkState( ) == Qt.Checked: self.Ui.textEdit_log.append( "<p style=\"color:blue\">[%s]Debug:%s。</p>" % (time.strftime('%H:%M:%S'), text)) if type == 'result': url = all[0] filename = all[1] pocmethods = all[2] poc_name = all[3] self.Ui.textEdit_log.append( "<p style=\"color:green\">[%s]Result:%s----%s----%s。</p>" % ((time.strftime('%H:%M:%S', time.localtime( time.time()))), url, poc_name, text)) if text != '不存在' and text != '': row = self.Ui.tableWidget_vuln.rowCount() # 获取行数 self.Ui.tableWidget_vuln.setRowCount(row + 1) urlItem = QTableWidgetItem(url) nameItem = QTableWidgetItem(poc_name) payloadItem = QTableWidgetItem(payload) resultItem = QTableWidgetItem(text) filenameItem = QTableWidgetItem(filename) self.Ui.tableWidget_vuln.setItem(row, 0, urlItem) self.Ui.tableWidget_vuln.setItem(row, 1, nameItem) self.Ui.tableWidget_vuln.setItem(row, 3, resultItem) self.Ui.tableWidget_vuln.setItem(row, 2, filenameItem) self.Ui.tableWidget_vuln.setItem(row, 4, payloadItem) if type != "Debug" and type != 'result': self.Ui.textEdit_log.append( "<p style=\"color:%s\">[%s]%s:%s。</p>" % (color, time.strftime('%H:%M:%S'), type, text)) def vuln_exp_log(self, type, text='', color='black'): if type == 'result': self.Ui.textEdit_result.setText(text) self.Ui.vuln_exp_textEdit_log.append( "[%s]执行结果:%s" % (time.strftime('%H:%M:%S'), text)) else: self.Ui.vuln_exp_textEdit_log.append( "<p style=\"color:%s\">[%s]%s:%s。</p>" % (color, time.strftime('%H:%M:%S'), type, text)) def sql_search(self, sql, type='list'): if type == 'dict': conn = sqlite3.connect(DB_NAME) conn.row_factory = self.dict_factory else: conn = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn.cursor() # self.Ui.textEdit_log.append("[%s]Info:正在查询数据..."%(time.strftime('%H:%M:%S', time.localtime(time.time())))) # 列出所有数据 cursor.execute(sql) values = cursor.fetchall() return values #sql查询返回字典 def dict_factory(self, cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d def change_exp_list(self, exp_cms_name): self.Ui.vuln_name.clear() for exp_methods in self.exp_cms_name_dict[exp_cms_name]: # print(exp_methods) self.Ui.vuln_name.addItem(exp_methods['pocname']) self.change_exp_name_change() # print(exp_cms_name) #vuln_name 改变调用函数 def change_exp_name_change(self): self.Ui.exp_tabWidget.setCurrentIndex(0) vuln_name_text = self.Ui.vuln_name.currentText() sql = "select expdescription from POC where pocname='%s'" % vuln_name_text expdescription = self.sql_search(sql) # print(expdescription[0][0]) # pass if expdescription: self.Ui.vuln_exp_textEdit_info.setText(expdescription[0][0]) else: box = QtWidgets.QMessageBox() box.warning(self, "提示", "该EXP暂无描述信息!")
class MainWindows(QtWidgets.QMainWindow, Ui_MainWindow): # 主窗口 def __init__(self, parent=None): super(MainWindows, self).__init__(parent) # self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) #去掉标题栏 self.Ui = Ui_MainWindow() self.Ui.setupUi(self) self.setWindowIcon(QtGui.QIcon('main.ico')) # self.setFixedSize(self.width(), self.height()) # 设置宽高不可变 # self.Ui.exit.clicked.connect(QtCore.QCoreApplication.instance().quit) #退出 self.Ui.action_vuln_start.triggered.connect(self.vuln_Start) # 开始扫描 self.Ui.action_vuln_import.triggered.connect(self.vuln_import_file) # 导入文件列表 self.Ui.pushButton_vuln_file.clicked.connect(self.vuln_import_file) # 导入地址 self.Ui.action_vuln_export.triggered.connect(self.vuln_export_file) # 导出扫描结果 self.Ui.pushButton_vuln_export.clicked.connect(self.vuln_export_file) # 导出结果 self.Ui.action_vuln_reload.triggered.connect(self.vuln_reload_Plugins) # 重新加载插件 self.Ui.action_vuln_showplubins.triggered.connect(self.vuln_ShowPlugins) # 查看插件 self.Ui.pushButton_vuln_showplugins.clicked.connect(self.vuln_ShowPlugins) # 查看插件 self.Ui.pushButton_vuln_start.clicked.connect(self.vuln_Start) # 开始扫描\ self.Ui.action_about.triggered.connect(self.about) # 关于 self.Ui.action_update.triggered.connect(self.version_update) # 更新 self.Ui.action_ideas.triggered.connect(self.ideas) # 意见反馈 self.Ui.pushButton_vuln_all.clicked.connect(self.vuln_all) # 全选 self.Ui.pushButton_vuln_noall.clicked.connect(self.vuln_noall) # 反选 # 右键菜单 self.Ui.tableWidget_vuln.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.Ui.tableWidget_vuln.customContextMenuRequested['QPoint'].connect(self.createtableWidget_vulnMenu) self.timer = QTimer() # 设定一个定时器用来显示时间 self.timer.timeout.connect(self.showtime) self.timer.start() self.loadplugins() self.url_list = [] self.readfile() # 设置漏洞扫描表格属性 列宽度 self.Ui.tableWidget_vuln.setColumnWidth(0, 150) self.Ui.tableWidget_vuln.setColumnWidth(1, 240) self.Ui.tableWidget_vuln.setColumnWidth(2, 280) self.Ui.tableWidget_vuln.setColumnWidth(3, 80) #帮助 othersmenubar = self.menuBar() # 获取窗体的菜单栏 others = othersmenubar.addMenu("帮助") for i in ["关于",'更新','意见反馈']: sub_action = QAction(QIcon(''), i, self) others.addAction(sub_action) impMenu = QMenu("皮肤风格", self) for z in json_qss: sub_action = QAction(QIcon(''), z, self) impMenu.addAction(sub_action) others.addMenu(impMenu) others.triggered[QAction].connect(self.show_others) def readfile(self): try: global json_qss f=open('QSS/list.txt','r',encoding='utf-8') json_qss=json.load(f) # print(json_data) f.close() f=open('QSS/Setup.txt','r',encoding='utf-8') qss_Setup=json.load(f) with open("QSS/"+qss_Setup["QSS"], 'r', encoding='utf-8') as f: qss_style = f.read() f.close() MainWindows.setStyleSheet(self,qss_style) f.close() except Exception as e : QMessageBox.critical(self,'Error',str(e)) pass def createtableWidget_vulnMenu(self): ''''' 创建右键菜单 ''' # 必须将ContextMenuPolicy设置为Qt.CustomContextMenu # 否则无法使用customContextMenuRequested信号 self.Ui.tableWidget_vuln.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.Ui.tableWidget_vuln.customContextMenuRequested.connect(self.showContextMenu) # 创建QMenu self.contextMenu = QtWidgets.QMenu(self) self.copy_textEdit = self.contextMenu.addAction(u'复制') self.clear_textEdit = self.contextMenu.addAction(u'清空') self.delete_textEdit= self.contextMenu.addAction(u'删除') # 将动作与处理函数相关联 # 这里为了简单,将所有action与同一个处理函数相关联, # 当然也可以将他们分别与不同函数关联,实现不同的功能 self.copy_textEdit.triggered.connect(self.Copy_tableWidget_vuln) self.clear_textEdit.triggered.connect(self.Clear_tableWidget_vuln) self.delete_textEdit.triggered.connect(self.Delete_tableWidget_vuln) # 右键点击时调用的函数,移动鼠标位置 def showContextMenu(self, pos): # 菜单显示前,将它移动到鼠标点击的位置 self.contextMenu.move(QtGui.QCursor.pos()) self.contextMenu.show() def Copy_tableWidget_vuln(self): try: data = self.Ui.tableWidget_vuln.selectedItems()[0].text() # print(data) # 访问剪切板,存入值 wincld.OpenClipboard() wincld.EmptyClipboard() wincld.SetClipboardData(win32con.CF_UNICODETEXT, data) wincld.CloseClipboard() except: pass def Clear_tableWidget_vuln(self): for i in range(0, self.Ui.tableWidget_vuln.rowCount()): # 循环行 self.Ui.tableWidget_vuln.removeRow(0) def Delete_tableWidget_vuln(self): self.Ui.tableWidget_vuln.removeRow(self.Ui.tableWidget_vuln.currentRow())#删除选中的行 # 显示时间 def showtime(self): datetime = QDateTime.currentDateTime() text = datetime.toString("yyyy-MM-dd hh:mm:ss") self.setWindowTitle("FrameScan-GUI v"+version+" 测试版 "+update_time+" %s" % text) # 得到选中的方法 def get_methods(self): all_data = [] conn2 = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn2.cursor() item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if not item.value().parent(): # 判断有没有父节点 pass else: # 输出所有子节点 if item.value().checkState(0) == QtCore.Qt.Checked: # 参考网上的方法,判断有无父母结点后再分别操作的那个,实在找不到更直接的 sql = "SELECT * from POC where pocmethods = '%s'"%(item.value().text(0)) cursor.execute(sql) xuanzhong_data = cursor.fetchall() all_data.append(xuanzhong_data) item = item.__iadd__(1) conn2.close() #返回所有选中的数据 return all_data # 开始扫描 def vuln_Start(self): threadnum = int(self.Ui.threadsnum.currentText()) self.Ui.textEdit_log.clear() target = [] # 存放扫描的URL if self.url_list: target = self.url_list else: url = self.Ui.lineEdit_vuln_url.text() if 'http://' in url or 'https://' in url: target.append(url.strip()) if not target: self.Ui.textEdit_log.append( "[%s]Info:未获取到URL地址。" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return 0 all_data = self.get_methods() if not all_data: self.Ui.textEdit_log.append( "[%s]Info:未选择插件。" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) return 0 else: self.Ui.textEdit_log.append( "[%s]Info:共加载%s个插件。" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), len(all_data))) self.Ui.textEdit_log.append( "[%s]Info:共获取到%s个URL地址。" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), len(target))) self.Ui.textEdit_log.append( "[%s]Info:正在创建队列..." % ((time.strftime('%H:%M:%S', time.localtime(time.time()))))) thread = threading.Thread(target=self.add_queue, args=(target,all_data,threadnum)) thread.setDaemon(True) # 设置为后台线程,这里默认是False,设置为True之后则主线程不用等待子线程 thread.start() def add_queue(self,target,all_data,threadnum): portQueue = queue.Queue() # 待检测端口队列,会在《Python常用操作》一文中更新用法 if self.Ui.jump_url.checkState() != Qt.Checked: num= len(target) for u in target: for xuanzhong_data in all_data: for p in xuanzhong_data: # print(p) cms_name = p[1] filename = 'Plugins/' + cms_name + '/' + p[2] poc_methods = 'Plugins.' + cms_name + '.' + p[6] portQueue.put(u + '$$$' + filename + '$$$' + poc_methods) else: num = 0 for u in target: headers = {'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'} try: dara = requests.get(u, timeout=3, headers=headers) except Exception as e: row = self.Ui.tableWidget_vuln.rowCount() # 获取行数 self.Ui.tableWidget_vuln.setRowCount(row + 1) urlItem = QTableWidgetItem(u) resultItem = QTableWidgetItem('无法访问') self.Ui.tableWidget_vuln.setItem(row, 0, urlItem) self.Ui.tableWidget_vuln.setItem(row, 3, resultItem) continue else: for xuanzhong_data in all_data: for p in xuanzhong_data: # print(p) cms_name = p[1] filename = 'Plugins/' + cms_name + '/' + p[2] poc_methods = 'Plugins.' + cms_name + '.' + p[6] portQueue.put(u + '$$$' + filename + '$$$' + poc_methods) num+= 1 # 限制线程数小于队列大小 if threadnum > portQueue.qsize(): threadnum = portQueue.qsize() # print(portQueue.qsize()) self.Ui.textEdit_log.append( "[%s]Info:共获取到%s个有效URL地址。" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), num)) self.Ui.textEdit_log.append( "[%s]Start:扫描开始..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) self.Ui.action_vuln_import.setEnabled(False) self.Ui.pushButton_vuln_file.setEnabled(False) self.Ui.action_vuln_start.setEnabled(False) self.Ui.pushButton_vuln_start.setEnabled(False) for i in range(threadnum): thread = threading.Thread(target=self.vuln_scan, args=(portQueue, threadnum)) thread.setDaemon(True) # 设置为后台线程,这里默认是False,设置为True之后则主线程不用等待子线程 thread.start() # 调用脚本 def vuln_scan(self, portQueue, threadnum): # print(portQueue.queue) #输出所有队列 while 1: try: if portQueue.empty() : # 队列空就结束 time.sleep(3) self.Ui.action_vuln_import.setEnabled(True) self.Ui.pushButton_vuln_file.setEnabled(True) self.Ui.action_vuln_start.setEnabled(True) self.Ui.pushButton_vuln_start.setEnabled(True) return else: all = portQueue.get() # 从队列中取出 url = all.split('$$$')[0] filename = all.split('$$$')[1] poc_methods = all.split('$$$')[2] # nnnnnnnnnnnn1 = importlib.import_module(poc_methods) nnnnnnnnnnnn1 = importlib.machinery.SourceFileLoader(poc_methods, filename).load_module() result = nnnnnnnnnnnn1.run(url) # print(result) result_url = url.replace("http://", "").replace("https://", "") self.Ui.textEdit_log.append( "[%s]Info:%s----%s----%s。" % ( (time.strftime('%H:%M:%S', time.localtime(time.time()))), result_url, result[0], result[2])) if result[2] != '不存在' and result[2] != '': row = self.Ui.tableWidget_vuln.rowCount() # 获取行数 self.Ui.tableWidget_vuln.setRowCount(row + 1) urlItem = QTableWidgetItem(result_url) nameItem = QTableWidgetItem(result[0]) payloadItem = QTableWidgetItem(result[1]) resultItem = QTableWidgetItem(result[2]) filenameItem = QTableWidgetItem(filename) self.Ui.tableWidget_vuln.setItem(row, 0, urlItem) self.Ui.tableWidget_vuln.setItem(row, 1, nameItem) self.Ui.tableWidget_vuln.setItem(row, 3, resultItem) self.Ui.tableWidget_vuln.setItem(row, 2, filenameItem) self.Ui.tableWidget_vuln.setItem(row, 4, payloadItem) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:%s脚本执行错误!\n[Exception]:\n%s" % ( (time.strftime('%H:%M:%S', time.localtime(time.time()))), filename, e)) pass # 初始化加载插件 def loadplugins(self): if os.path.isfile(DB_NAME): conn = sqlite3.connect(DB_NAME) else: box = QtWidgets.QMessageBox() box.warning(self, "提示", "数据文件不存在,正在重新加载数据库!") self.vuln_reload_Plugins() return 0 try: # 创建一个游标 curson cursor = conn.cursor() # 列出所有数据 sql = "SELECT cmsname,pocmethods from POC" cursor.execute(sql) values = cursor.fetchall() except Exception as e: box = QtWidgets.QMessageBox() box.warning(self, "提示", "数据文件错误:\n%s" % e) return 0 # 将查询的值组合为字典包含列表的形式 cms_name = {} for cms in values: cms_name[cms[0]] = [] for cms in values: if cms[0] in cms_name.keys(): cms_name[cms[0]].append(cms[1]) for cms in cms_name: # 设置root为self.treeWidget_Plugins的子树,故root是根节点 root = QTreeWidgetItem(self.Ui.treeWidget_Plugins) root.setText(0, cms) # 设置根节点的名称 root.setCheckState(0, Qt.Unchecked) # 开启复选框 for poc in cms_name[cms]: # 为root节点设置子结点 child1 = QTreeWidgetItem(root) child1.setText(0, poc) child1.setCheckState(0, Qt.Unchecked) self.Ui.treeWidget_Plugins.itemChanged.connect(self.handleChanged) self.Ui.treeWidget_Plugins.doubleClicked.connect(self.Show_Plugins_info) self.Ui.textEdit_log.append( "[%s]Success:插件加载完成,共%s个。" % (time.strftime('%H:%M:%S', time.localtime(time.time())), len(values))) def Show_Plugins_info(self): methods_name = self.Ui.treeWidget_Plugins.currentItem().text(0) conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() # 列出所有数据 sql = "SELECT * from POC where pocmethods='%s'"%methods_name cursor.execute(sql) values = cursor.fetchall() # print(values) try: self.dialog.close() except: pass if len(values) !=0: self.WChild_info = Ui_Plugins_information() self.dialog = QtWidgets.QDialog(self) self.WChild_info.setupUi(self.dialog) self.dialog.show() self.WChild_info.vuln_name.setText(values[0][3]) self.WChild_info.cms_name.setText(values[0][1]) self.WChild_info.plugins_methods.setText(values[0][6]) self.WChild_info.file_path.setText("Plugins/"+values[0][1]+'/'+values[0][2]) self.WChild_info.vuln_url.setText('<a href="'+values[0][4]+'">'+values[0][4]+'</a>') self.WChild_info.vuln_miaoshu.setText(values[0][5]) return 0 else: return # 父节点关联子节点 def handleChanged(self, item, column): count = item.childCount() # print dir(item) if item.checkState(column) == Qt.Checked: # print "checked", item, item.text(column) for f in range(count): item.child(f).setCheckState(0, Qt.Checked) if item.checkState(column) == Qt.Unchecked: # print "unchecked", item, item.text(column) for f in range(count): item.child(f).setCheckState(0, Qt.Unchecked) # self.Ui.treeWidget_Plugins.setSelectionMode(QAbstractItemView.ExtendedSelection) # 设置item可以多选 # self.tree.itemChanged.connect(self.handleChanged) # self.Ui.treeWidget_Plugins.addTopLevelItem(root) # 导入文件列表 def vuln_import_file(self): self.url_list = [] filename = self.file_open(r"Text Files (*.txt);;All files(*.*)") if os.path.isfile(filename): self.Ui.textEdit_log.append( "[%s]Info:正在从文件中读取URL..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) f = open(filename, 'r', encoding='utf-8') for line in f.readlines(): if 'http' in line: line = line.replace('\n', '').strip() self.url_list.append(line) self.Ui.textEdit_log.append( "[%s]Info:读取完成,共加载%s条。" % ( (time.strftime('%H:%M:%S', time.localtime(time.time()))), len(self.url_list))) self.Ui.lineEdit_vuln_url.setText(filename) # 导出扫描结果 def vuln_export_file(self): data = [] comdata = [] for i in range(0, self.Ui.tableWidget_vuln.rowCount()): # 循环行 for j in range(0, self.Ui.tableWidget_vuln.columnCount()): # 循环列 if self.Ui.tableWidget_vuln.item(i, j) != None: # 有数据 data.append(self.Ui.tableWidget_vuln.item(i, j).text()) # 空格分隔 comdata.append(list(data)) data = [] if len(comdata) > 0: path = (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '.csv').replace(' ', '-').replace('-','').replace( ':', '') # print(path) file_name = self.file_save(path) if file_name != "": with open(file_name, 'w', newline='') as f: writer = csv.writer(f) for row in comdata: writer.writerow(row) f.close() box = QtWidgets.QMessageBox() box.information(self, "Success", "导出成功!\n文件位置:"+file_name) else: box2= QtWidgets.QMessageBox() box2.warning(self, "Error", "保存失败!文件名错误!" ) else: self.Ui.textEdit_log.append( "[%s]Faile:没有扫描结果!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) # 显示插件 def vuln_ShowPlugins(self): self.widget = Ui_Form() self.dialog = QtWidgets.QDialog(self) self.widget.setupUi(self.dialog) self.dialog.setFixedSize(self.dialog.width(), self.dialog.height()) # 设置宽高不可变 # 设置查看插件表格属性 列宽度 self.widget.show_Plugins.setColumnWidth(0, 100) self.widget.show_Plugins.setColumnWidth(1, 350) self.widget.show_Plugins.setColumnWidth(2, 350) self.widget.show_Plugins.setColumnWidth(3, 383) self.widget.show_Plugins.setColumnWidth(4, 218) conn2 = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn2.cursor() # self.Ui.textEdit_log.append("[%s]Info:正在查询数据..."%(time.strftime('%H:%M:%S', time.localtime(time.time())))) # 列出所有数据 sql = "SELECT * from POC" cursor.execute(sql) values = cursor.fetchall() # self.Ui.textEdit_log.append("[%s]Success:数据查询成功!"%(time.strftime('%H:%M:%S', time.localtime(time.time())))) i = 0 self.widget.show_Plugins.setRowCount(len(values)) sql2 = "SELECT distinct cmsname from POC" cursor.execute(sql2) cms_name_data = cursor.fetchall() # 添加查询列表 for cms_name in cms_name_data: self.widget.show_Plugins_comboBox.addItem(cms_name[0]) # print(cms_name[0]) for single in values: vuln_name = QTableWidgetItem(str(single[1])) vuln_url = QTableWidgetItem(str(single[3])) vuln_payload = QTableWidgetItem(str(single[4])) vuln_result = QTableWidgetItem(str(single[5])) vuln_motheds = QTableWidgetItem(str(single[2])) self.widget.show_Plugins.setItem(i, 0, vuln_name) self.widget.show_Plugins.setItem(i, 1, vuln_url) self.widget.show_Plugins.setItem(i, 2, vuln_payload) self.widget.show_Plugins.setItem(i, 3, vuln_result) self.widget.show_Plugins.setItem(i, 4, vuln_motheds) i = i + 1 conn2.close() self.dialog.show() self.widget.show_Plugins_comboBox.currentIndexChanged.connect(self.show_plugins_go) # comboBox事件选中触发刷新 # 单击列表刷新显示控件 def show_plugins_go(self): self.widget.show_Plugins.clearContents() conn2 = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn2.cursor() cms_name = self.widget.show_Plugins_comboBox.currentText() # 获取文本 if cms_name == "ALL": sql = "SELECT * from POC " else: sql = "SELECT * from POC where cmsname = '%s'" % cms_name cursor.execute(sql) cms_data = cursor.fetchall() i = 0 self.widget.show_Plugins.setRowCount(len(cms_data)) for single in cms_data: vuln_name = QTableWidgetItem(str(single[1])) vuln_url = QTableWidgetItem(str(single[3])) vuln_payload = QTableWidgetItem(str(single[4])) vuln_result = QTableWidgetItem(str(single[5])) vuln_motheds = QTableWidgetItem(str(single[2])) self.widget.show_Plugins.setItem(i, 0, vuln_name) self.widget.show_Plugins.setItem(i, 1, vuln_url) self.widget.show_Plugins.setItem(i, 2, vuln_payload) self.widget.show_Plugins.setItem(i, 3, vuln_result) self.widget.show_Plugins.setItem(i, 4, vuln_motheds) i = i + 1 conn2.close() # 重新加载插件 def vuln_reload_Plugins(self): self.Ui.treeWidget_Plugins.clear() self.Ui.textEdit_log.setText("[%s]Start:正在重新加载插件..." % (time.strftime('%H:%M:%S', time.localtime(time.time())))) # 删除数据库,重新建立 if os.path.isfile(DB_NAME): try: # print(DB_NAME) os.remove(DB_NAME) except Exception as e: self.Ui.textEdit_log.append("[%s]Error:数据库文件删除失败!\n[Exception]:\n%s" % ( (time.strftime('%H:%M:%S', time.localtime(time.time()))), e)) return 0 self.Ui.textEdit_log.append( "[%s]Success:删除数据库完成!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) else: self.Ui.textEdit_log.append( "[%s]Success:数据库文件不存在,尝试创建数据库!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) try: # 连接数据库。如果数据库不存在的话,将会自动创建一个 数据库 conn = sqlite3.connect(DB_NAME) # 创建一个游标 curson cursor = conn.cursor() # 执行一条语句,创建 user表 如不存在创建 sql = "create table IF NOT EXISTS POC (id integer primary key autoincrement , cmsname varchar(30),pocfilename varchar(40),pocname varchar(30),pocreferer varchar(50),pocdescription varchar(200),pocmethods varchar(40))" cursor.execute(sql) self.Ui.textEdit_log.append( "[%s]Success:创建数据库完成!" % (time.strftime('%H:%M:%S', time.localtime(time.time())))) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:数据框创建失败!\n[Exception]:\n%s" % (time.strftime('%H:%M:%S', time.localtime(time.time())), e)) return 0 try: cms_path = "Plugins" cms_path = cms_path.replace("\\", "/") for cms_name in os.listdir(cms_path): # 遍历目录名 poc_path = os.path.join(cms_path, cms_name).replace("\\", "/") for path, dirs, poc_methos_list in os.walk(poc_path): # 遍历poc文件,得到方法名称 # print(path,dirs,poc_methos_list) for poc_file_name in poc_methos_list: # self.Ui.textEdit_log.append(poc_file_name[-3:]) # self.Ui.textEdit_log.append(poc_file_name) poc_name_path = cms_path + "\\" + cms_name + "\\" + poc_file_name poc_name_path = poc_name_path.replace("\\", "/") # print(poc_name_path) # 判断是py文件在打开 文件存在 if os.path.isfile(poc_name_path) and poc_file_name.endswith('.py'): # 判断py文件不包含. # print(poc_name_path) if '.' not in poc_file_name.replace(".py", ""): # print(poc_name_path) f = open(poc_name_path, "r", encoding="utf-8") # 获取poc的中文名称 # printSkyBlue(cms_name) poc_methos = "" # 定义局部变量 存放poc方法 poc_name = "" # 定义局部变量 存放poc名称 poc_referer = "" if cms_name[0:2] != "__": # 判断文件夹的前两位不是下划线 for name in f.readlines(): # print(name) # 得到中文poc_name if "name:" in name: poc_name = name.replace("name:", "").replace("\n", "").replace( "\r", "").replace("\r\n", "").strip() # print(poc_name) # 得到调用的poc_methos # self.Ui.textEdit_log.append(poc_methos) # 得到调用的poc_referer if "referer" in name: poc_referer = name.replace("referer:", "").replace("\n", "").replace( "\r", "").replace("\r\n", "").strip() # self.Ui.textEdit_log.append(poc_referer) # print(poc_referer) # 读取文件光标恢复到初始位置 f.seek(0) condata = f.read() ##所有数据 # print(condata) # 匹配描述 comment = re.compile(r"description:(.*?)'''", re.DOTALL) poc_description = str(comment.findall(condata)[0]).replace("\"", "").replace(" ", "") if poc_name != "" : poc_methos = poc_file_name[:-3] # print(poc_methos) # 将数据插入到表中 cursor.execute( 'insert into POC (cmsname, pocname,pocfilename,pocreferer,pocdescription,pocmethods) values ("%s","%s","%s","%s","%s","%s")' % ( cms_name, poc_name, poc_file_name, poc_referer, poc_description, poc_methos)) f.close() else: self.Ui.textEdit_log.append("[%s]Error:%s文件加载失败,文件名中不允许包含英文符号点!" % ( (time.strftime('%H:%M:%S', time.localtime(time.time())))( cms_name + "/" + poc_file_name))) return 0 else: pass conn.commit() # 提交 result = cursor.fetchall() if not len(result): cursor.execute("select count(*) from POC") values = cursor.fetchall() self.Ui.textEdit_log.append( "[%s]Success:共写入%s个插件" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), values[0][0])) self.loadplugins() # 调用加载插件 else: self.Ui.textEdit_log.append( "[%s]Error:数据更新失败,原因:" % (time.strftime('%H:%M:%S', time.localtime(time.time()))), str(result)) return 0 conn.close() box = QtWidgets.QMessageBox() box.information(self, "Load Plugins", "数据更新完成!\n插件数量:%s" % values[0][0]) # reboot = sys.executable # os.execl(reboot, reboot, *sys.argv) except Exception as e: self.Ui.textEdit_log.append( "[%s]Error:数据写入失败!\n[Exception]:\n%s" % ((time.strftime('%H:%M:%S', time.localtime(time.time()))), e)) return 0 def show_others(self,q): if q.text() =="关于": self.about() return if q.text() =="更新": self.version_update() return if q.text() =="意见反馈": self.ideas() return else: try: with open("QSS/" + json_qss[q.text()], 'r', encoding='utf-8') as f: qss_style = f.read() f.close() MainWindows.setStyleSheet(self, qss_style) f = open('QSS/Setup.txt', 'w', encoding='utf-8') f.write('{"QSS": "%s"}'%json_qss[q.text()]) f.close() python = sys.executable os.execl(python, python, *sys.argv) except Exception as e: QMessageBox.critical(self, 'Error', str(e)) pass # 关于 def about(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about(self, "About", "\t\t\tAbout\n 此程序为一款CMS扫描工具,可自行选择扫描的插件进行漏洞检查,请勿非法使用!\n\t\t\t Powered by qianxiao996") # 更新 def version_update(self): webbrowser.open("https://github.com/qianxiao996/FrameScan-GUI/releases") # 意见反馈 def ideas(self): box = QtWidgets.QMessageBox() box.setIcon(1) box.about(self, "意见反馈", "作者邮箱:[email protected]\n作者主页:http://blog.qianxiao996.cn") # 全选 def vuln_all(self): item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if item.value().checkState(0) != QtCore.Qt.Checked: item.value().setCheckState(0, Qt.Checked) item = item.__iadd__(1) # 反选 def vuln_noall(self): item = QtWidgets.QTreeWidgetItemIterator(self.Ui.treeWidget_Plugins) # 该类的value()即为QTreeWidgetItem while item.value(): if item.value().checkState(0) == QtCore.Qt.Checked: item.value().setCheckState(0, Qt.Unchecked) item = item.__iadd__(1) # 文件打开对话框 def file_open(self, type): fileName, selectedFilter = QFileDialog.getOpenFileName(self, (r"上传文件"),'', type) return (fileName) # 返回文件路径 # 保存文件对话框 def file_save(self, filename): fileName, filetype = QFileDialog.getSaveFileName(self, (r"保存文件"), (filename),r"All files(*.*)") return fileName