zoukankan      html  css  js  c++  java
  • Python:SQLMap源码精读—start函数

    源代码

      1 def start():
      2     """
      3     This function calls a function that performs checks on both URL
      4     stability and all GET, POST, Cookie and User-Agent parameters to
      5     check if they are dynamic and SQL injection affected
      6     """
      7     if not conf.start:
      8         return False
      9 
     10     if conf.direct:
     11         initTargetEnv()
     12         setupTargetEnv()
     13         action()
     14         return True
     15 
     16     if conf.url and not conf.forms:
     17         kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie ))
     18 
     19     if conf.configFile and not kb.targetUrls:
     20         errMsg  = "you did not edit the configuration file properly, set "
     21         errMsg += "the target url, list of targets or google dork"
     22         logger.error(errMsg)
     23         return False
     24 
     25     if kb.targetUrls and len(kb.targetUrls) > 1:
     26         infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls)
     27         logger.info(infoMsg)
     28 
     29     hostCount             = 0
     30     cookieStr             = ""
     31     setCookieAsInjectable = True
     32 
     33     for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls:
     34         try:
     35             conf.url    = targetUrl
     36             conf.method = targetMethod
     37             conf.data   = targetData
     38             conf.cookie = targetCookie
     39             initTargetEnv()
     40             parseTargetUrl()
     41 
     42             testSqlInj = False
     43             if PLACE.GET in conf.parameters:
     44                 for parameter in re.findall(r"([^=]+)=[^&]+&?", conf.parameters[PLACE.GET]):
     45                     paramKey = (conf.hostname, conf.path, PLACE.GET, parameter)
     46                     if paramKey not in kb.testedParams:
     47                         testSqlInj = True
     48                         break
     49             else:
     50                 paramKey = (conf.hostname, conf.path, None, None)
     51                 if paramKey not in kb.testedParams:
     52                     testSqlInj = True
     53 
     54             testSqlInj &= (conf.hostname, conf.path, None, None) not in kb.testedParams
     55 
     56             if not testSqlInj:
     57                 infoMsg = "skipping '%s'" % targetUrl
     58                 logger.info(infoMsg)
     59                 continue
     60 
     61             if conf.multipleTargets:
     62                 hostCount += 1
     63                 if conf.forms:
     64                     message = "[#%d] form:
    %s %s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl)
     65                 else:
     66                     message = "url %d:
    %s %s%s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl,  " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "")
     67 
     68                 if conf.cookie:
     69                     message += "
    Cookie: %s" % conf.cookie
     70 
     71                 if conf.data:
     72                     message += "
    POST data: %s" % urlencode(conf.data) if conf.data else ""
     73 
     74                 if conf.forms:
     75                     if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1:
     76                         continue
     77 
     78                     message += "
    do you want to test this form? [Y/n/q] "
     79                     test = readInput(message, default="Y")
     80 
     81                     if not test or test[0] in ("y", "Y"):
     82                         if conf.method == HTTPMETHOD.POST:
     83                             message = "Edit POST data [default: %s]%s: " % (urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "")
     84                             conf.data = readInput(message, default=conf.data)
     85                             if extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data):
     86                                 message = "do you want to fill blank fields with random values? [Y/n] "
     87                                 test = readInput(message, default="Y")
     88                                 if not test or test[0] in ("y", "Y"):
     89                                     while extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data):
     90                                         item = extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data)
     91                                         if item[-1] == '&':
     92                                             conf.data = conf.data.replace(item, "%s%s&" % (item[:-1], randomStr()))
     93                                         else:
     94                                             conf.data = conf.data.replace(item, "%s%s" % (item, randomStr()))
     95                             conf.data = urldecode(conf.data)
     96 
     97                         elif conf.method == HTTPMETHOD.GET:
     98                             if conf.url.find("?") > -1:
     99                                 firstPart = conf.url[:conf.url.find("?")]
    100                                 secondPart = conf.url[conf.url.find("?")+1:]
    101                                 message = "Edit GET data [default: %s]: " % secondPart
    102                                 test = readInput(message, default=secondPart)
    103                                 conf.url = "%s?%s" % (firstPart, test)
    104 
    105                     elif test[0] in ("n", "N"):
    106                         continue
    107                     elif test[0] in ("q", "Q"):
    108                         break
    109 
    110                 elif conf.realTest:
    111                     logger.info(message)
    112                 else:
    113                     message += "
    do you want to test this url? [Y/n/q]"
    114                     test = readInput(message, default="Y")
    115 
    116                     if not test or test[0] in ("y", "Y"):
    117                         pass
    118                     elif test[0] in ("n", "N"):
    119                         continue
    120                     elif test[0] in ("q", "Q"):
    121                         break
    122 
    123                     logMsg = "testing url %s" % targetUrl
    124                     logger.info(logMsg)
    125 
    126             setupTargetEnv()
    127             if not checkConnection(suppressOutput = conf.forms) or not checkString() or not checkRegexp():
    128                 continue
    129 
    130             if conf.nullConnection:
    131                 checkNullConnection()
    132 
    133             if not conf.dropSetCookie and conf.cj:
    134                 for _, cookie in enumerate(conf.cj):
    135                     cookie = getUnicode(cookie)
    136                     index  = cookie.index(" for ")
    137 
    138                     cookieStr += "%s;" % cookie[8:index]
    139 
    140                 if cookieStr:
    141                     cookieStr = cookieStr[:-1]
    142 
    143                     if PLACE.COOKIE in conf.parameters:
    144                         message  = "you provided an HTTP Cookie header value. "
    145                         message += "The target url provided its own Cookie within "
    146                         message += "the HTTP Set-Cookie header. Do you want to "
    147                         message += "continue using the HTTP Cookie values that "
    148                         message += "you provided? [Y/n] "
    149                         test = readInput(message, default="Y")
    150 
    151                         if not test or test[0] in ("y", "Y"):
    152                             setCookieAsInjectable = False
    153 
    154                     if setCookieAsInjectable:
    155                         conf.httpHeaders.append(("Cookie", cookieStr))
    156                         conf.parameters[PLACE.COOKIE] = cookieStr
    157                         __paramDict = paramToDict(PLACE.COOKIE, cookieStr)
    158 
    159                         if __paramDict:
    160                             conf.paramDict[PLACE.COOKIE] = __paramDict
    161                             # TODO: consider the following line in __setRequestParams()
    162                             # __testableParameters = True
    163 
    164             if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) 
    165                 and (kb.injection.place is None or kb.injection.parameter is None):
    166                 if not conf.string and not conf.regexp:
    167                     # NOTE: this is not needed anymore, leaving only to display
    168                     # a warning message to the user in case the page is not stable
    169                     checkStability()
    170 
    171                 # Do a little prioritization reorder of a testable parameter list 
    172                 parameters = conf.parameters.keys()
    173 
    174                 # Order of testing list (last to first)
    175                 orderList = (PLACE.URI, PLACE.GET, PLACE.POST)
    176 
    177                 for place in orderList:
    178                     if place in parameters:
    179                         parameters.remove(place)
    180                         parameters.insert(0, place)
    181 
    182                 proceed = True
    183 
    184                 for place in parameters:
    185                     # Test User-Agent and Referer headers only if
    186                     # --level >= 3
    187                     skip = (place == PLACE.UA and conf.level < 3)
    188                     skip |= (place == PLACE.REFERER and conf.level < 3)
    189 
    190                     # Test Cookie header only if --level >= 2
    191                     skip |= (place == PLACE.COOKIE and conf.level < 2)
    192 
    193                     skip &= not (place == PLACE.UA and intersect(USER_AGENT_ALIASES, conf.testParameter))
    194                     skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter))
    195 
    196                     if skip:
    197                         continue
    198 
    199                     if not conf.paramDict.has_key(place):
    200                         continue
    201 
    202                     paramDict = conf.paramDict[place]
    203                     for parameter, value in paramDict.items():
    204                         if not proceed:
    205                             break
    206 
    207                         testSqlInj = True
    208 
    209                         paramKey = (conf.hostname, conf.path, place, parameter)
    210 
    211                         if paramKey in kb.testedParams:
    212                             testSqlInj = False
    213 
    214                             infoMsg = "skipping previously processed %s parameter '%s'" % (place, parameter)
    215                             logger.info(infoMsg)
    216 
    217                         # Avoid dinamicity test if the user provided the
    218                         # parameter manually
    219                         elif parameter in conf.testParameter or conf.realTest:
    220                             pass
    221 
    222                         elif not checkDynParam(place, parameter, value):
    223                             warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter)
    224                             logger.warn(warnMsg)
    225 
    226                         else:
    227                             logMsg = "%s parameter '%s' is dynamic" % (place, parameter)
    228                             logger.info(logMsg)
    229 
    230                         kb.testedParams.add(paramKey)
    231 
    232                         if testSqlInj:
    233                             check = heuristicCheckSqlInjection(place, parameter)
    234                             if not check and conf.realTest and
    235                               not simpletonCheckSqlInjection(place, parameter, value):
    236                                 continue
    237 
    238                             logMsg = "testing sql injection on %s " % place
    239                             logMsg += "parameter '%s'" % parameter
    240                             logger.info(logMsg)
    241 
    242                             injection = checkSqlInjection(place, parameter, value)
    243                             proceed = not kb.endDetection
    244 
    245                             if injection is not None and injection.place is not None:
    246                                 kb.injections.append(injection)
    247 
    248                                 # In case when user wants to end detection phase (Ctrl+C)
    249                                 if not proceed:
    250                                     break
    251 
    252                                 msg = "%s parameter '%s' " % (injection.place, injection.parameter)
    253                                 msg += "is vulnerable. Do you want to keep testing the others? [y/N] "
    254                                 test = readInput(msg, default="N")
    255 
    256                                 if test[0] in ("n", "N"):
    257                                     proceed = False
    258                                     paramKey = (conf.hostname, conf.path, None, None)
    259                                     kb.testedParams.add(paramKey)
    260                             else:
    261                                 warnMsg = "%s parameter '%s' is not " % (place, parameter)
    262                                 warnMsg += "injectable"
    263                                 logger.warn(warnMsg)
    264 
    265             if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
    266                 if not conf.realTest:
    267                     errMsg = "all parameters are not injectable, try to "
    268                     errMsg += "increase --level/--risk values to perform "
    269                     errMsg += "more tests."
    270 
    271                     if isinstance(conf.tech, list) and len(conf.tech) > 0:
    272                         errMsg += " Rerun without providing the --technique switch."
    273 
    274                     if not conf.textOnly and kb.originalPage:
    275                         percent = (100.0 * len(getFilteredPageContent(kb.originalPage)) / len(kb.originalPage))
    276                         errMsg += " Give it a go with the --text-only switch "
    277                         errMsg += "if the target page has a low percentage of "
    278                         errMsg += "textual content (~%.2f%% of " % percent
    279                         errMsg += "page content is text)"
    280 
    281                     raise sqlmapNotVulnerableException, errMsg
    282                 else:
    283                     errMsg = "it seems that all parameters are not injectable"
    284                     raise sqlmapNotVulnerableException, errMsg
    285             else:
    286                 # Flush the flag
    287                 kb.testMode = False
    288 
    289                 __saveToSessionFile()
    290                 __showInjections()
    291                 __selectInjection()
    292 
    293             if kb.injection.place is not None and kb.injection.parameter is not None:
    294                 if kb.testQueryCount == 0 and conf.realTest:
    295                     condition = False
    296                 elif conf.multipleTargets:
    297                     message = "do you want to exploit this SQL injection? [Y/n] "
    298                     exploit = readInput(message, default="Y")
    299 
    300                     condition = not exploit or exploit[0] in ("y", "Y")
    301                 else:
    302                     condition = True
    303                 if condition:
    304                     action()
    305 
    306         except KeyboardInterrupt:
    307             if conf.multipleTargets:
    308                 warnMsg = "user aborted in multiple target mode"
    309                 logger.warn(warnMsg)
    310 
    311                 message = "do you want to skip to the next target in list? [Y/n/q]"
    312                 test = readInput(message, default="Y")
    313 
    314                 if not test or test[0] in ("y", "Y"):
    315                     pass
    316                 elif test[0] in ("n", "N"):
    317                     return False
    318                 elif test[0] in ("q", "Q"):
    319                     raise sqlmapUserQuitException
    320             else:
    321                 raise
    322 
    323         except sqlmapUserQuitException:
    324             raise
    325 
    326         except sqlmapSilentQuitException:
    327             raise
    328 
    329         except exceptionsTuple, e:
    330             e = getUnicode(e)
    331 
    332             if conf.multipleTargets:
    333                 e += ", skipping to the next %s" % ("form" if conf.forms else "url")
    334                 logger.error(e)
    335             else:
    336                 logger.critical(e)
    337                 return False
    338 
    339         finally:
    340             showHttpErrorCodes()
    341 
    342     if conf.loggedToOut and not conf.multipleTargets:
    343         logger.info("Fetched data logged to text files under '%s'" % conf.outputPath)
    344 
    345     return True

    代码解释

    10-14行

    if conf.direct:
        initTargetEnv()
        setupTargetEnv()
        action()
        return True

    conf.direct是通过命令行参数:"-d"指定的。

    通过参数"-d"指定要连接的数据库
    eg:-d "mysql:123123//root:@127.0.0.1:3306/security"

    39-40行

    initTargetEnv()
    parseTargetUrl()

    initTargetEnv()函数主要就是完成全局变量conf和kb的初始化工作

    parseTargetUrl()函数主要完成针对目标网址的解析工作,如获取协议名、路径、端口、请求参数等信息

    43-52行

    if PLACE.GET in conf.parameters:
        for parameter in re.findall(r"([^=]+)=[^&]+&?", conf.parameters[PLACE.GET]):
            paramKey = (conf.hostname, conf.path, PLACE.GET, parameter)
            if paramKey not in kb.testedParams:
                testSqlInj = True
                break
    else:
        paramKey = (conf.hostname, conf.path, None, None)
        if paramKey not in kb.testedParams:
            testSqlInj = True

    测试过的url参数信息会保存到kb.testedParams中(第230行和第259行),所以在进行test之前,会先判断当前的url是否已经test过

    如果没test过的话,则testSqlInj = True,否则testSqlInj = False。

    当testSqlInj = False的时候,就不会执行 injection = checkSqlInjection(place, parameter, value)这句代码了。

    126行

    setupTargetEnv()

    该函数主要包含3个子功能:

    1.创建保存目标执行结果的目录和文件
    2.将get或post发送的数据解析成字典形式,并保存到conf.paramDict中
    3.读取session文件(如果存在的话),并提起文件中的数据,保存到kb变量中

    133-162行

    如果在命令中有提供cookie的话,就会将攻城师指定的cookie加入到http请求头中,以便使用cookie访问。

    164-263行

     提取url中的参数信息,并将其传递给checkSqlInjection函数,checkSqlInjection函数的功能主要是检测给定的url参数,看其是否可注入,如果可注入的话,就将payload等相关信息返回(即checkSqlInjection函数的返回值),再将其append到kb.injections中。

    304行

    action()是很总要的一个函数,该函数主要根据攻城师的命令行参数选型,从而利用存在注入漏洞的url,以进一步获取攻城师要获取的数据。

    比如:当前的数据库用户、枚举数据库的所有数据表等等

    版权

    作       者:曾是土木人

    新浪微博:http://weibo.com/cstmr

    转载请注明出处:http://www.cnblogs.com/hongfei/p/sqlmap-start.html

  • 相关阅读:
    Discuz!NT 系统架构分析
    jquery pager
    Nhibernate分页方法
    Discuz nt模板机制
    WTclient创建OPC client方法
    OPC
    Regular Expressions in Java
    How to use VS to manipulate Access
    OPC客户端设计
    How to use VS to manipulate Excel使用MFC读写Excel
  • 原文地址:https://www.cnblogs.com/hongfei/p/sqlmap-start.html
Copyright © 2011-2022 走看看