diff --git a/src/sqlmap-master/lib/controller/checks.py b/src/sqlmap-master/lib/controller/checks.py index f25fb8a..a853bc6 100644 --- a/src/sqlmap-master/lib/controller/checks.py +++ b/src/sqlmap-master/lib/controller/checks.py @@ -913,6 +913,7 @@ def checkFalsePositives(injection): retVal = True + # 如果注入数据中所有元素都在PAYLOAD.TECHNIQUE.BOOLEAN、PAYLOAD.TECHNIQUE.TIME、PAYLOAD.TECHNIQUE.STACKED中,或者注入数据长度为1且PAYLOAD.TECHNIQUE.UNION在注入数据中且"Generic"在注入数据[PAYLOAD.TECHNIQUE.UNION].title中 if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or (len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title): pushValue(kb.injection) @@ -920,11 +921,13 @@ def checkFalsePositives(injection): infoMsg += "parameter '%s' is a false positive" % injection.parameter logger.info(infoMsg) + # 定义一个函数,返回一个随机整数 def _(): return int(randomInt(2)) + 1 kb.injection = injection + # 遍历配置级别 for level in xrange(conf.level): while True: randInt1, randInt2, randInt3 = (_() for j in xrange(3)) @@ -932,38 +935,48 @@ def checkFalsePositives(injection): randInt1 = min(randInt1, randInt2, randInt3) randInt3 = max(randInt1, randInt2, randInt3) + # 如果配置字符串存在且配置字符串在任意一个Unicode(_)中 if conf.string and any(conf.string in getUnicode(_) for _ in (randInt1, randInt2, randInt3)): continue + # 如果配置非字符串存在且配置非字符串在任意一个Unicode(_)中 if conf.notString and any(conf.notString in getUnicode(_) for _ in (randInt1, randInt2, randInt3)): continue + # 如果randInt3 > randInt2 > randInt1,则跳出循环 if randInt3 > randInt2 > randInt1: break + # 如果不满足布尔表达式,则retVal为False,跳出循环 if not checkBooleanExpression("%d%s%d" % (randInt1, INFERENCE_EQUALS_CHAR, randInt1)): retVal = False break + # 如果PAYLOAD.TECHNIQUE.BOOLEAN不在注入数据中,则检查布尔表达式 if PAYLOAD.TECHNIQUE.BOOLEAN not in injection.data: checkBooleanExpression("%d%s%d" % (randInt1, INFERENCE_EQUALS_CHAR, randInt2)) # just in case if DBMS hasn't properly recovered from previous delayed request + # 如果满足布尔表达式,则retVal为False,跳出循环 if checkBooleanExpression("%d%s%d" % (randInt1, INFERENCE_EQUALS_CHAR, randInt3)): # this must not be evaluated to True retVal = False break + # 如果满足布尔表达式,则retVal为False,跳出循环 elif checkBooleanExpression("%d%s%d" % (randInt3, INFERENCE_EQUALS_CHAR, randInt2)): # this must not be evaluated to True retVal = False break + # 如果不满足布尔表达式,则retVal为False,跳出循环 elif not checkBooleanExpression("%d%s%d" % (randInt2, INFERENCE_EQUALS_CHAR, randInt2)): # this must be evaluated to True retVal = False break + # 如果满足布尔表达式,则retVal为False,跳出循环 elif checkBooleanExpression("%d %d" % (randInt3, randInt2)): # this must not be evaluated to True (invalid statement) retVal = False break + # 如果retVal为False,则记录警告信息 if not retVal: warnMsg = "false positive or unexploitable injection point detected" logger.warning(warnMsg) @@ -978,22 +991,28 @@ def checkSuhosinPatch(injection): Checks for existence of Suhosin-patch (and alike) protection mechanism(s) """ + # 如果注入点在GET或URI中 if injection.place in (PLACE.GET, PLACE.URI): debugMsg = "checking for parameter length " debugMsg += "constraining mechanisms" logger.debug(debugMsg) + # 将当前的注入点保存到栈中 pushValue(kb.injection) + # 设置当前的注入点 kb.injection = injection + # 生成一个随机数 randInt = randomInt() + # 检查参数长度是否被限制 if not checkBooleanExpression("%d=%s%d" % (randInt, ' ' * SUHOSIN_MAX_VALUE_LENGTH, randInt)): warnMsg = "parameter length constraining " warnMsg += "mechanism detected (e.g. Suhosin patch). " warnMsg += "Potential problems in enumeration phase can be expected" logger.warning(warnMsg) + # 恢复之前的注入点 kb.injection = popValue() @stackedmethod @@ -1001,9 +1020,12 @@ def checkFilteredChars(injection): debugMsg = "checking for filtered characters" logger.debug(debugMsg) + # 将当前的注入点保存到栈中 pushValue(kb.injection) + # 设置当前的注入点 kb.injection = injection + # 生成一个随机数 randInt = randomInt() # all other techniques are already using parentheses in tests @@ -1025,17 +1047,23 @@ def checkFilteredChars(injection): kb.injection = popValue() +# 定义一个函数,用于检查SQL注入 def heuristicCheckSqlInjection(place, parameter): + # 如果配置文件中设置了跳过启发式测试,则返回None if conf.skipHeuristics: return None + # 获取原始值 origValue = conf.paramDict[place][parameter] + # 获取参数类型 paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place + # 定义前缀、后缀和随机字符串 prefix = "" suffix = "" randStr = "" + # 如果配置文件中设置了前缀或后缀,则获取前缀和后缀 if conf.prefix or conf.suffix: if conf.prefix: prefix = conf.prefix @@ -1043,52 +1071,82 @@ def heuristicCheckSqlInjection(place, parameter): if conf.suffix: suffix = conf.suffix + # 生成一个包含一个单引号和一个双引号的随机字符串 while randStr.count('\'') != 1 or randStr.count('\"') != 1: randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET) + # 设置启发式模式为True kb.heuristicMode = True + # 构造payload payload = "%s%s%s" % (prefix, randStr, suffix) + # 使用agent.payload方法构造payload payload = agent.payload(place, parameter, newValue=payload) + # 发送请求并获取页面和响应码 page, _, code = Request.queryPage(payload, place, content=True, raise404=False) + # 将页面和响应码保存到kb中 kb.heuristicPage = page kb.heuristicCode = code + # 设置启发式模式为False kb.heuristicMode = False + # 解析页面中的文件路径 parseFilePaths(page) + # 判断是否是数据库错误 result = wasLastResponseDBMSError() + # 构造提示信息 infoMsg = "heuristic (basic) test shows that %sparameter '%s' might " % ("%s " % paramType if paramType != parameter else "", parameter) + # 判断page中是否包含FORMAT_EXCEPTION_STRINGS中的任意一个字符串 def _(page): return any(_ in (page or "") for _ in FORMAT_EXCEPTION_STRINGS) + # 判断page中是否包含FORMAT_EXCEPTION_STRINGS中的任意一个字符串,且kb.originalPage中不包含 casting = _(page) and not _(kb.originalPage) + # 如果没有进行类型转换,且result为空,kb.dynamicParameter为真,origValue为数字,且kb.heavilyDynamic为假 if not casting and not result and kb.dynamicParameter and origValue.isdigit() and not kb.heavilyDynamic: + # 生成一个随机整数 randInt = int(randomInt()) + # 生成payload payload = "%s%s%s" % (prefix, "%d-%d" % (int(origValue) + randInt, randInt), suffix) + # 使用agent.payload生成payload payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE) + # 使用Request.queryPage查询页面 result = Request.queryPage(payload, place, raise404=False) + # 如果result为空 if not result: + # 生成一个随机字符串 randStr = randomStr() + # 生成payload payload = "%s%s%s" % (prefix, "%s.%d%s" % (origValue, random.randint(1, 9), randStr), suffix) + # 使用agent.payload生成payload payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE) + # 使用Request.queryPage查询页面 casting = Request.queryPage(payload, place, raise404=False) + # 根据casting和result的值,设置kb.heuristicTest的值 kb.heuristicTest = HEURISTIC_TEST.CASTED if casting else HEURISTIC_TEST.NEGATIVE if not result else HEURISTIC_TEST.POSITIVE + # 如果kb.heavilyDynamic为真 if kb.heavilyDynamic: + # 输出debug信息 debugMsg = "heuristic check stopped because of heavy dynamicity" logger.debug(debugMsg) + # 返回kb.heuristicTest的值 return kb.heuristicTest + # 如果casting为真 if casting: + # 输出错误信息 errMsg = "possible %s casting detected (e.g. '" % ("integer" if origValue.isdigit() else "type") + # 获取url的后缀 platform = conf.url.split('.')[-1].lower() + # 根据后缀,输出不同的错误信息 if platform == WEB_PLATFORM.ASP: errMsg += "%s=CInt(request.querystring(\"%s\"))" % (parameter, parameter) elif platform == WEB_PLATFORM.ASPX: @@ -1101,45 +1159,68 @@ def heuristicCheckSqlInjection(place, parameter): errMsg += "') at the back-end web application" logger.error(errMsg) + # 如果kb.ignoreCasted为空 if kb.ignoreCasted is None: + # 输出提示信息 message = "do you want to skip those kind of cases (and save scanning time)? %s " % ("[Y/n]" if conf.multipleTargets else "[y/N]") + # 读取用户输入,设置kb.ignoreCasted的值 kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N', boolean=True) + # 如果result为真 elif result: + # 输出信息 infoMsg += "be injectable" + # 如果Backend.getErrorParsedDBMSes()不为空 if Backend.getErrorParsedDBMSes(): + # 输出信息 infoMsg += " (possible DBMS: '%s')" % Format.getErrorParsedDBMSes() logger.info(infoMsg) + # 如果以上条件都不满足 else: + # 输出警告信息 infoMsg += "not be injectable" logger.warning(infoMsg) + # 设置kb.heuristicMode为真 kb.heuristicMode = True + # 设置kb.disableHtmlDecoding为真 kb.disableHtmlDecoding = True + # 生成两个随机字符串 randStr1, randStr2 = randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH), randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH) + # 生成value value = "%s%s%s" % (randStr1, DUMMY_NON_SQLI_CHECK_APPENDIX, randStr2) + # 生成payload payload = "%s%s%s" % (prefix, "'%s" % value, suffix) + # 使用agent.payload生成payload payload = agent.payload(place, parameter, newValue=payload) + # 使用Request.queryPage查询页面 page, _, _ = Request.queryPage(payload, place, content=True, raise404=False) + # 获取paramType paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place - # Reference: https://bugs.python.org/issue18183 if value.upper() in (page or "").upper(): + # 如果value的大写字母在page的大写字母中,则执行以下代码 infoMsg = "heuristic (XSS) test shows that %sparameter '%s' might be vulnerable to cross-site scripting (XSS) attacks" % ("%s " % paramType if paramType != parameter else "", parameter) + # 输出信息,表示参数可能存在XSS攻击 logger.info(infoMsg) if conf.beep: + # 如果配置文件中设置了beep,则执行beep函数 beep() for match in re.finditer(FI_ERROR_REGEX, page or ""): + # 在page中查找FI_ERROR_REGEX,如果找到,则执行以下代码 if randStr1.lower() in match.group(0).lower(): + # 如果randStr1的小写字母在match.group(0)的小写字母中,则执行以下代码 infoMsg = "heuristic (FI) test shows that %sparameter '%s' might be vulnerable to file inclusion (FI) attacks" % ("%s " % paramType if paramType != parameter else "", parameter) + # 输出信息,表示参数可能存在FI攻击 logger.info(infoMsg) if conf.beep: + # 如果配置文件中设置了beep,则执行beep函数 beep() break @@ -1157,6 +1238,7 @@ def checkDynParam(place, parameter, value): """ if kb.choices.redirect: + # 如果kb.choices.redirect为True,则返回None return None kb.matchRatio = None @@ -1166,11 +1248,14 @@ def checkDynParam(place, parameter, value): paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place infoMsg = "testing if %sparameter '%s' is dynamic" % ("%s " % paramType if paramType != parameter else "", parameter) + # 输出信息,表示正在测试参数是否动态 logger.info(infoMsg) try: payload = agent.payload(place, parameter, value, getUnicode(randInt)) + # 生成payload dynResult = Request.queryPage(payload, place, raise404=False) + # 发送payload,获取结果 except SqlmapConnectionException: pass @@ -1184,40 +1269,51 @@ def checkDynamicContent(firstPage, secondPage): This function checks for the dynamic content in the provided pages """ + # 如果没有网络连接,则跳过动态内容检查 if kb.nullConnection: debugMsg = "dynamic content checking skipped " debugMsg += "because NULL connection used" logger.debug(debugMsg) return + # 如果没有提供页面内容,则无法检查动态内容 if any(page is None for page in (firstPage, secondPage)): warnMsg = "can't check dynamic content " warnMsg += "because of lack of page content" logger.critical(warnMsg) return + # 如果提供了页面内容,并且页面内容长度超过最大长度,则无法计算相似度 if firstPage and secondPage and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (firstPage, secondPage)): ratio = None else: try: + # 获取当前线程的数据 seqMatcher = getCurrentThreadData().seqMatcher + # 设置第一个序列 seqMatcher.set_seq1(firstPage) + # 设置第二个序列 seqMatcher.set_seq2(secondPage) + # 计算相似度 ratio = seqMatcher.quick_ratio() except MemoryError: ratio = None + # 如果无法计算相似度,则跳过动态内容检查 if ratio is None: kb.skipSeqMatcher = True # In case of an intolerable difference turn on dynamicity removal engine elif ratio <= UPPER_RATIO_BOUND: + # 如果比率小于等于上限比率,则调用findDynamicContent函数 findDynamicContent(firstPage, secondPage) count = 0 + # 当Request.queryPage()返回False时,循环执行 while not Request.queryPage(): count += 1 + # 如果重试次数超过配置的最大重试次数,则输出警告信息,并将textOnly设置为True if count > conf.retries: warnMsg = "target URL content appears to be too dynamic. " warnMsg += "Switching to '--text-only' " @@ -1226,12 +1322,14 @@ def checkDynamicContent(firstPage, secondPage): conf.textOnly = True return + # 输出警告信息,表示目标URL内容过于动态,sqlmap将重试请求 warnMsg = "target URL content appears to be heavily dynamic. " warnMsg += "sqlmap is going to retry the request(s)" singleTimeLogMessage(warnMsg, logging.CRITICAL) kb.heavilyDynamic = True + # 重新查询页面内容 secondPage, _, _ = Request.queryPage(content=True) findDynamicContent(firstPage, secondPage) @@ -1249,17 +1347,22 @@ def checkStability(): infoMsg = "testing if the target URL content is stable" logger.info(infoMsg) + # 获取原始页面内容 firstPage = kb.originalPage # set inside checkConnection() + # 计算延迟时间 delay = MAX_STABILITY_DELAY - (time.time() - (kb.originalPageTime or 0)) delay = max(0, min(MAX_STABILITY_DELAY, delay)) time.sleep(delay) + # 重新查询页面内容 secondPage, _, _ = Request.queryPage(content=True, noteResponseTime=False, raise404=False) + # 如果存在重定向,则返回None if kb.choices.redirect: return None + # 比较两个页面内容是否相同 kb.pageStable = (firstPage == secondPage) if kb.pageStable: @@ -1281,6 +1384,7 @@ def checkStability(): warnMsg += "'Page comparison'" logger.warning(warnMsg) + # 提示用户如何继续 message = "how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] " choice = readInput(message, default='C').upper() @@ -1288,6 +1392,7 @@ def checkStability(): raise SqlmapUserQuitException elif choice == 'S': + # 如果用户选择字符串匹配,则调用showStaticWords函数 showStaticWords(firstPage, secondPage) message = "please enter value for parameter 'string': " @@ -1307,6 +1412,7 @@ def checkStability(): raise SqlmapNoneDataException(errMsg) elif choice == 'R': + # 如果用户选择正则表达式匹配,则提示用户输入正则表达式 message = "please enter value for parameter 'regex': " regex = readInput(message) @@ -1324,6 +1430,7 @@ def checkStability(): raise SqlmapNoneDataException(errMsg) else: + # 如果用户选择继续,则调用checkDynamicContent函数 checkDynamicContent(firstPage, secondPage) return kb.pageStable @@ -1334,12 +1441,15 @@ def checkWaf(): Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse """ + # 如果配置中存在字符串匹配、不匹配、正则表达式匹配、假数据、离线模式或跳过WAF检测,则返回None if any((conf.string, conf.notString, conf.regexp, conf.dummy, conf.offline, conf.skipWaf)): return None + # 如果原始HTTP状态码为404,则返回None if kb.originalCode == _http_client.NOT_FOUND: return None + # 从哈希数据库中获取WAF检测结果 _ = hashDBRetrieve(HASHDB_KEYS.CHECK_WAF_RESULT, True) if _ is not None: if _: @@ -1348,6 +1458,7 @@ def checkWaf(): logger.critical(warnMsg) return _ + # 如果原始页面内容为空,则返回None if not kb.originalPage: return None @@ -1356,36 +1467,44 @@ def checkWaf(): logger.info(infoMsg) retVal = False + # 生成随机payload payload = "%d %s" % (randomInt(), IPS_WAF_CHECK_PAYLOAD) place = PLACE.GET + # 如果URI参数存在,则将payload添加到URI参数中 if PLACE.URI in conf.parameters: value = "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload)) else: value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER value += "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload)) + # 保存当前状态 pushValue(kb.choices.redirect) pushValue(kb.resendPostOnRedirect) pushValue(conf.timeout) + # 设置重定向为True,重发POST请求为False,超时时间为IPS_WAF_CHECK_TIMEOUT kb.choices.redirect = REDIRECTION.YES kb.resendPostOnRedirect = False conf.timeout = IPS_WAF_CHECK_TIMEOUT try: + # 查询页面内容,并比较比率 retVal = (Request.queryPage(place=place, value=value, getRatioValue=True, noteResponseTime=False, silent=True, raise404=False, disableTampering=True)[1] or 0) < IPS_WAF_CHECK_RATIO except SqlmapConnectionException: retVal = True finally: kb.matchRatio = None + # 恢复之前的状态 conf.timeout = popValue() kb.resendPostOnRedirect = popValue() kb.choices.redirect = popValue() + # 将WAF检测结果写入哈希数据库 hashDBWrite(HASHDB_KEYS.CHECK_WAF_RESULT, retVal, True) + # 如果检测到WAF,则输出警告信息,并提示用户是否继续 if retVal: if not kb.identifiedWafs: warnMsg = "heuristics detected that the target " @@ -1411,9 +1530,11 @@ def checkNullConnection(): Reference: http://www.wisec.it/sectou.php?id=472f952d79293 """ + # 如果存在POST数据,则返回False if conf.data: return False + # 从哈希数据库中获取NULL连接检测结果 _ = hashDBRetrieve(HASHDB_KEYS.CHECK_NULL_CONNECTION_RESULT, True) if _ is not None: kb.nullConnection = _ @@ -1426,10 +1547,12 @@ def checkNullConnection(): infoMsg = "testing NULL connection to the target URL" logger.info(infoMsg) + # 保存当前状态 pushValue(kb.pageCompress) kb.pageCompress = False try: + # 使用HEAD方法测试NULL连接 page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD, raise404=False) if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}): @@ -1438,6 +1561,7 @@ def checkNullConnection(): infoMsg = "NULL connection is supported with HEAD method ('Content-Length')" logger.info(infoMsg) else: + # 使用GET方法测试NULL连接 page, headers, _ = Request.getPage(auxHeaders={HTTP_HEADER.RANGE: "bytes=-1"}) if page and len(page) == 1 and HTTP_HEADER.CONTENT_RANGE in (headers or {}): @@ -1446,6 +1570,7 @@ def checkNullConnection(): infoMsg = "NULL connection is supported with GET method ('Range')" logger.info(infoMsg) else: + # 使用skip-read方法测试NULL连接 _, headers, _ = Request.getPage(skipRead=True) if HTTP_HEADER.CONTENT_LENGTH in (headers or {}): @@ -1465,36 +1590,48 @@ def checkNullConnection(): return kb.nullConnection in getPublicTypeMembers(NULLCONNECTION, True) def checkConnection(suppressOutput=False): + # 获取当前线程数据 threadData = getCurrentThreadData() + # 检查主机名是否为IP地址 if not re.search(r"\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z", conf.hostname): + # 如果没有代理、Tor、Dummy或离线模式 if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)): try: + # 解析主机名 debugMsg = "resolving hostname '%s'" % conf.hostname logger.debug(debugMsg) socket.getaddrinfo(conf.hostname, None) except socket.gaierror: + # 主机名不存在 errMsg = "host '%s' does not exist" % conf.hostname raise SqlmapConnectionException(errMsg) except socket.error as ex: + # 解析主机名时出现问题 errMsg = "problem occurred while " errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex)) raise SqlmapConnectionException(errMsg) except UnicodeError as ex: + # 处理主机名时出现问题 errMsg = "problem occurred while " errMsg += "handling a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex)) raise SqlmapDataException(errMsg) + # 如果没有抑制输出,并且不是Dummy或离线模式 if not suppressOutput and not conf.dummy and not conf.offline: + # 测试连接到目标URL infoMsg = "testing connection to the target URL" logger.info(infoMsg) try: + # 获取页面内容 kb.originalPageTime = time.time() page, headers, _ = Request.queryPage(content=True, noteResponseTime=False) + # 获取原始响应 rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page) + # 如果提供了字符串,检查字符串是否在页面内容中 if conf.string: infoMsg = "testing if the provided string is within the " infoMsg += "target URL page content" @@ -1506,6 +1643,7 @@ def checkConnection(suppressOutput=False): warnMsg += "URL raw response, sqlmap will carry on anyway" logger.warning(warnMsg) + # 如果提供了正则表达式,检查正则表达式是否匹配页面内容 if conf.regexp: infoMsg = "testing if the provided regular expression matches within " infoMsg += "the target URL page content" @@ -1519,19 +1657,25 @@ def checkConnection(suppressOutput=False): kb.errorIsNone = False + # 如果服务器头包含不兼容的服务器,关闭预连接机制 if any(_ in (kb.serverHeader or "") for _ in PRECONNECT_INCOMPATIBLE_SERVERS): singleTimeWarnMessage("turning off pre-connect mechanism because of incompatible server ('%s')" % kb.serverHeader) conf.disablePrecon = True + # 如果没有原始页面,并且最后一个响应是HTTP错误 if not kb.originalPage and wasLastResponseHTTPError(): + # 如果最后一个请求的HTTP错误代码不在忽略代码中 if getLastRequestHTTPError() not in (conf.ignoreCode or []): errMsg = "unable to retrieve page content" raise SqlmapConnectionException(errMsg) + # 如果最后一个响应是DBMS错误 elif wasLastResponseDBMSError(): warnMsg = "there is a DBMS error found in the HTTP response body " warnMsg += "which could interfere with the results of the tests" logger.warning(warnMsg) + # 如果最后一个响应是HTTP错误 elif wasLastResponseHTTPError(): + # 如果最后一个请求的HTTP错误代码不在忽略代码中 if getLastRequestHTTPError() not in (conf.ignoreCode or []): warnMsg = "the web server responded with an HTTP error code (%d) " % getLastRequestHTTPError() warnMsg += "which could interfere with the results of the tests" @@ -1539,14 +1683,20 @@ def checkConnection(suppressOutput=False): else: kb.errorIsNone = True + # 如果重定向为是,并且最后一个重定向URL和最后一个请求UID相同 if kb.choices.redirect == REDIRECTION.YES and threadData.lastRedirectURL and threadData.lastRedirectURL[0] == threadData.lastRequestUID: + # 如果最后一个重定向URL以https://开头,并且主机名在最后一个重定向URL中 if (threadData.lastRedirectURL[1] or "").startswith("https://") and conf.hostname in getUnicode(threadData.lastRedirectURL[1]): + # 将URL改为https:// conf.url = re.sub(r"https?://", "https://", conf.url) + # 获取端口号 match = re.search(r":(\d+)", threadData.lastRedirectURL[1]) port = match.group(1) if match else 443 + # 将URL中的端口号改为最后一个重定向URL中的端口号 conf.url = re.sub(r":\d+(/|\Z)", r":%s\g<1>" % port, conf.url) except SqlmapConnectionException as ex: + # 如果提供了IPv6地址,检查连接 if conf.ipv6: warnMsg = "check connection to a provided " warnMsg += "IPv6 address with a tool like ping6 " @@ -1555,13 +1705,16 @@ def checkConnection(suppressOutput=False): warnMsg += "any addressing issues" singleTimeWarnMessage(warnMsg) + # 如果HTTP错误代码为404 if any(code in kb.httpErrorCodes for code in (_http_client.NOT_FOUND, )): errMsg = getSafeExString(ex) logger.critical(errMsg) + # 如果有多个目标 if conf.multipleTargets: return False + # 提示用户是否退出 msg = "it is not recommended to continue in this kind of cases. Do you want to quit and make sure that everything is set up properly? [Y/n] " if readInput(msg, default='Y', boolean=True): raise SqlmapSilentQuitException @@ -1570,12 +1723,16 @@ def checkConnection(suppressOutput=False): else: raise finally: + # 将原始页面和页面模板设置为最后一个页面和最后一个代码 kb.originalPage = kb.pageTemplate = threadData.lastPage kb.originalCode = threadData.lastCode + # 如果提供了cookie,并且没有声明cookie,也没有在httpHeaders中声明cookie,也没有设置dropSetCookie if conf.cj and not conf.cookie and not any(_[0] == HTTP_HEADER.COOKIE for _ in conf.httpHeaders) and not conf.dropSetCookie: + # 获取cookie candidate = DEFAULT_COOKIE_DELIMITER.join("%s=%s" % (_.name, _.value) for _ in conf.cj) + # 提示用户是否使用这些cookie message = "you have not declared cookie(s), while " message += "server wants to set its own ('%s'). " % re.sub(r"(=[^=;]{10}[^=;])[^=;]+([^=;]{10})", r"\g<1>...\g<2>", candidate) message += "Do you want to use those [Y/n] " @@ -1585,8 +1742,11 @@ def checkConnection(suppressOutput=False): return True +# 检查网络连接 def checkInternet(): + # 获取页面内容 content = Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[0] + # 判断页面内容是否包含指定的值 return CHECK_INTERNET_VALUE in (content or "") def setVerbosity(): # Cross-referenced function