|
|
#!/usr/bin/env python
|
|
|
|
|
|
"""
|
|
|
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
|
|
|
See the file 'LICENSE' for copying permission
|
|
|
"""
|
|
|
|
|
|
from __future__ import print_function # 导入print_function特性,确保在Python 2和3中print函数的行为一致
|
|
|
|
|
|
try:
|
|
|
import sys # 导入sys模块,用于处理与Python解释器相关的操作
|
|
|
|
|
|
# 防止Python自动生成.pyc文件
|
|
|
sys.dont_write_bytecode = True # 设置不生成.pyc字节码文件,以减少磁盘空间占用和加载时间
|
|
|
|
|
|
try:
|
|
|
# 检查sqlmap的安装是否正确
|
|
|
__import__("lib.utils.versioncheck") # 动态导入lib.utils.versioncheck模块,通常用于检查版本兼容性
|
|
|
except ImportError: # 如果导入失败(例如模块不存在),则执行以下代码
|
|
|
sys.exit("[!] wrong installation detected (missing modules). Visit 'https://github.com/sqlmapproject/sqlmap/#installation' for further details") # 退出程序并提示安装错误,建议用户访问指定链接查看安装说明
|
|
|
|
|
|
# 导入标准库模块
|
|
|
import bdb # 导入bdb模块,用于调试器支持
|
|
|
import glob # 导入glob模块,用于文件路径匹配
|
|
|
import inspect # 导入inspect模块,用于获取对象信息
|
|
|
import json # 导入json模块,用于处理JSON数据
|
|
|
import logging # 导入logging模块,用于记录日志信息
|
|
|
import os # 导入os模块,用于与操作系统进行交互
|
|
|
import re # 导入re模块,用于正则表达式操作
|
|
|
import shutil # 导入shutil模块,用于文件操作(如复制、删除等)
|
|
|
import sys # 再次导入sys模块,确保其可用性
|
|
|
import tempfile # 导入tempfile模块,用于创建临时文件和目录
|
|
|
import threading # 导入threading模块,用于多线程支持
|
|
|
import time # 导入time模块,用于时间相关操作
|
|
|
import traceback # 导入traceback模块,用于获取异常信息
|
|
|
import warnings # 导入warnings模块,用于处理警告信息
|
|
|
|
|
|
# 忽略DeprecationWarning,除非命令行参数中包含"--deprecations"
|
|
|
if "--deprecations" not in sys.argv: # 如果命令行参数中不包含"--deprecations"
|
|
|
warnings.filterwarnings(action="ignore", category=DeprecationWarning) # 忽略所有DeprecationWarning类别的警告
|
|
|
else: # 如果命令行参数中包含"--deprecations"
|
|
|
warnings.resetwarnings() # 重置警告过滤器
|
|
|
warnings.filterwarnings(action="ignore", message="'crypt'", category=DeprecationWarning) # 忽略特定消息的DeprecationWarning
|
|
|
warnings.simplefilter("ignore", category=ImportWarning) # 忽略所有ImportWarning类别的警告
|
|
|
if sys.version_info >= (3, 0): # 如果Python版本大于等于3.0
|
|
|
warnings.simplefilter("ignore", category=ResourceWarning) # 忽略所有ResourceWarning类别的警告
|
|
|
|
|
|
# 忽略特定警告
|
|
|
warnings.filterwarnings(action="ignore", message="Python 2 is no longer supported") # 忽略关于Python 2不再支持的警告
|
|
|
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning) # 忽略关于模块已导入的UserWarning
|
|
|
warnings.filterwarnings(action="ignore", message=".*using a very old release", category=UserWarning) # 忽略关于使用旧版本的UserWarning
|
|
|
warnings.filterwarnings(action="ignore", message=".*default buffer size will be used", category=RuntimeWarning) # 忽略关于默认缓冲区大小的RuntimeWarning
|
|
|
warnings.filterwarnings(action="ignore", category=UserWarning, module="psycopg2") # 忽略psycopg2模块的UserWarning
|
|
|
|
|
|
# 导入sqlmap的核心日志模块
|
|
|
from lib.core.data import logger # 从lib.core.data模块导入logger对象,用于记录日志信息
|
|
|
|
|
|
# 导入sqlmap的核心功能模块
|
|
|
from lib.core.common import banner # 从lib.core.common模块导入banner函数,用于显示程序横幅
|
|
|
from lib.core.common import checkPipedInput # 从lib.core.common模块导入checkPipedInput函数,用于检查管道输入
|
|
|
from lib.core.common import checkSums # 从lib.core.common模块导入checkSums函数,用于校验文件哈希值
|
|
|
from lib.core.common import createGithubIssue # 从lib.core.common模块导入createGithubIssue函数,用于创建GitHub问题
|
|
|
from lib.core.common import dataToStdout # 从lib.core.common模块导入dataToStdout函数,用于将数据输出到标准输出
|
|
|
from lib.core.common import extractRegexResult # 从lib.core.common模块导入extractRegexResult函数,用于提取正则表达式匹配结果
|
|
|
from lib.core.common import filterNone # 从lib.core.common模块导入filterNone函数,用于过滤None值
|
|
|
from lib.core.common import getDaysFromLastUpdate # 从lib.core.common模块导入getDaysFromLastUpdate函数,用于计算自上次更新以来的天数
|
|
|
from lib.core.common import getFileItems # 从lib.core.common模块导入getFileItems函数,用于从文件中读取内容
|
|
|
from lib.core.common import getSafeExString # 从lib.core.common模块导入getSafeExString函数,用于安全地获取异常信息
|
|
|
from lib.core.common import maskSensitiveData # 从lib.core.common模块导入maskSensitiveData函数,用于屏蔽敏感数据
|
|
|
from lib.core.common import openFile # 从lib.core.common模块导入openFile函数,用于打开文件
|
|
|
from lib.core.common import setPaths # 从lib.core.common模块导入setPaths函数,用于设置文件路径
|
|
|
from lib.core.common import weAreFrozen # 从lib.core.common模块导入weAreFrozen函数,用于检查程序是否被冻结(打包)
|
|
|
from lib.core.convert import getUnicode # 从lib.core.convert模块导入getUnicode函数,用于将字符串转换为Unicode格式
|
|
|
from lib.core.common import setColor # 从lib.core.common模块导入setColor函数,用于设置输出颜色
|
|
|
from lib.core.common import unhandledExceptionMessage # 从lib.core.common模块导入unhandledExceptionMessage函数,用于处理未捕获的异常信息
|
|
|
from lib.core.compat import LooseVersion # 从lib.core.compat模块导入LooseVersion类,用于版本号比较
|
|
|
from lib.core.compat import xrange # 从lib.core.compat模块导入xrange函数,用于兼容Python 2和3的range函数
|
|
|
from lib.core.data import cmdLineOptions # 从lib.core.data模块导入cmdLineOptions对象,用于存储命令行选项
|
|
|
from lib.core.data import conf # 从lib.core.data模块导入conf对象,用于存储配置信息
|
|
|
from lib.core.data import kb # 从lib.core.data模块导入kb对象,用于存储知识库信息
|
|
|
from lib.core.datatype import OrderedSet # 从lib.core.datatype模块导入OrderedSet类,用于存储有序集合
|
|
|
from lib.core.enums import MKSTEMP_PREFIX # 从lib.core.enums模块导入MKSTEMP_PREFIX常量,表示临时文件前缀
|
|
|
from lib.core.exception import SqlmapBaseException # 从lib.core.exception模块导入SqlmapBaseException类,表示sqlmap的基础异常
|
|
|
from lib.core.exception import SqlmapShellQuitException # 从lib.core.exception模块导入SqlmapShellQuitException类,表示shell退出异常
|
|
|
from lib.core.exception import SqlmapSilentQuitException # 从lib.core.exception模块导入SqlmapSilentQuitException类,表示静默退出异常
|
|
|
from lib.core.exception import SqlmapUserQuitException # 从lib.core.exception模块导入SqlmapUserQuitException类,表示用户退出异常
|
|
|
from lib.core.option import init # 从lib.core.option模块导入init函数,用于初始化选项
|
|
|
from lib.core.option import initOptions # 从lib.core.option模块导入initOptions函数,用于初始化命令行选项
|
|
|
from lib.core.patch import dirtyPatches # 从lib.core.patch模块导入dirtyPatches函数,用于应用临时补丁
|
|
|
from lib.core.patch import resolveCrossReferences # 从lib.core.patch模块导入resolveCrossReferences函数,用于解决交叉引用问题
|
|
|
from lib.core.settings import GIT_PAGE # 从lib.core.settings模块导入GIT_PAGE常量,表示GitHub页面地址
|
|
|
from lib.core.settings import IS_WIN # 从lib.core.settings模块导入IS_WIN常量,表示当前操作系统是否为Windows
|
|
|
from lib.core.settings import LAST_UPDATE_NAGGING_DAYS # 从lib.core.settings模块导入LAST_UPDATE_NAGGING_DAYS常量,表示提醒更新的天数
|
|
|
from lib.core.settings import LEGAL_DISCLAIMER # 从lib.core.settings模块导入LEGAL_DISCLAIMER常量,表示法律声明
|
|
|
from lib.core.settings import THREAD_FINALIZATION_TIMEOUT # 从lib.core.settings模块导入THREAD_FINALIZATION_TIMEOUT常量,表示线程结束的超时时间
|
|
|
from lib.core.settings import UNICODE_ENCODING # 从lib.core.settings模块导入UNICODE_ENCODING常量,表示默认的Unicode编码
|
|
|
from lib.core.settings import VERSION # 从lib.core.settings模块导入VERSION常量,表示程序版本号
|
|
|
from lib.parse.cmdline import cmdLineParser # 从lib.parse.cmdline模块导入cmdLineParser函数,用于解析命令行参数
|
|
|
from lib.utils.crawler import crawl # 从lib.utils.crawler模块导入crawl函数,用于爬取数据
|
|
|
except Exception as ex: # 捕获所有异常
|
|
|
print("An error occurred: " + str(ex)) # 打印异常信息
|
|
|
except KeyboardInterrupt: # 捕获用户中断(如按下Ctrl+C)
|
|
|
errMsg = "user aborted" # 定义错误信息
|
|
|
|
|
|
if "logger" in globals(): # 如果logger对象已定义
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
else: # 如果logger对象未定义
|
|
|
import time # 导入time模块
|
|
|
sys.exit("\r[%s] [CRITICAL] %s" % (time.strftime("%X"), errMsg)) # 退出程序并打印错误信息,包含当前时间
|
|
|
|
|
|
def modulePath(): # 定义modulePath函数,用于获取程序的目录路径
|
|
|
"""
|
|
|
获取程序的目录路径,即使使用了 py2exe 进行冻结打包也能正确获取。
|
|
|
|
|
|
返回值:
|
|
|
返回程序所在目录的Unicode编码路径字符串。
|
|
|
"""
|
|
|
try:
|
|
|
# 如果程序被py2exe冻结,则使用sys.executable获取路径;否则使用__file__获取
|
|
|
_ = sys.executable if weAreFrozen() else __file__ # 如果程序被冻结,使用sys.executable获取路径;否则使用__file__获取当前文件路径
|
|
|
except NameError: # 如果__file__未定义(在某些环境下可能发生),则执行以下代码
|
|
|
# 如果__file__未定义(在某些环境下可能发生),则使用inspect模块获取当前函数的文件路径
|
|
|
_ = inspect.getsourcefile(modulePath) # 使用inspect模块获取当前函数的源文件路径
|
|
|
|
|
|
# 获取_的目录路径,并转换为Unicode编码
|
|
|
return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING) # 返回_的目录路径,并将其转换为Unicode编码
|
|
|
|
|
|
def checkEnvironment(): # 定义checkEnvironment函数,用于检查运行环境是否适合运行sqlmap
|
|
|
"""
|
|
|
检查运行环境是否适合运行 sqlmap。
|
|
|
|
|
|
如果在检查过程中发现问题,则会记录错误信息并退出程序。
|
|
|
"""
|
|
|
try:
|
|
|
# 检查程序目录是否存在
|
|
|
os.path.isdir(modulePath()) # 检查modulePath函数返回的路径是否为目录
|
|
|
except UnicodeEncodeError: # 如果系统无法正确处理非ASCII路径,则执行以下代码
|
|
|
# 如果系统无法正确处理非ASCII路径,则记录错误信息并退出
|
|
|
errMsg = "your system does not properly handle non-ASCII paths. " # 定义错误信息,提示系统无法处理非ASCII路径
|
|
|
errMsg += "Please move the sqlmap's directory to the other location" # 建议用户将sqlmap目录移动到其他位置
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查sqlmap的版本是否低于1.0,如果是,则说明运行环境有问题
|
|
|
if LooseVersion(VERSION) < LooseVersion("1.0"): # 如果当前版本低于1.0
|
|
|
errMsg = "your runtime environment (e.g. PYTHONPATH) is " # 定义错误信息,提示运行环境有问题
|
|
|
errMsg += "broken. Please make sure that you are not running " # 建议用户检查是否使用了旧版本的运行脚本
|
|
|
errMsg += "newer versions of sqlmap with runtime scripts for older " # 提示用户不要使用旧版本的运行脚本运行新版本的sqlmap
|
|
|
errMsg += "versions" # 提示用户检查运行环境
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果是通过pip安装的sqlmap,则需要对sys.modules进行一些修补操作
|
|
|
if "sqlmap.sqlmap" in sys.modules: # 如果sqlmap.sqlmap模块已加载
|
|
|
for _ in ("cmdLineOptions", "conf", "kb"): # 遍历需要修补的变量名
|
|
|
# 将lib.core.data模块中的cmdLineOptions、conf、kb变量添加到全局变量中
|
|
|
globals()[_] = getattr(sys.modules["lib.core.data"], _) # 将lib.core.data模块中的变量添加到全局变量中
|
|
|
|
|
|
for _ in ("SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException", "SqlmapUserQuitException"): # 遍历需要修补的异常类名
|
|
|
# 将lib.core.exception模块中的异常类添加到全局变量中
|
|
|
globals()[_] = getattr(sys.modules["lib.core.exception"], _) # 将lib.core.exception模块中的异常类添加到全局变量中
|
|
|
|
|
|
def main():
|
|
|
"""
|
|
|
当从命令行运行时,这是 sqlmap 的主函数。
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
# 应用脏补丁和解析交叉引用
|
|
|
dirtyPatches() # 应用一些临时的修复或补丁
|
|
|
resolveCrossReferences() # 解析并处理代码中的交叉引用
|
|
|
|
|
|
# 检查运行环境并设置程序路径
|
|
|
checkEnvironment() # 检查当前运行环境是否满足要求
|
|
|
setPaths(modulePath()) # 设置程序的路径
|
|
|
banner() # 显示程序的横幅信息
|
|
|
|
|
|
# 解析命令行参数并更新全局配置
|
|
|
args = cmdLineParser() # 解析命令行参数
|
|
|
cmdLineOptions.update(args.__dict__ if hasattr(args, "__dict__") else args) # 更新全局命令行选项
|
|
|
initOptions(cmdLineOptions) # 初始化全局配置选项
|
|
|
|
|
|
# 如果有管道输入,则设置批量模式
|
|
|
if checkPipedInput(): # 检查是否有管道输入
|
|
|
conf.batch = True # 如果有管道输入,则设置批量模式为True
|
|
|
|
|
|
# 如果配置了API,设置API日志和重定向标准输出和错误
|
|
|
if conf.get("api"): # 检查是否配置了API
|
|
|
# 延迟导入(重量级导入)
|
|
|
from lib.utils.api import StdDbOut # 导入StdDbOut类,用于重定向标准输出和错误
|
|
|
from lib.utils.api import setRestAPILog # 导入setRestAPILog函数,用于设置API日志
|
|
|
|
|
|
# 重定向标准输出和错误到IPC数据库
|
|
|
sys.stdout = StdDbOut(conf.taskid, messagetype="stdout") # 重定向标准输出到IPC数据库
|
|
|
sys.stderr = StdDbOut(conf.taskid, messagetype="stderr") # 重定向标准错误到IPC数据库
|
|
|
|
|
|
setRestAPILog() # 设置API日志
|
|
|
|
|
|
# 设置显示时间并显示法律声明和启动信息
|
|
|
conf.showTime = True # 设置显示时间
|
|
|
dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True) # 显示法律声明
|
|
|
dataToStdout("[*] starting @ %s\n\n" % time.strftime("%X /%Y-%m-%d/"), forceOutput=True) # 显示启动信息
|
|
|
|
|
|
# 初始化程序
|
|
|
init() # 调用初始化函数,完成程序的初始化工作
|
|
|
|
|
|
# 如果没有设置更新所有选项,则执行后续操作
|
|
|
if not conf.updateAll: # 检查是否设置了更新所有选项
|
|
|
# 延迟导入(更快的启动)
|
|
|
if conf.smokeTest: # 检查是否设置了烟雾测试
|
|
|
# 运行烟雾测试
|
|
|
from lib.core.testing import smokeTest # 导入烟雾测试函数
|
|
|
os._exitcode = 1 - (smokeTest() or 0) # 运行烟雾测试并设置退出码
|
|
|
elif conf.vulnTest: # 检查是否设置了漏洞测试
|
|
|
# 运行漏洞测试
|
|
|
from lib.core.testing import vulnTest # 导入漏洞测试函数
|
|
|
os._exitcode = 1 - (vulnTest() or 0) # 运行漏洞测试并设置退出码
|
|
|
else:
|
|
|
# 启动sqlmap控制器
|
|
|
from lib.controller.controller import start # 导入启动控制器函数
|
|
|
if conf.profile: # 检查是否设置了性能分析
|
|
|
# 如果设置了性能分析,则进行性能分析
|
|
|
from lib.core.profiling import profile # 导入性能分析函数
|
|
|
globals()["start"] = start # 将start函数添加到全局命名空间
|
|
|
profile() # 运行性能分析
|
|
|
else:
|
|
|
try:
|
|
|
# 如果设置了爬取深度和批量文件,则开始爬取
|
|
|
if conf.crawlDepth and conf.bulkFile: # 检查是否设置了爬取深度和批量文件
|
|
|
targets = getFileItems(conf.bulkFile) # 从批量文件中获取目标列表
|
|
|
|
|
|
for i in xrange(len(targets)): # 遍历目标列表
|
|
|
target = None # 初始化目标变量
|
|
|
|
|
|
try:
|
|
|
kb.targets = OrderedSet() # 初始化目标集合
|
|
|
target = targets[i] # 获取当前目标
|
|
|
|
|
|
if not re.search(r"(?i)\Ahttp[s]*://", target): # 检查目标是否包含协议
|
|
|
target = "http://%s" % target # 如果没有协议,则添加默认的HTTP协议
|
|
|
|
|
|
infoMsg = "starting crawler for target URL '%s' (%d/%d)" % (target, i + 1, len(targets)) # 生成日志信息
|
|
|
logger.info(infoMsg) # 记录日志信息
|
|
|
|
|
|
crawl(target) # 开始爬取目标
|
|
|
except Exception as ex: # 捕获异常
|
|
|
if target and not isinstance(ex, SqlmapUserQuitException): # 检查异常类型
|
|
|
errMsg = "problem occurred while crawling '%s' ('%s')" % (target, getSafeExString(ex)) # 生成错误信息
|
|
|
logger.error(errMsg) # 记录错误信息
|
|
|
else:
|
|
|
raise # 重新抛出异常
|
|
|
else:
|
|
|
if kb.targets: # 检查目标集合是否非空
|
|
|
start() # 启动控制器
|
|
|
else:
|
|
|
start() # 如果没有设置爬取深度和批量文件,则直接启动控制器
|
|
|
except Exception as ex: # 捕获异常
|
|
|
os._exitcode = 1 # 设置退出码为1
|
|
|
|
|
|
# 如果无法启动新线程,则记录错误信息并退出
|
|
|
if "can't start new thread" in getSafeExString(ex): # 检查异常信息是否包含无法启动新线程
|
|
|
errMsg = "unable to start new threads. Please check OS (u)limits" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
else:
|
|
|
raise # 重新抛出异常
|
|
|
|
|
|
# 捕获并处理各种异常,记录错误信息并退出
|
|
|
except SqlmapUserQuitException: # 捕获用户主动退出的异常
|
|
|
if not conf.batch: # 检查是否处于批量模式
|
|
|
errMsg = "user quit" # 生成错误信息
|
|
|
logger.error(errMsg) # 记录错误信息
|
|
|
|
|
|
except (SqlmapSilentQuitException, bdb.BdbQuit): # 捕获静默退出或调试器退出的异常
|
|
|
pass # 不处理,直接跳过
|
|
|
|
|
|
except SqlmapShellQuitException: # 捕获SQLMap Shell退出的异常
|
|
|
cmdLineOptions.sqlmapShell = False # 设置SQLMap Shell选项为False
|
|
|
|
|
|
except SqlmapBaseException as ex: # 捕获SQLMap基础异常
|
|
|
errMsg = getSafeExString(ex) # 获取安全的异常信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
|
|
|
os._exitcode = 1 # 设置退出码为1
|
|
|
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
except KeyboardInterrupt: # 捕获键盘中断异常(如Ctrl+C)
|
|
|
try:
|
|
|
print() # 打印空行
|
|
|
except IOError: # 捕获IO错误
|
|
|
pass # 不处理,直接跳过
|
|
|
|
|
|
except EOFError: # 捕获文件结束异常(如Ctrl+D)
|
|
|
print() # 打印空行
|
|
|
|
|
|
errMsg = "exit" # 生成错误信息
|
|
|
logger.error(errMsg) # 记录错误信息
|
|
|
|
|
|
except SystemExit as ex: # 捕获系统退出异常
|
|
|
os._exitcode = ex.code or 0 # 设置退出码为异常代码或0
|
|
|
|
|
|
except: # 捕获所有其他异常
|
|
|
print() # 打印空行
|
|
|
errMsg = unhandledExceptionMessage() # 获取未处理异常的信息
|
|
|
excMsg = traceback.format_exc() # 获取异常的详细堆栈信息
|
|
|
valid = checkSums() # 检查校验和
|
|
|
|
|
|
os._exitcode = 255 # 设置退出码为255
|
|
|
|
|
|
# 如果异常信息中包含内存耗尽相关的消息,则记录内存耗尽错误并退出
|
|
|
if any(_ in excMsg for _ in ("MemoryError", "Cannot allocate memory")): # 检查异常信息是否包含内存耗尽
|
|
|
errMsg = "memory exhaustion detected" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含磁盘空间不足相关的消息,则记录磁盘空间错误并退出
|
|
|
elif any(_ in excMsg for _ in ("No space left", "Disk quota exceeded", "Disk full while accessing")): # 检查异常信息是否包含磁盘空间不足
|
|
|
errMsg = "no space left on output device" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含分页文件空间不足的消息,则记录分页文件空间错误并退出
|
|
|
elif any(_ in excMsg for _ in ("The paging file is too small",)): # 检查异常信息是否包含分页文件空间不足
|
|
|
errMsg = "no space left for paging file" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含权限拒绝和Metasploit相关的消息,则记录Metasploit权限错误并退出
|
|
|
elif all(_ in excMsg for _ in ("Access is denied", "subprocess", "metasploit")): # 检查异常信息是否包含Metasploit权限错误
|
|
|
errMsg = "permission error occurred while running Metasploit" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含权限拒绝和metasploit相关的消息,则记录Metasploit权限错误并退出
|
|
|
elif all(_ in excMsg for _ in ("Permission denied", "metasploit")): # 检查异常信息是否包含Metasploit权限错误
|
|
|
errMsg = "permission error occurred while using Metasploit" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含只读文件系统的消息,则记录只读文件系统错误并退出
|
|
|
elif "Read-only file system" in excMsg: # 检查异常信息是否包含只读文件系统
|
|
|
errMsg = "output device is mounted as read-only" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含系统资源不足的消息,则记录资源耗尽错误并退出
|
|
|
elif "Insufficient system resources" in excMsg: # 检查异常信息是否包含系统资源不足
|
|
|
errMsg = "resource exhaustion detected" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含磁盘I/O错误的消息,则记录I/O错误并退出
|
|
|
elif "OperationalError: disk I/O error" in excMsg: # 检查异常信息是否包含磁盘I/O错误
|
|
|
errMsg = "I/O error on output device" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含URL违反BIDI规则的消息,则记录无效URL错误并退出
|
|
|
elif "Violation of BIDI" in excMsg: # 检查异常信息是否包含URL违反BIDI规则
|
|
|
errMsg = "invalid URL (violation of Bidi IDNA rule - RFC 5893)" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含无效IPv6 URL的消息,则记录无效URL错误并退出
|
|
|
elif "Invalid IPv6 URL" in excMsg: # 检查异常信息是否包含无效IPv6 URL
|
|
|
errMsg = "invalid URL ('%s')" % excMsg.strip().split('\n')[-1] # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
|
|
|
# 如果异常信息中包含临时文件访问问题的消息,则记录临时文件访问错误并退出
|
|
|
elif "_mkstemp_inner" in excMsg: # 检查异常信息是否包含临时文件访问问题
|
|
|
errMsg = "there has been a problem while accessing temporary files" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含无法写入临时目录的消息,则记录临时目录写入错误并退出
|
|
|
elif any(_ in excMsg for _ in ("tempfile.mkdtemp", "tempfile.mkstemp", "tempfile.py")): # 检查异常信息是否包含临时目录写入问题
|
|
|
errMsg = "unable to write to the temporary directory '%s'. " % tempfile.gettempdir() # 生成错误信息
|
|
|
errMsg += "Please make sure that your disk is not full and " # 添加提示信息
|
|
|
errMsg += "that you have sufficient write permissions to " # 添加提示信息
|
|
|
errMsg += "create temporary files and/or directories" # 添加提示信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含权限拒绝的消息,则记录文件访问权限错误并退出
|
|
|
elif "Permission denied: '" in excMsg: # 检查异常信息是否包含权限拒绝
|
|
|
match = re.search(r"Permission denied: '([^']*)", excMsg) # 提取被拒绝访问的文件路径
|
|
|
errMsg = "permission error occurred while accessing file '%s'" % match.group(1) # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含sqlalchemy包版本问题的消息,则记录sqlalchemy版本错误并退出
|
|
|
elif all(_ in excMsg for _ in ("twophase", "sqlalchemy")): # 检查异常信息是否包含sqlalchemy版本问题
|
|
|
errMsg = "please update the 'sqlalchemy' package (>= 1.1.11) " # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含Python版本问题的消息,则记录Python版本错误并退出
|
|
|
elif "invalid maximum character passed to PyUnicode_New" in excMsg and re.search(r"\A3\.[34]", sys.version) is not None: # 检查异常信息是否包含Python版本问题
|
|
|
errMsg = "please upgrade the Python version (>= 3.5) " # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含PyMySQL包版本问题的消息,则记录PyMySQL版本错误并退出
|
|
|
elif all(_ in excMsg for _ in ("scramble_caching_sha2", "TypeError")): # 检查异常信息是否包含PyMySQL版本问题
|
|
|
errMsg = "please downgrade the 'PyMySQL' package (=< 0.8.1) " # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果异常信息中包含Python解
|
|
|
# 假设excMsg是一个包含异常信息的字符串变量
|
|
|
|
|
|
# 检查excMsg是否包含"pymysql"和"configparser"这两个字符串
|
|
|
elif all(_ in excMsg for _ in ("pymysql", "configparser")): # 检查异常信息是否包含pymysql和configparser
|
|
|
errMsg = "wrong initialization of 'pymsql' detected (using Python3 dependencies)" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查excMsg是否包含"ntlm"、"socket.error, err"和"SyntaxError"这三个字符串
|
|
|
elif all(_ in excMsg for _ in ("ntlm", "socket.error, err", "SyntaxError")): # 检查异常信息是否包含ntlm、socket.error和SyntaxError
|
|
|
errMsg = "wrong initialization of 'python-ntlm' detected (using Python2 syntax)" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查excMsg是否包含"drda"和"to_bytes"这两个字符串
|
|
|
elif all(_ in excMsg for _ in ("drda", "to_bytes")): # 检查异常信息是否包含drda和to_bytes
|
|
|
errMsg = "wrong initialization of 'drda' detected (using Python3 syntax)" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查excMsg是否包含特定的错误信息,即'WebSocket'对象没有'status'属性
|
|
|
elif "'WebSocket' object has no attribute 'status'" in excMsg: # 检查异常信息是否包含WebSocket对象缺少status属性
|
|
|
errMsg = "wrong websocket library detected" # 生成错误信息
|
|
|
errMsg += " (Reference: 'https://github.com/sqlmapproject/sqlmap/issues/4572#issuecomment-775041086')" # 添加参考链接
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查excMsg是否包含特定的错误信息,即初始化GUI界面时出现问题
|
|
|
elif all(_ in excMsg for _ in ("window = tkinter.Tk()",)): # 检查异常信息是否包含GUI初始化问题
|
|
|
errMsg = "there has been a problem in initialization of GUI interface " # 生成错误信息
|
|
|
errMsg += "('%s')" % excMsg.strip().split('\n')[-1] # 添加具体错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查excMsg是否包含特定的错误信息,即使用了不同版本的sqlmap文件
|
|
|
elif any(_ in excMsg for _ in ("unable to access item 'liveTest'",)): # 检查异常信息是否包含不同版本sqlmap文件问题
|
|
|
errMsg = "detected usage of files from different versions of sqlmap" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查errMsg是否包含特定的错误信息,即版本号相关的错误
|
|
|
elif any(_ in errMsg for _ in (": 9.9.9#",)): # 检查错误信息是否包含特定版本号
|
|
|
errMsg = "LOL xD" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查是否设置了键盘中断的标记
|
|
|
elif kb.get("dumpKeyboardInterrupt"): # 检查是否设置了键盘中断标记
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查excMsg是否包含特定的错误信息,即"Broken pipe"
|
|
|
elif any(_ in excMsg for _ in ("Broken pipe",)): # 检查异常信息是否包含Broken pipe
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查valid变量是否为False
|
|
|
elif valid is False: # 检查校验和是否无效
|
|
|
errMsg = "code checksum failed (turning off automatic issue creation). " # 生成错误信息
|
|
|
errMsg += "You should retrieve the latest development version from official GitHub " # 添加提示信息
|
|
|
errMsg += "repository at '%s'" % GIT_PAGE # 添加GitHub仓库链接
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
print() # 打印空行
|
|
|
dataToStdout(excMsg) # 输出异常信息到标准输出
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查errMsg和excMsg组合后是否包含特定的错误信息,即文件路径或特定参数
|
|
|
elif any(_ in "%s\n%s" % (errMsg, excMsg) for _ in ("tamper/", "waf/", "--engagement-dojo")): # 检查错误信息是否包含特定路径或参数
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
print() # 打印空行
|
|
|
dataToStdout(excMsg) # 输出异常信息到标准输出
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 检查错误信息中是否包含特定的错误关键词,如果包含,则认为是运行时环境错误,并提取错误信息的最后部分。
|
|
|
elif any(_ in excMsg for _ in ("ImportError", "ModuleNotFoundError", "<frozen", "Can't find file for module", "SAXReaderNotAvailable", "<built-in function compile> returned NULL without setting an exception", "source code string cannot contain null bytes", "No module named", "tp_name field", "module 'sqlite3' has no attribute 'OperationalError'")): # 检查异常信息是否包含运行时环境错误
|
|
|
errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含非ASCII字符编码错误,则认为是运行时环境错误,并提取错误信息的最后部分。
|
|
|
elif all(_ in excMsg for _ in ("SyntaxError: Non-ASCII character", ".py on line", "but no encoding declared")): # 检查异常信息是否包含非ASCII字符编码错误
|
|
|
errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含文件不存在的错误,则认为是运行时环境错误,并提取错误信息的最后部分。
|
|
|
elif all(_ in excMsg for _ in ("FileNotFoundError: [Errno 2] No such file or directory", "cwd = os.getcwd()")): # 检查异常信息是否包含文件不存在错误
|
|
|
errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含权限错误,则提示用户可能存在权限问题,并建议重新运行程序时禁用多进程。
|
|
|
elif all(_ in excMsg for _ in ("PermissionError: [WinError 5]", "multiprocessing")): # 检查异常信息是否包含权限错误
|
|
|
errMsg = "there is a permission problem in running multiprocessing on this system. " # 生成错误信息
|
|
|
errMsg += "Please rerun with '--disable-multi'" # 添加建议信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含文件不存在的错误,则提示用户安装可能已损坏,并建议从官方GitHub仓库获取最新开发版本。
|
|
|
elif all(_ in excMsg for _ in ("No such file", "_'")): # 检查异常信息是否包含文件不存在错误
|
|
|
errMsg = "corrupted installation detected ('%s'). " % excMsg.strip().split('\n')[-1] # 生成错误信息
|
|
|
errMsg += "You should retrieve the latest development version from official GitHub " # 添加提示信息
|
|
|
errMsg += "repository at '%s'" % GIT_PAGE # 添加GitHub仓库链接
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含尝试在生产环境中运行开发测试的错误,则输出相应的错误信息。
|
|
|
elif all(_ in excMsg for _ in ("No such file", "sqlmap.conf", "Test")): # 检查异常信息是否包含在生产环境中运行开发测试的错误
|
|
|
errMsg = "you are trying to run (hidden) development tests inside the production environment" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含HTTP NTLM认证相关的兼容性问题,则输出相应的错误信息,并提供参考链接。
|
|
|
elif all(_ in excMsg for _ in ("HTTPNtlmAuthHandler", "'str' object has no attribute 'decode'")): # 检查异常信息是否包含HTTP NTLM认证兼容性问题
|
|
|
errMsg = "package 'python-ntlm' has a known compatibility issue with the " # 生成错误信息
|
|
|
errMsg += "Python 3 (Reference: 'https://github.com/mullender/python-ntlm/pull/61')" " # 添加参考链接
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含字典对象属性错误,并且与枚举相关,则提示用户可能存在枚举问题,并建议重新运行程序时刷新会话。
|
|
|
elif "'DictObject' object has no attribute '" in excMsg and all(_ in errMsg for _ in ("(fingerprinted)", "(identified)")): # 检查异常信息是否包含字典对象属性错误
|
|
|
errMsg = "there has been a problem in enumeration. " # 生成错误信息
|
|
|
errMsg += "Because of a considerable chance of false-positive case " # 添加提示信息
|
|
|
errMsg += "you are advised to rerun with switch '--flush-session'" # 添加建议信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含数据库磁盘映像损坏的错误,则提示用户会话文件可能损坏,并建议刷新会话。
|
|
|
elif "database disk image is malformed" in excMsg: # 检查异常信息是否包含数据库磁盘映像损坏
|
|
|
errMsg = "local session file seems to be malformed. Please rerun with '--flush-session'" # 生成错误信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 如果错误信息包含模块属性错误,则认为是运行时环境错误,并提取错误信息的最后部分。
|
|
|
elif "AttributeError: 'module' object has no attribute 'F_GETFD'" in excMsg: # 检查异常信息是否包含模块属性错误
|
|
|
errMsg = "invalid runtime (\"%s\") " % excMsg.split("Error: ")[-1].strip() # 生成错误信息
|
|
|
errMsg += "(Reference: 'https://stackoverflow.com/a/38841364' & 'https://bugs.python.org/issue24944#msg249231')" " # 添加参考链接
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
|
|
|
# 如果错误信息包含marshal数据错误,则提示用户.pyc文件可能损坏,并建议删除.pyc文件来解决问题。
|
|
|
elif "bad marshal data (unknown type code)" in excMsg: # 检查异常信息是否包含marshal数据错误
|
|
|
match = re.search(r"\s*(.+)\s+ValueError", excMsg) # 提取损坏的文件路径
|
|
|
errMsg = "one of your .pyc files are corrupted%s" % (" ('%s')" % match.group(1) if match else "") # 生成错误信息
|
|
|
errMsg += ". Please delete .pyc files on your system to fix the problem" # 添加建议信息
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
raise SystemExit # 退出程序
|
|
|
|
|
|
# 遍历异常信息中的文件路径,并对其进行规范化处理
|
|
|
for match in re.finditer(r'File "(.+?)", line', excMsg): # 查找异常信息中的文件路径
|
|
|
file_ = match.group(1) # 提取文件路径
|
|
|
try:
|
|
|
file_ = os.path.relpath(file_, os.path.dirname(__file__)) # 将文件路径转换为相对路径
|
|
|
except ValueError: # 捕获路径转换错误
|
|
|
pass # 忽略错误
|
|
|
file_ = file_.replace("\\", '/') # 将路径中的反斜杠替换为正斜杠
|
|
|
if "../" in file_: # 检查路径中是否包含上级目录
|
|
|
file_ = re.sub(r"(\.\./)+", '/', file_) # 替换上级目录为单斜杠
|
|
|
else:
|
|
|
file_ = file_.lstrip('/') # 去除路径开头的斜杠
|
|
|
file_ = re.sub(r"/{2,}", '/', file_) # 将多个斜杠替换为单斜杠
|
|
|
excMsg = excMsg.replace(match.group(1), file_) # 更新异常信息中的文件路径
|
|
|
|
|
|
# 对错误信息和异常信息进行敏感数据掩码处理
|
|
|
errMsg = maskSensitiveData(errMsg) # 掩码处理错误信息中的敏感数据
|
|
|
excMsg = maskSensitiveData(excMsg) # 掩码处理异常信息中的敏感数据
|
|
|
|
|
|
# 如果配置了API或校验和无效,则记录错误信息和异常信息
|
|
|
if conf.get("api") or not valid: # 检查是否配置了API或校验和无效
|
|
|
logger.critical("%s\n%s" % (errMsg, excMsg)) # 记录严重错误信息和异常信息
|
|
|
else:
|
|
|
logger.critical(errMsg) # 记录严重错误信息
|
|
|
dataToStdout("%s\n" % setColor(excMsg.strip(), level=logging.CRITICAL)) # 输出带颜色的异常信息到标准输出
|
|
|
createGithubIssue(errMsg, excMsg) # 创建GitHub问题
|
|
|
|
|
|
finally: # 无论是否发生异常,最终都会执行的代码块
|
|
|
kb.threadContinue = False # 设置线程继续标志为False
|
|
|
|
|
|
# 如果距离上次更新的天数超过指定值,则提示用户版本过时
|
|
|
if (getDaysFromLastUpdate() or 0) > LAST_UPDATE_NAGGING_DAYS: # 检查距离上次更新的天数
|
|
|
warnMsg = "your sqlmap version is outdated" # 生成警告信息
|
|
|
logger.warning(warnMsg) # 记录警告信息
|
|
|
|
|
|
# 如果配置了显示时间,则输出结束时间
|
|
|
if conf.get("showTime"): # 检查是否配置了显示时间
|
|
|
dataToStdout("\n[*] ending @ %s\n\n" % time.strftime("%X /%Y-%m-%d/"), forceOutput=True) # 输出结束时间
|
|
|
|
|
|
kb.threadException = True # 设置线程异常标志为True
|
|
|
|
|
|
# 如果存在临时目录,则清理临时文件
|
|
|
if kb.get("tempDir"): # 检查是否存在临时目录
|
|
|
for prefix in (MKSTEMP_PREFIX.IPC, MKSTEMP_PREFIX.TESTING, MKSTEMP_PREFIX.COOKIE_JAR, MKSTEMP_PREFIX.BIG_ARRAY): # 遍历临时文件前缀
|
|
|
for filepath in glob.glob(os.path.join(kb.tempDir, "%s*" % prefix)): # 查找匹配的临时文件
|
|
|
try:
|
|
|
os.remove(filepath) # 删除临时文件
|
|
|
except OSError: # 捕获文件删除错误
|
|
|
pass # 忽略错误
|
|
|
|
|
|
# 如果临时目录中没有其他文件,则删除临时目录
|
|
|
if not filterNone(filepath for filepath in glob.glob(os.path.join(kb.tempDir, '*')) if not any(filepath.endswith(_) for _ in (".lock", ".exe", ".so", '_'))): # 检查临时目录是否为空
|
|
|
# 使用glob模块获取临时目录中的所有文件路径,并过滤掉以.lock、.exe、.so或_结尾的文件
|
|
|
try:
|
|
|
shutil.rmtree(kb.tempDir, ignore_errors=True) # 删除临时目录,ignore_errors=True表示忽略删除过程中可能出现的错误
|
|
|
except OSError: # 捕获目录删除错误
|
|
|
pass # 忽略错误,继续执行后续代码
|
|
|
|
|
|
|
|
|
if conf.get("hashDB"): # 检查配置中是否存在hashDB
|
|
|
conf.hashDB.flush(True) # 将hashDB中的数据刷新到磁盘
|
|
|
conf.hashDB.close() # 关闭hashDB连接,NOTE: 由于PyPy的原因需要显式关闭
|
|
|
|
|
|
if conf.get("harFile"): # 检查配置中是否存在harFile
|
|
|
try:
|
|
|
with openFile(conf.harFile, "w+b") as f: # 以二进制写模式打开harFile
|
|
|
json.dump(conf.httpCollector.obtain(), fp=f, indent=4, separators=(',', ': ')) # 将HTTP收集器中的数据以JSON格式写入文件
|
|
|
except SqlmapBaseException as ex: # 捕获sqlmap基础异常
|
|
|
errMsg = getSafeExString(ex) # 获取异常的安全字符串表示
|
|
|
logger.critical(errMsg) # 记录严重错误日志
|
|
|
|
|
|
if conf.get("api"): # 检查配置中是否存在api
|
|
|
conf.databaseCursor.disconnect() # 断开数据库游标连接
|
|
|
|
|
|
if conf.get("dumper"): # 检查配置中是否存在dumper
|
|
|
conf.dumper.flush() # 刷新dumper中的数据
|
|
|
|
|
|
# short delay for thread finalization
|
|
|
_ = time.time() # 获取当前时间
|
|
|
while threading.active_count() > 1 and (time.time() - _) > THREAD_FINALIZATION_TIMEOUT: # 检查当前活跃线程数是否大于1,并且等待时间是否超过线程最终化超时时间
|
|
|
time.sleep(0.01) # 等待0.01秒,避免CPU占用过高
|
|
|
|
|
|
if cmdLineOptions.get("sqlmapShell"): # 检查命令行选项中是否存在sqlmapShell
|
|
|
cmdLineOptions.clear() # 清空命令行选项
|
|
|
conf.clear() # 清空配置
|
|
|
kb.clear() # 清空知识库
|
|
|
conf.disableBanner = True # 禁用启动横幅
|
|
|
main() # 调用主函数重新启动sqlmap
|
|
|
|
|
|
|
|
|
# 检查是否是作为主模块运行,如果是,则执行以下代码
|
|
|
if __name__ == "__main__":
|
|
|
try:
|
|
|
# 尝试调用main函数
|
|
|
main()
|
|
|
except KeyboardInterrupt:
|
|
|
# 如果用户按下Ctrl+C(键盘中断),则捕获KeyboardInterrupt异常,但不执行任何操作(pass表示空操作)
|
|
|
pass
|
|
|
except SystemExit:
|
|
|
# 如果程序调用了sys.exit(),则重新抛出SystemExit异常,允许正常退出流程
|
|
|
raise
|
|
|
except:
|
|
|
# 捕获其他所有异常,并打印异常信息
|
|
|
traceback.print_exc()
|
|
|
finally:
|
|
|
# 无论try块中的代码是否成功执行,都会执行finally块中的代码
|
|
|
# 参考:http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program
|
|
|
# 检查当前线程数量是否大于1(主线程和至少一个其他线程)
|
|
|
if threading.active_count() > 1:
|
|
|
# 如果大于1,则调用os._exit强制退出程序,不进行清理操作
|
|
|
# getattr(os, "_exitcode", 0)用于获取os模块的_exitcode属性,如果不存在则默认为0
|
|
|
os._exit(getattr(os, "_exitcode", 0))
|
|
|
else:
|
|
|
# 如果只有主线程,则正常退出程序
|
|
|
sys.exit(getattr(os, "_exitcode", 0))
|
|
|
else:
|
|
|
# 如果不是作为主模块运行,则取消延迟导入(因为CI/CD检查)
|
|
|
__import__("lib.controller.controller") |