diff --git a/lib/controller/checks.py b/lib/controller/checks.py index a1e681ded..c07930ef6 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -17,6 +17,7 @@ from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import beep from lib.core.common import extractRegexResult +from lib.core.common import extractTextTagContent from lib.core.common import findDynamicContent from lib.core.common import Format from lib.core.common import getComparePageRatio @@ -329,9 +330,11 @@ def checkSqlInjection(place, parameter, value): kb.matchRatio = None kb.negativeLogic = (where == PAYLOAD.WHERE.NEGATIVE) Request.queryPage(genCmpPayload(), place, raise404=False) + falsePage = threadData.lastComparisonPage # Perform the test's True request trueResult = Request.queryPage(reqPayload, place, raise404=False) + truePage = threadData.lastComparisonPage if trueResult: falseResult = Request.queryPage(genCmpPayload(), place, raise404=False) @@ -342,6 +345,15 @@ def checkSqlInjection(place, parameter, value): logger.info(infoMsg) injectable = True + else: + trueSet = set(extractTextTagContent(truePage)) + falseSet = set(extractTextTagContent(falsePage)) + candidate = reduce(lambda x, y: x or (y.strip() if y.strip() in (kb.pageTemplate or "") else None), (trueSet - falseSet), None) + if candidate: + conf.string = candidate + infoMsg = "%s parameter '%s' is '%s' injectable (with --string='%s')" % (place, parameter, title, candidate) + logger.info(infoMsg) + injectable = True # In case of error-based SQL injection elif method == PAYLOAD.METHOD.GREP: diff --git a/lib/core/common.py b/lib/core/common.py index d6ec95b0b..06367f264 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -124,6 +124,7 @@ from lib.core.settings import TIME_STDEV_COEFF from lib.core.settings import DYNAMICITY_MARK_LENGTH from lib.core.settings import REFLECTIVE_MISS_THRESHOLD from lib.core.settings import SENSITIVE_DATA_REGEX +from lib.core.settings import TEXT_TAG_REGEX from lib.core.settings import UNION_UNIQUE_FIFO_LENGTH from lib.core.settings import URI_INJECTION_MARK_CHAR from lib.core.settings import URI_QUESTION_MARKER @@ -2155,6 +2156,13 @@ def extractRegexResult(regex, content, flags=0): return retVal +def extractTextTagContent(page): + """ + Returns list containing content from "textual" tags + """ + + return [_.group('result') for _ in re.finditer(TEXT_TAG_REGEX, page or "")] + def trimAlphaNum(value): """ Trims alpha numeric characters from start and ending of a given value diff --git a/lib/core/settings.py b/lib/core/settings.py index d544effcf..16e775fc8 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -62,10 +62,13 @@ URI_QUESTION_MARKER = "__QUESTION_MARK__" PAYLOAD_DELIMITER = "\x00" CHAR_INFERENCE_MARK = "%c" -PRINTABLE_CHAR_REGEX = r'[^\x00-\x1f\x7e-\xff]' +PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7e-\xff]" # regular expression used for extracting results from google search -GOOGLE_REGEX = r'url\?q=(http[^>]+)&sa=U&' +GOOGLE_REGEX = r"url\?q=(http[^>]+)&sa=U&" + +# regular expression used for extracting content from "textual" tags +TEXT_TAG_REGEX = r"(?si)<(abbr|acronym|b|blockquote|br|center|cite|code|dt|em|font|h\d|i|li|p|pre|q|strong|sub|sup|td|th|title|tt|u)(?!\w).*?>(?P[^<]+)" # dumping characters used in GROUP_CONCAT MySQL technique CONCAT_ROW_DELIMITER = ',' diff --git a/lib/core/threads.py b/lib/core/threads.py index e1cd35fc0..88c63c282 100644 --- a/lib/core/threads.py +++ b/lib/core/threads.py @@ -43,6 +43,7 @@ class _ThreadData(threading.local): self.disableStdOut = False self.hashDBCursor = None self.inTransaction = False + self.lastComparisonPage = None self.lastErrorPage = None self.lastHTTPError = None self.lastRedirectMsg = None diff --git a/lib/request/comparison.py b/lib/request/comparison.py index f06c55bb1..47ad22e63 100644 --- a/lib/request/comparison.py +++ b/lib/request/comparison.py @@ -45,10 +45,15 @@ def _adjust(condition, getRatioValue): return retVal def _comparison(page, headers, code, getRatioValue, pageLength): + threadData = getCurrentThreadData() + + if kb.testMode: + threadData.lastComparisonPage = page + if page is None and pageLength is None: return None - seqMatcher = getCurrentThreadData().seqMatcher + seqMatcher = threadData.seqMatcher seqMatcher.set_seq1(kb.pageTemplate) if any([conf.string, conf.regexp]):