安全工具学习之SQLmap部分代码分析

sqlmap源码分析

前言:
最近突发奇想想研究一下安全工具,所以就分析了最常见但是写的特别特别好的sqlmap,因为本人属于小白,如果文章分析内容有错误,望大佬们帮忙指正!Q'w'Q

0x000 sqlmap 执行的流程图

首先贴一张sqlmap源码流程图

sqlmap源码流程图 流程图模板_ProcessOn思维导图、流程图

0x001 sqlmap.py 入口分析

直接先来看sqlmap.py​,前面都是导入基础的包,和一些lib​先略过,看main​函数

try:
        dirtyPatches() # Place for "dirty" Python related patches
        resolveCrossReferences() # Place for cross-reference resolution
        checkEnvironment()
        setPaths(modulePath())
        banner()

这部分就是初始化sqlmap​的操作

checkEnvironment()​ 就是检测当前系统的环境,sqlmap​的安装目录 python​的环境等等

setPaths(modulePath())​ 调用moudlePath()​再传入setPaths()​中

def modulePath():
    """
    This will get us the program's directory, even if we are frozen
    using py2exe
    """

    try:
        # 尝试定义`_`变量为当前执行程序的路径或者当前文件的路径
        # `WeAreFrozen()`函数使用来判断当前程序是否被封装
        _ = sys.executable if weAreFrozen() else __file__
    except NameError:
        # 如果发生了NameError的话就用inspect模块中的getsourceFile函数来获取文件路径
        _ = inspect.getsourcefile(modulePath)
    # 将上面定义的路径的目录部分,转换为系统文件系统编码后返回
    return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)


'''
WeareFrozen() 
    Returns whether we are frozen via py2exe.
    This will affect how we find out where we are located.
getUnicode()
    Returns the unicode representation of the supplied value
'''

setPaths()​函数实现的功能就是Sets absolute paths for project directories and files

就是因为setPaths(modulePath())​所以我们在哪个目录下执行都不会报错

然后banner()​函数就是用来输出sqlmap​的版本信息和有意思的图案的

# Store original command line options for possible later restoration    
        args = cmdLineParser()
        cmdLineOptions.update(args.__dict__ if hasattr(args, "__dict__") else args)
        # 弱国args有一个`__dict__`属性,表示它可能是一个类的实例,那么会使用这个`__dict__`属性的内容区更新cmdLineOptions
        # 如果args没有`__dict__`属性,就直接使用args本身去更新cmdLineOptions
        initOptions(cmdLineOptions)

        if checkPipedInput():
            conf.batch = True

        if conf.get("api"):
            # heavy imports
            from lib.utils.api import StdDbOut
            from lib.utils.api import setRestAPILog

            # Overwrite system standard output and standard error to write
            # to an IPC database
            sys.stdout = StdDbOut(conf.taskid, messagetype="stdout")
            sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")

            setRestAPILog()

        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()
.....

然后就是对参数进行参数解析

所以命令行的参数配置都在lib/parse/cmdline.py​之中,我们可以看到

parser.add_argument("--hh", dest="advancedHelp", action="store_true",
            help="Show advanced help message and exit")

        parser.add_argument("--version", dest="showVersion", action="store_true",
            help="Show program's version number and exit")

        parser.add_argument("-v", dest="verbose", type=int,
            help="Verbosity level: 0-6 (default %d)" % defaults.verbose)

调用help​,查看version​都是在lib/parse/cmdline.py​中定义的

然后检查args​参数,将args​参数传入到cmdLineOptions​中,再传递给initOptions

def initOptions(inputOptions=AttribDict(), overrideOptions=False):
    _setConfAttributes()
    _setKnowledgeBaseAttributes()
    _mergeOptions(inputOptions, overrideOptions)

就是初始化环境,包括配置文件等等....

继续往下走,程序调用了checkPipedInput()​函数,用来检测用户输入是否标准,比如python sqlmap -r test.txt​,如果通过了就将conf.batch​设置为True

如果conf​字典中有关键字api​则会导入下面的包,并且覆盖要写入的系统标准输入和标准错误到IPC数据库,还调用setRestAPILog()​函数,这里先略过

然后调用了init()​函数

def init():
    """
    Set attributes into both configuration and knowledge base singletons
    based upon command line and configuration file options.
    """
.........

也是用来初始化一些配置信息的

if not conf.updateAll:
            # Postponed imports (faster start)
            if conf.smokeTest:
                from lib.core.testing import smokeTest
                os._exitcode = 1 - (smokeTest() or 0)
                # 设置os._exitcode的值为1 - (smokeTest() or 0) 也就是smokeTest()的执行结果,成功的话为0,失败则为1,所以smokeTest()执行成功的话os._exitcode为1,反之则为0
            elif conf.vulnTest:
                from lib.core.testing import vulnTest
                os._exitcode = 1 - (vulnTest() or 0)
            else:
                from lib.controller.controller import start
                if conf.profile:
                    from lib.core.profiling import profile
                    globals()["start"] = start
                    profile()
                    # This will run the program and present profiling data in a nice looking graph
                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

                                    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

                        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

上文一大段代码,是sqlmap​根据conf​中的配置信息来执行不同的操作选项,最终启动主程序

简单说一下执行的smokeTest()​和vlunTest()

smokeTest()​ : 检查错误的正则表达式,扫描python模块,动态导入模块等等...

vulnTest()​ : 自动化执行对vulnserver​的漏洞测试,通过调用sqlmap​工具并对比预期结果来验证是否存在漏洞

mian()​函数的后半段就是争对sqlmap.py​运行时候产生的报错进行一些处理,比如

elif "_mkstemp_inner" in excMsg:
            errMsg = "there has been a problem while accessing temporary files"
            logger.critical(errMsg)
            raise SystemExit

因为本人python代码的功底不是很夯实,主要还是看是如何进行注入,以及如何进行注入判断的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值