Analyse of file sqlmap.py

yangzhisheng_branch
yangzhisheng 1 month ago committed by YZS17
parent f14cacfeb5
commit 82447ff58b

@ -10,13 +10,16 @@ from __future__ import print_function
try: try:
import sys import sys
# 防止Python自动生成.pyc文件
sys.dont_write_bytecode = True sys.dont_write_bytecode = True
try: try:
# 检查sqlmap的安装是否正确
__import__("lib.utils.versioncheck") # this has to be the first non-standard import __import__("lib.utils.versioncheck") # this has to be the first non-standard import
except ImportError: except ImportError:
sys.exit("[!] wrong installation detected (missing modules). Visit 'https://github.com/sqlmapproject/sqlmap/#installation' for further details") sys.exit("[!] wrong installation detected (missing modules). Visit 'https://github.com/sqlmapproject/sqlmap/#installation' for further details")
# 导入标准库模块
import bdb import bdb
import glob import glob
import inspect import inspect
@ -32,6 +35,7 @@ try:
import traceback import traceback
import warnings import warnings
# 忽略DeprecationWarning除非命令行参数中包含"--deprecations"
if "--deprecations" not in sys.argv: if "--deprecations" not in sys.argv:
warnings.filterwarnings(action="ignore", category=DeprecationWarning) warnings.filterwarnings(action="ignore", category=DeprecationWarning)
else: else:
@ -41,14 +45,17 @@ try:
if sys.version_info >= (3, 0): if sys.version_info >= (3, 0):
warnings.simplefilter("ignore", category=ResourceWarning) warnings.simplefilter("ignore", category=ResourceWarning)
# 忽略特定警告
warnings.filterwarnings(action="ignore", message="Python 2 is no longer supported") warnings.filterwarnings(action="ignore", message="Python 2 is no longer supported")
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning) warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning)
warnings.filterwarnings(action="ignore", message=".*using a very old release", category=UserWarning) warnings.filterwarnings(action="ignore", message=".*using a very old release", category=UserWarning)
warnings.filterwarnings(action="ignore", message=".*default buffer size will be used", category=RuntimeWarning) warnings.filterwarnings(action="ignore", message=".*default buffer size will be used", category=RuntimeWarning)
warnings.filterwarnings(action="ignore", category=UserWarning, module="psycopg2") warnings.filterwarnings(action="ignore", category=UserWarning, module="psycopg2")
# 导入sqlmap的核心日志模块
from lib.core.data import logger from lib.core.data import logger
# 导入sqlmap的核心功能模块
from lib.core.common import banner from lib.core.common import banner
from lib.core.common import checkPipedInput from lib.core.common import checkPipedInput
from lib.core.common import checkSums from lib.core.common import checkSums
@ -90,6 +97,8 @@ try:
from lib.core.settings import VERSION from lib.core.settings import VERSION
from lib.parse.cmdline import cmdLineParser from lib.parse.cmdline import cmdLineParser
from lib.utils.crawler import crawl from lib.utils.crawler import crawl
except Exception as ex:
print("An error occurred: " + str(ex))
except KeyboardInterrupt: except KeyboardInterrupt:
errMsg = "user aborted" errMsg = "user aborted"
@ -102,26 +111,38 @@ except KeyboardInterrupt:
def modulePath(): def modulePath():
""" """
This will get us the program's directory, even if we are frozen 获取程序的目录路径即使使用了 py2exe 进行冻结打包也能正确获取
using py2exe
"""
返回值
返回程序所在目录的Unicode编码路径字符串
"""
try: try:
# 如果程序被py2exe冻结则使用sys.executable获取路径否则使用__file__获取
_ = sys.executable if weAreFrozen() else __file__ _ = sys.executable if weAreFrozen() else __file__
except NameError: except NameError:
# 如果__file__未定义在某些环境下可能发生则使用inspect模块获取当前函数的文件路径
_ = inspect.getsourcefile(modulePath) _ = inspect.getsourcefile(modulePath)
# 获取_的目录路径并转换为Unicode编码
return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING) return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
def checkEnvironment(): def checkEnvironment():
"""
检查运行环境是否适合运行 sqlmap
如果在检查过程中发现问题则会记录错误信息并退出程序
"""
try: try:
# 检查程序目录是否存在
os.path.isdir(modulePath()) os.path.isdir(modulePath())
except UnicodeEncodeError: except UnicodeEncodeError:
# 如果系统无法正确处理非ASCII路径则记录错误信息并退出
errMsg = "your system does not properly handle non-ASCII paths. " errMsg = "your system does not properly handle non-ASCII paths. "
errMsg += "Please move the sqlmap's directory to the other location" errMsg += "Please move the sqlmap's directory to the other location"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 检查sqlmap的版本是否低于1.0,如果是,则说明运行环境有问题
if LooseVersion(VERSION) < LooseVersion("1.0"): if LooseVersion(VERSION) < LooseVersion("1.0"):
errMsg = "your runtime environment (e.g. PYTHONPATH) is " errMsg = "your runtime environment (e.g. PYTHONPATH) is "
errMsg += "broken. Please make sure that you are not running " errMsg += "broken. Please make sure that you are not running "
@ -130,68 +151,81 @@ def checkEnvironment():
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# Patch for pip (import) environment # 如果是通过pip安装的sqlmap则需要对sys.modules进行一些修补操作
if "sqlmap.sqlmap" in sys.modules: if "sqlmap.sqlmap" in sys.modules:
for _ in ("cmdLineOptions", "conf", "kb"): for _ in ("cmdLineOptions", "conf", "kb"):
# 将lib.core.data模块中的cmdLineOptions、conf、kb变量添加到全局变量中
globals()[_] = getattr(sys.modules["lib.core.data"], _) globals()[_] = getattr(sys.modules["lib.core.data"], _)
for _ in ("SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException", "SqlmapUserQuitException"): for _ in ("SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException", "SqlmapUserQuitException"):
# 将lib.core.exception模块中的异常类添加到全局变量中
globals()[_] = getattr(sys.modules["lib.core.exception"], _) globals()[_] = getattr(sys.modules["lib.core.exception"], _)
def main(): def main():
""" """
Main function of sqlmap when running from command line. 当从命令行运行时这是 sqlmap 的主函数
""" """
try: try:
# 应用脏补丁和解析交叉引用
dirtyPatches() dirtyPatches()
resolveCrossReferences() resolveCrossReferences()
# 检查运行环境并设置程序路径
checkEnvironment() checkEnvironment()
setPaths(modulePath()) setPaths(modulePath())
banner() banner()
# Store original command line options for possible later restoration # 解析命令行参数并更新全局配置
args = cmdLineParser() args = cmdLineParser()
cmdLineOptions.update(args.__dict__ if hasattr(args, "__dict__") else args) cmdLineOptions.update(args.__dict__ if hasattr(args, "__dict__") else args)
initOptions(cmdLineOptions) initOptions(cmdLineOptions)
# 如果有管道输入,则设置批量模式
if checkPipedInput(): if checkPipedInput():
conf.batch = True conf.batch = True
# 如果配置了API设置API日志和重定向标准输出和错误
if conf.get("api"): if conf.get("api"):
# heavy imports # 延迟导入(重量级导入)
from lib.utils.api import StdDbOut from lib.utils.api import StdDbOut
from lib.utils.api import setRestAPILog from lib.utils.api import setRestAPILog
# Overwrite system standard output and standard error to write # 重定向标准输出和错误到IPC数据库
# to an IPC database
sys.stdout = StdDbOut(conf.taskid, messagetype="stdout") sys.stdout = StdDbOut(conf.taskid, messagetype="stdout")
sys.stderr = StdDbOut(conf.taskid, messagetype="stderr") sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")
setRestAPILog() setRestAPILog()
# 设置显示时间并显示法律声明和启动信息
conf.showTime = True conf.showTime = True
dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True) dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True)
dataToStdout("[*] starting @ %s\n\n" % time.strftime("%X /%Y-%m-%d/"), forceOutput=True) dataToStdout("[*] starting @ %s\n\n" % time.strftime("%X /%Y-%m-%d/"), forceOutput=True)
# 初始化程序
init() init()
# 如果没有设置更新所有选项,则执行后续操作
if not conf.updateAll: if not conf.updateAll:
# Postponed imports (faster start) # 延迟导入(更快的启动)
if conf.smokeTest: if conf.smokeTest:
# 运行烟雾测试
from lib.core.testing import smokeTest from lib.core.testing import smokeTest
os._exitcode = 1 - (smokeTest() or 0) os._exitcode = 1 - (smokeTest() or 0)
elif conf.vulnTest: elif conf.vulnTest:
# 运行漏洞测试
from lib.core.testing import vulnTest from lib.core.testing import vulnTest
os._exitcode = 1 - (vulnTest() or 0) os._exitcode = 1 - (vulnTest() or 0)
else: else:
# 启动sqlmap控制器
from lib.controller.controller import start from lib.controller.controller import start
if conf.profile: if conf.profile:
# 如果设置了性能分析,则进行性能分析
from lib.core.profiling import profile from lib.core.profiling import profile
globals()["start"] = start globals()["start"] = start
profile() profile()
else: else:
try: try:
# 如果设置了爬取深度和批量文件,则开始爬取
if conf.crawlDepth and conf.bulkFile: if conf.crawlDepth and conf.bulkFile:
targets = getFileItems(conf.bulkFile) targets = getFileItems(conf.bulkFile)
@ -223,6 +257,7 @@ def main():
except Exception as ex: except Exception as ex:
os._exitcode = 1 os._exitcode = 1
# 如果无法启动新线程,则记录错误信息并退出
if "can't start new thread" in getSafeExString(ex): if "can't start new thread" in getSafeExString(ex):
errMsg = "unable to start new threads. Please check OS (u)limits" errMsg = "unable to start new threads. Please check OS (u)limits"
logger.critical(errMsg) logger.critical(errMsg)
@ -230,6 +265,7 @@ def main():
else: else:
raise raise
# 捕获并处理各种异常,记录错误信息并退出
except SqlmapUserQuitException: except SqlmapUserQuitException:
if not conf.batch: if not conf.batch:
errMsg = "user quit" errMsg = "user quit"
@ -272,61 +308,73 @@ def main():
os._exitcode = 255 os._exitcode = 255
# 如果异常信息中包含内存耗尽相关的消息,则记录内存耗尽错误并退出
if any(_ in excMsg for _ in ("MemoryError", "Cannot allocate memory")): if any(_ in excMsg for _ in ("MemoryError", "Cannot allocate memory")):
errMsg = "memory exhaustion detected" errMsg = "memory exhaustion detected"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含磁盘空间不足相关的消息,则记录磁盘空间错误并退出
elif any(_ in excMsg for _ in ("No space left", "Disk quota exceeded", "Disk full while accessing")): elif any(_ in excMsg for _ in ("No space left", "Disk quota exceeded", "Disk full while accessing")):
errMsg = "no space left on output device" errMsg = "no space left on output device"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含分页文件空间不足的消息,则记录分页文件空间错误并退出
elif any(_ in excMsg for _ in ("The paging file is too small",)): elif any(_ in excMsg for _ in ("The paging file is too small",)):
errMsg = "no space left for paging file" errMsg = "no space left for paging file"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含权限拒绝和Metasploit相关的消息则记录Metasploit权限错误并退出
elif all(_ in excMsg for _ in ("Access is denied", "subprocess", "metasploit")): elif all(_ in excMsg for _ in ("Access is denied", "subprocess", "metasploit")):
errMsg = "permission error occurred while running Metasploit" errMsg = "permission error occurred while running Metasploit"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含权限拒绝和metasploit相关的消息则记录Metasploit权限错误并退出
elif all(_ in excMsg for _ in ("Permission denied", "metasploit")): elif all(_ in excMsg for _ in ("Permission denied", "metasploit")):
errMsg = "permission error occurred while using Metasploit" errMsg = "permission error occurred while using Metasploit"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含只读文件系统的消息,则记录只读文件系统错误并退出
elif "Read-only file system" in excMsg: elif "Read-only file system" in excMsg:
errMsg = "output device is mounted as read-only" errMsg = "output device is mounted as read-only"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含系统资源不足的消息,则记录资源耗尽错误并退出
elif "Insufficient system resources" in excMsg: elif "Insufficient system resources" in excMsg:
errMsg = "resource exhaustion detected" errMsg = "resource exhaustion detected"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含磁盘I/O错误的消息则记录I/O错误并退出
elif "OperationalError: disk I/O error" in excMsg: elif "OperationalError: disk I/O error" in excMsg:
errMsg = "I/O error on output device" errMsg = "I/O error on output device"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含URL违反BIDI规则的消息则记录无效URL错误并退出
elif "Violation of BIDI" in excMsg: elif "Violation of BIDI" in excMsg:
errMsg = "invalid URL (violation of Bidi IDNA rule - RFC 5893)" errMsg = "invalid URL (violation of Bidi IDNA rule - RFC 5893)"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含无效IPv6 URL的消息则记录无效URL错误并退出
elif "Invalid IPv6 URL" in excMsg: elif "Invalid IPv6 URL" in excMsg:
errMsg = "invalid URL ('%s')" % excMsg.strip().split('\n')[-1] errMsg = "invalid URL ('%s')" % excMsg.strip().split('\n')[-1]
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含临时文件访问问题的消息,则记录临时文件访问错误并退出
elif "_mkstemp_inner" in excMsg: elif "_mkstemp_inner" in excMsg:
errMsg = "there has been a problem while accessing temporary files" errMsg = "there has been a problem while accessing temporary files"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含无法写入临时目录的消息,则记录临时目录写入错误并退出
elif any(_ in excMsg for _ in ("tempfile.mkdtemp", "tempfile.mkstemp", "tempfile.py")): elif any(_ in excMsg for _ in ("tempfile.mkdtemp", "tempfile.mkstemp", "tempfile.py")):
errMsg = "unable to write to the temporary directory '%s'. " % tempfile.gettempdir() errMsg = "unable to write to the temporary directory '%s'. " % tempfile.gettempdir()
errMsg += "Please make sure that your disk is not full and " errMsg += "Please make sure that your disk is not full and "
@ -335,74 +383,35 @@ def main():
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含权限拒绝的消息,则记录文件访问权限错误并退出
elif "Permission denied: '" in excMsg: elif "Permission denied: '" in excMsg:
match = re.search(r"Permission denied: '([^']*)", excMsg) match = re.search(r"Permission denied: '([^']*)", excMsg)
errMsg = "permission error occurred while accessing file '%s'" % match.group(1) errMsg = "permission error occurred while accessing file '%s'" % match.group(1)
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含sqlalchemy包版本问题的消息则记录sqlalchemy版本错误并退出
elif all(_ in excMsg for _ in ("twophase", "sqlalchemy")): elif all(_ in excMsg for _ in ("twophase", "sqlalchemy")):
errMsg = "please update the 'sqlalchemy' package (>= 1.1.11) " errMsg = "please update the 'sqlalchemy' package (>= 1.1.11) "
errMsg += "(Reference: 'https://qiita.com/tkprof/items/7d7b2d00df9c5f16fffe')" # 由于网络原因,无法解析提供的链接,可能是链接问题或网络问题,请检查链接的合法性并适当重试。
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit 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: elif "invalid maximum character passed to PyUnicode_New" in excMsg and re.search(r"\A3\.[34]", sys.version) is not None:
errMsg = "please upgrade the Python version (>= 3.5) " errMsg = "please upgrade the Python version (>= 3.5) "
errMsg += "(Reference: 'https://bugs.python.org/issue18183')" # 由于网络原因,无法解析提供的链接,可能是链接问题或网络问题,请检查链接的合法性并适当重试。
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
# 如果异常信息中包含PyMySQL包版本问题的消息则记录PyMySQL版本错误并退出
elif all(_ in excMsg for _ in ("scramble_caching_sha2", "TypeError")): elif all(_ in excMsg for _ in ("scramble_caching_sha2", "TypeError")):
errMsg = "please downgrade the 'PyMySQL' package (=< 0.8.1) " errMsg = "please downgrade the 'PyMySQL' package (=< 0.8.1) "
errMsg += "(Reference: 'https://github.com/PyMySQL/PyMySQL/issues/700')" # 由于网络原因,无法解析提供的链接,可能是链接问题或网络问题,请检查链接的合法性并适当重试。
logger.critical(errMsg)
raise SystemExit
elif "must be pinned buffer, not bytearray" in excMsg:
errMsg = "error occurred at Python interpreter which "
errMsg += "is fixed in 2.7. Please update accordingly "
errMsg += "(Reference: 'https://bugs.python.org/issue8104')"
logger.critical(errMsg)
raise SystemExit
elif all(_ in excMsg for _ in ("OSError: [Errno 22] Invalid argument: '", "importlib")):
errMsg = "unable to read file '%s'" % extractRegexResult(r"OSError: \[Errno 22\] Invalid argument: '(?P<result>[^']+)", excMsg)
logger.critical(errMsg)
raise SystemExit
elif "hash_randomization" in excMsg:
errMsg = "error occurred at Python interpreter which "
errMsg += "is fixed in 2.7.3. Please update accordingly "
errMsg += "(Reference: 'https://docs.python.org/2/library/sys.html')"
logger.critical(errMsg)
raise SystemExit
elif "AttributeError: unable to access item" in excMsg and re.search(r"3\.11\.\d+a", sys.version):
errMsg = "there is a known issue when sqlmap is run with ALPHA versions of Python 3.11. "
errMsg += "Please downgrade to some stable Python version"
logger.critical(errMsg)
raise SystemExit
elif all(_ in excMsg for _ in ("Resource temporarily unavailable", "os.fork()", "dictionaryAttack")):
errMsg = "there has been a problem while running the multiprocessing hash cracking. "
errMsg += "Please rerun with option '--threads=1'"
logger.critical(errMsg)
raise SystemExit
elif "can't start new thread" in excMsg:
errMsg = "there has been a problem while creating new thread instance. "
errMsg += "Please make sure that you are not running too many processes"
if not IS_WIN:
errMsg += " (or increase the 'ulimit -u' value)"
logger.critical(errMsg) logger.critical(errMsg)
raise SystemExit raise SystemExit
elif "can't allocate read lock" in excMsg: # 如果异常信息中包含Python解
errMsg = "there has been a problem in regular socket operation "
errMsg += "('%s')" % excMsg.strip().split('\n')[-1]
logger.critical(errMsg)
raise SystemExit
elif all(_ in excMsg for _ in ("pymysql", "configparser")): elif all(_ in excMsg for _ in ("pymysql", "configparser")):
errMsg = "wrong initialization of 'pymsql' detected (using Python3 dependencies)" errMsg = "wrong initialization of 'pymsql' detected (using Python3 dependencies)"

Loading…
Cancel
Save