From 78fdb27a0b0eeb28e347611470101eb87e03ad44 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 3 Jun 2016 15:51:52 +0200 Subject: [PATCH] More improvements --- lib/controller/checks.py | 71 ++++++++++++++++++++++++++-------------- lib/core/settings.py | 4 +-- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index f6c65526f..ae9760a3f 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -446,12 +446,12 @@ def checkSqlInjection(place, parameter, value): kb.matchRatio = None kb.negativeLogic = (where == PAYLOAD.WHERE.NEGATIVE) Request.queryPage(genCmpPayload(), place, raise404=False) - falsePage, falseHeaders = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders + falsePage, falseHeaders, falseCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode falseRawResponse = "%s%s" % (falseHeaders, falsePage) # Perform the test's True request trueResult = Request.queryPage(reqPayload, place, raise404=False) - truePage, trueHeaders = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders + truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode trueRawResponse = "%s%s" % (trueHeaders, truePage) if trueResult and not(truePage == falsePage and not kb.nullConnection): @@ -473,32 +473,52 @@ def checkSqlInjection(place, parameter, value): kb.matchRatio = _ logger.debug("adjusting match ratio for current parameter to %.3f" % kb.matchRatio) + injectable = True + + if injectable and kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): + if all((falseCode, trueCode)) and falseCode != trueCode: + conf.code = trueCode + + infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --code=%d)" % (paramType, parameter, title, conf.code) + logger.info(infoMsg) + else: + trueSet = set(extractTextTagContent(trueRawResponse)) + trueSet = trueSet.union(__ for _ in trueSet for __ in _.split()) + + falseSet = set(extractTextTagContent(falseRawResponse)) + falseSet = falseSet.union(__ for _ in falseSet for __ in _.split()) + + candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet))) + + if candidates: + candidates = sorted(candidates, key=lambda _: len(_)) + for candidate in candidates: + if re.match(r"\A\w+\Z", candidate): + break + + conf.string = candidate + + infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'")) + logger.info(infoMsg) + + if not any((conf.string, conf.notString)): + candidates = filter(None, (_.strip() if _.strip() in falseRawResponse and _.strip() not in trueRawResponse else None for _ in (falseSet - trueSet))) + + if candidates: + candidates = sorted(candidates, key=lambda _: len(_)) + for candidate in candidates: + if re.match(r"\A\w+\Z", candidate): + break + + conf.notString = candidate + + infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --not-string=\"%s\")" % (paramType, parameter, title, repr(conf.notString).lstrip('u').strip("'")) + logger.info(infoMsg) + + if not any((conf.string, conf.notString, conf.code)): infoMsg = "%s parameter '%s' appears to be '%s' injectable " % (paramType, parameter, title) logger.info(infoMsg) - injectable = True - - if not any((conf.string, conf.notString, conf.regexp, conf.code)) and kb.pageStable and injectable: - trueSet = set(extractTextTagContent(trueRawResponse)) - trueSet = trueSet.union(__ for _ in trueSet for __ in _.split()) - - falseSet = set(extractTextTagContent(falseRawResponse)) - falseSet = falseSet.union(__ for _ in falseSet for __ in _.split()) - - candidates = filter(None, (_.strip() if _.strip() in trueRawResponse and _.strip() not in falseRawResponse else None for _ in (trueSet - falseSet))) - - if candidates: - candidates = sorted(candidates, key=lambda _: len(_)) - for candidate in candidates: - if re.match(r"\A\w+\Z", candidate): - break - conf.string = candidate - - infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'")) - logger.info(infoMsg) - - injectable = True - # In case of error-based SQL injection elif method == PAYLOAD.METHOD.GREP: # Perform the test's request and grep the response @@ -648,6 +668,7 @@ def checkSqlInjection(place, parameter, value): injection.conf.textOnly = conf.textOnly injection.conf.titles = conf.titles + injection.conf.code = conf.code injection.conf.string = conf.string injection.conf.notString = conf.notString injection.conf.regexp = conf.regexp diff --git a/lib/core/settings.py b/lib/core/settings.py index 20242271f..6fb9ddf4c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from lib.core.enums import OS from lib.core.revision import getRevisionNumber # sqlmap version (...) -VERSION = "1.0.6.22" +VERSION = "1.0.6.23" REVISION = getRevisionNumber() STABLE = VERSION.count('.') <= 2 VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev") @@ -540,7 +540,7 @@ HASHDB_FLUSH_RETRIES = 3 HASHDB_END_TRANSACTION_RETRIES = 3 # Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism) -HASHDB_MILESTONE_VALUE = "ERqvmQHalF" # "".join(random.sample(string.ascii_letters, 10)) +HASHDB_MILESTONE_VALUE = "pGBhWXgbtJ" # import random, string; print "".join(random.sample(string.ascii_letters, 10)) # Warn user of possible delay due to large page dump in full UNION query injections LARGE_OUTPUT_THRESHOLD = 1024 ** 2