SIGN IN SIGN UP
sqlmapproject / sqlmap UNCLAIMED

Automatic SQL injection and database takeover tool

36950 0 0 Python
2019-05-08 12:47:52 +02:00
#!/usr/bin/env python
"""
2025-05-08 23:54:39 +02:00
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
2017-10-11 14:50:46 +02:00
See the file 'LICENSE' for copying permission
"""
2019-06-04 12:15:39 +02:00
from __future__ import division
import re
from lib.core.common import extractRegexResult
from lib.core.common import getFilteredPageContent
from lib.core.common import listToStrValue
2010-12-04 10:13:18 +00:00
from lib.core.common import removeDynamicContent
2021-05-25 14:40:15 +02:00
from lib.core.common import getLastRequestHTTPError
2013-01-29 20:53:11 +01:00
from lib.core.common import wasLastResponseDBMSError
from lib.core.common import wasLastResponseHTTPError
2019-05-03 13:20:15 +02:00
from lib.core.convert import getBytes
from lib.core.data import conf
2010-09-13 13:31:01 +00:00
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import DEFAULT_PAGE_ENCODING
2010-11-09 22:49:31 +00:00
from lib.core.settings import DIFF_TOLERANCE
from lib.core.settings import HTML_TITLE_REGEX
2019-06-04 14:44:06 +02:00
from lib.core.settings import LOWER_RATIO_BOUND
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
2011-02-03 23:25:56 +00:00
from lib.core.settings import MAX_RATIO
2019-06-04 14:44:06 +02:00
from lib.core.settings import MIN_RATIO
from lib.core.settings import REFLECTED_VALUE_MARKER
2010-12-24 11:06:57 +00:00
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.settings import URI_HTTP_HEADER
from lib.core.threads import getCurrentThreadData
2019-04-19 11:24:34 +02:00
from thirdparty import six
def comparison(page, headers, code=None, getRatioValue=False, pageLength=None):
if not isinstance(page, (six.text_type, six.binary_type, type(None))):
logger.critical("got page of type %s; repr(page)[:200]=%s" % (type(page), repr(page)[:200]))
try:
page = b"".join(page)
except:
page = six.text_type(page)
_ = _adjust(_comparison(page, headers, code, getRatioValue, pageLength), getRatioValue)
return _
def _adjust(condition, getRatioValue):
2012-08-22 09:58:39 +02:00
if not any((conf.string, conf.notString, conf.regexp, conf.code)):
2012-03-29 14:35:47 +00:00
# Negative logic approach is used in raw page comparison scheme as that what is "different" than original
# PAYLOAD.WHERE.NEGATIVE response is considered as True; in switch based approach negative logic is not
# applied as that what is by user considered as True is that what is returned by the comparison mechanism
# itself
2012-07-16 16:06:39 +02:00
retVal = not condition if kb.negativeLogic and condition is not None and not getRatioValue else condition
else:
retVal = condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO)
return retVal
def _comparison(page, headers, code, getRatioValue, pageLength):
threadData = getCurrentThreadData()
if kb.testMode:
2017-11-08 15:58:23 +01:00
threadData.lastComparisonHeaders = listToStrValue(_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)) if headers else ""
threadData.lastComparisonPage = page
2016-06-03 14:29:32 +02:00
threadData.lastComparisonCode = code
2010-11-03 21:51:36 +00:00
if page is None and pageLength is None:
return None
if any((conf.string, conf.notString, conf.regexp)):
2017-11-08 15:58:23 +01:00
rawResponse = "%s%s" % (listToStrValue(_ for _ in headers.headers if not _.startswith("%s:" % URI_HTTP_HEADER)) if headers else "", page)
2020-05-05 13:31:44 +02:00
# String to match in page when the query is True
if conf.string:
return conf.string in rawResponse
2020-05-05 13:31:44 +02:00
# String to match in page when the query is False
if conf.notString:
2020-05-05 13:31:44 +02:00
if conf.notString in rawResponse:
return False
else:
if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()):
return None
else:
return True
# Regular expression to match in page when the query is True and/or valid
if conf.regexp:
return re.search(conf.regexp, rawResponse, re.I | re.M) is not None
2010-11-03 21:51:36 +00:00
# HTTP code to match when the query is valid
2012-12-18 09:36:26 +01:00
if conf.code:
return conf.code == code
2016-08-26 12:28:35 +02:00
seqMatcher = threadData.seqMatcher
seqMatcher.set_seq1(kb.pageTemplate)
if page:
# In case of an DBMS error page return None
if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()) and not kb.negativeLogic:
2021-05-25 14:40:15 +02:00
if not (wasLastResponseHTTPError() and getLastRequestHTTPError() in (conf.ignoreCode or [])):
return None
2010-11-07 00:12:00 +00:00
# Dynamic content lines to be excluded before comparison
if not kb.nullConnection:
2010-12-04 10:13:18 +00:00
page = removeDynamicContent(page)
seqMatcher.set_seq1(removeDynamicContent(kb.pageTemplate))
2010-11-03 21:51:36 +00:00
if not pageLength:
pageLength = len(page)
if kb.nullConnection and pageLength:
2011-02-22 13:18:47 +00:00
if not seqMatcher.a:
2013-07-31 09:24:34 +02:00
errMsg = "problem occurred while retrieving original page content "
2011-04-21 22:31:02 +00:00
errMsg += "which prevents sqlmap from continuation. Please rerun, "
errMsg += "and if the problem persists turn off any optimization switches"
raise SqlmapNoneDataException(errMsg)
2011-02-22 13:18:47 +00:00
ratio = 1. * pageLength / len(seqMatcher.a)
2010-11-07 16:23:03 +00:00
2010-09-16 09:32:09 +00:00
if ratio > 1.:
ratio = 1. / ratio
else:
# Preventing "Unicode equal comparison failed to convert both arguments to Unicode"
# (e.g. if one page is PDF and the other is HTML)
2019-04-19 11:24:34 +02:00
if isinstance(seqMatcher.a, six.binary_type) and isinstance(page, six.text_type):
page = getBytes(page, kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore")
elif isinstance(seqMatcher.a, six.text_type) and isinstance(page, six.binary_type):
2025-02-26 17:36:02 +01:00
seqMatcher.set_seq1(getBytes(seqMatcher.a, kb.pageEncoding or DEFAULT_PAGE_ENCODING, "ignore"))
2017-12-13 10:46:46 +01:00
if any(_ is None for _ in (page, seqMatcher.a)):
return None
elif seqMatcher.a and page and seqMatcher.a == page:
ratio = 1.
elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)):
2017-12-13 10:46:46 +01:00
if not page or not seqMatcher.a:
return float(seqMatcher.a == page)
else:
ratio = 1. * len(seqMatcher.a) / len(page)
if ratio > 1:
ratio = 1. / ratio
2011-06-17 16:58:50 +00:00
else:
seq1, seq2 = None, None
2011-06-17 16:58:50 +00:00
if conf.titles:
seq1 = extractRegexResult(HTML_TITLE_REGEX, seqMatcher.a)
seq2 = extractRegexResult(HTML_TITLE_REGEX, page)
else:
seq1 = getFilteredPageContent(seqMatcher.a, True) if conf.textOnly else seqMatcher.a
seq2 = getFilteredPageContent(page, True) if conf.textOnly else page
if seq1 is None or seq2 is None:
return None
2025-02-26 17:36:02 +01:00
if isinstance(seq1, six.binary_type):
seq1 = seq1.replace(REFLECTED_VALUE_MARKER.encode(), b"")
elif isinstance(seq1, six.text_type):
seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
if isinstance(seq2, six.binary_type):
seq2 = seq2.replace(REFLECTED_VALUE_MARKER.encode(), b"")
elif isinstance(seq2, six.text_type):
seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
2014-12-26 22:24:28 +01:00
if kb.heavilyDynamic:
2025-02-26 17:36:02 +01:00
seq1 = seq1.split("\n" if isinstance(seq1, six.text_type) else b"\n")
seq2 = seq2.split("\n" if isinstance(seq2, six.text_type) else b"\n")
2021-03-08 15:40:05 +01:00
key = None
else:
key = (hash(seq1), hash(seq2))
seqMatcher.set_seq1(seq1)
seqMatcher.set_seq2(seq2)
2021-03-03 23:28:27 +01:00
if key in kb.cache.comparison:
ratio = kb.cache.comparison[key]
else:
ratio = round(seqMatcher.quick_ratio() if not kb.heavilyDynamic else seqMatcher.ratio(), 3)
2021-03-04 08:26:23 +01:00
if key:
kb.cache.comparison[key] = ratio
2010-03-10 14:14:27 +00:00
# If the url is stable and we did not set yet the match ratio and the
# current injected value changes the url page content
2010-12-18 09:51:34 +00:00
if kb.matchRatio is None:
if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND:
2010-12-18 09:51:34 +00:00
kb.matchRatio = ratio
logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio)
2017-02-06 13:28:33 +01:00
if kb.testMode:
threadData.lastComparisonRatio = ratio
# If it has been requested to return the ratio and not a comparison
# response
2011-02-03 23:25:56 +00:00
if getRatioValue:
return ratio
2010-12-27 18:27:42 +00:00
elif ratio > UPPER_RATIO_BOUND:
return True
elif ratio < LOWER_RATIO_BOUND:
return False
2010-12-18 09:51:34 +00:00
elif kb.matchRatio is None:
return None
else:
return (ratio - kb.matchRatio) > DIFF_TOLERANCE