2008-12-05 18:34:13 +03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
"""
|
|
|
|
$Id$
|
|
|
|
|
2012-01-11 18:59:46 +04:00
|
|
|
Copyright (c) 2006-2012 sqlmap developers (http://www.sqlmap.org/)
|
2010-10-15 03:18:29 +04:00
|
|
|
See the file 'doc/COPYING' for copying permission
|
2008-12-05 18:34:13 +03:00
|
|
|
"""
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
2011-06-11 03:18:43 +04:00
|
|
|
from lib.core.common import extractRegexResult
|
2011-01-14 17:37:03 +03:00
|
|
|
from lib.core.common import getFilteredPageContent
|
2011-08-12 19:33:37 +04:00
|
|
|
from lib.core.common import listToStrValue
|
2010-12-04 13:13:18 +03:00
|
|
|
from lib.core.common import removeDynamicContent
|
2010-11-16 13:42:42 +03:00
|
|
|
from lib.core.common import wasLastRequestDBMSError
|
2010-12-26 16:20:52 +03:00
|
|
|
from lib.core.common import wasLastRequestHTTPError
|
2008-12-05 18:34:13 +03:00
|
|
|
from lib.core.data import conf
|
2010-09-13 17:31:01 +04:00
|
|
|
from lib.core.data import kb
|
2009-02-09 13:28:03 +03:00
|
|
|
from lib.core.data import logger
|
2011-02-22 16:18:47 +03:00
|
|
|
from lib.core.exception import sqlmapNoneDataException
|
2011-05-26 00:54:30 +04:00
|
|
|
from lib.core.settings import DEFAULT_PAGE_ENCODING
|
2010-11-10 01:49:31 +03:00
|
|
|
from lib.core.settings import DIFF_TOLERANCE
|
2011-06-11 03:18:43 +04:00
|
|
|
from lib.core.settings import HTML_TITLE_REGEX
|
2011-02-04 02:25:56 +03:00
|
|
|
from lib.core.settings import MIN_RATIO
|
|
|
|
from lib.core.settings import MAX_RATIO
|
2010-12-24 14:06:57 +03:00
|
|
|
from lib.core.settings import LOWER_RATIO_BOUND
|
|
|
|
from lib.core.settings import UPPER_RATIO_BOUND
|
2011-01-16 13:52:42 +03:00
|
|
|
from lib.core.threads import getCurrentThreadData
|
2008-12-05 18:34:13 +03:00
|
|
|
|
2011-08-12 20:48:11 +04:00
|
|
|
def comparison(page, headers, code=None, getRatioValue=False, pageLength=None):
|
2010-11-04 00:51:36 +03:00
|
|
|
if page is None and pageLength is None:
|
|
|
|
return None
|
|
|
|
|
2011-01-16 13:52:42 +03:00
|
|
|
seqMatcher = getCurrentThreadData().seqMatcher
|
|
|
|
seqMatcher.set_seq1(kb.pageTemplate)
|
2008-12-05 18:34:13 +03:00
|
|
|
|
2011-06-11 03:05:47 +04:00
|
|
|
if any([conf.string, conf.regexp]):
|
2011-08-12 19:33:37 +04:00
|
|
|
rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
|
2011-06-11 03:05:47 +04:00
|
|
|
|
2011-08-12 19:33:37 +04:00
|
|
|
# String to match in page when the query is valid
|
|
|
|
if conf.string:
|
|
|
|
condition = conf.string in rawResponse
|
|
|
|
return condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO)
|
|
|
|
|
|
|
|
# Regular expression to match in page when the query is valid
|
|
|
|
if conf.regexp:
|
|
|
|
condition = re.search(conf.regexp, rawResponse, re.I | re.M) is not None
|
|
|
|
return condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO)
|
2010-11-04 00:51:36 +03:00
|
|
|
|
2011-08-12 20:48:11 +04:00
|
|
|
if isinstance(code, int) and conf.code:
|
|
|
|
return code == conf.code
|
|
|
|
|
2011-06-11 03:05:47 +04:00
|
|
|
if page:
|
2010-11-13 01:44:15 +03:00
|
|
|
# In case of an DBMS error page return None
|
2010-12-26 16:20:52 +03:00
|
|
|
if kb.errorIsNone and (wasLastRequestDBMSError() or wasLastRequestHTTPError()):
|
2010-11-13 01:44:15 +03:00
|
|
|
return None
|
|
|
|
|
2010-11-07 03:12:00 +03:00
|
|
|
# Dynamic content lines to be excluded before comparison
|
2011-01-14 17:37:03 +03:00
|
|
|
if not kb.nullConnection:
|
2010-12-04 13:13:18 +03:00
|
|
|
page = removeDynamicContent(page)
|
2011-01-16 13:52:42 +03:00
|
|
|
seqMatcher.set_seq1(removeDynamicContent(kb.pageTemplate))
|
2010-11-04 00:51:36 +03:00
|
|
|
|
|
|
|
if not pageLength:
|
|
|
|
pageLength = len(page)
|
2010-11-03 15:40:11 +03:00
|
|
|
|
2011-02-03 18:55:19 +03:00
|
|
|
if kb.nullConnection and pageLength:
|
2011-02-22 16:18:47 +03:00
|
|
|
if not seqMatcher.a:
|
|
|
|
errMsg = "problem occured while retrieving original page content "
|
2011-04-22 02:31:02 +04:00
|
|
|
errMsg += "which prevents sqlmap from continuation. Please rerun, "
|
|
|
|
errMsg += "and if the problem persists turn off any optimization switches"
|
2011-02-22 16:18:47 +03:00
|
|
|
raise sqlmapNoneDataException, errMsg
|
|
|
|
|
2011-01-16 13:52:42 +03:00
|
|
|
ratio = 1. * pageLength / len(seqMatcher.a)
|
2010-11-07 19:23:03 +03:00
|
|
|
|
2010-09-16 13:32:09 +04:00
|
|
|
if ratio > 1.:
|
|
|
|
ratio = 1. / ratio
|
|
|
|
else:
|
2011-05-26 00:54:30 +04:00
|
|
|
# Preventing "Unicode equal comparison failed to convert both arguments to Unicode"
|
|
|
|
# (e.g. if one page is PDF and the other is HTML)
|
|
|
|
if isinstance(seqMatcher.a, str) and isinstance(page, unicode):
|
2011-06-07 09:57:21 +04:00
|
|
|
page = page.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
|
2011-05-26 00:54:30 +04:00
|
|
|
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
|
2011-06-07 09:57:21 +04:00
|
|
|
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
|
2011-05-26 00:54:30 +04:00
|
|
|
|
2011-06-17 20:58:50 +04:00
|
|
|
seq1, seq2 = None, None
|
|
|
|
|
2011-06-11 03:18:43 +04:00
|
|
|
if conf.titles:
|
2011-06-17 20:58:50 +04:00
|
|
|
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
|
|
|
|
|
2011-06-17 21:10:52 +04:00
|
|
|
if seq1 is not None:
|
2011-06-17 20:58:50 +04:00
|
|
|
seqMatcher.set_seq1(seq1)
|
|
|
|
|
2011-06-17 21:10:52 +04:00
|
|
|
if seq2 is not None:
|
2011-06-17 20:58:50 +04:00
|
|
|
seqMatcher.set_seq2(seq2)
|
2011-06-11 03:18:43 +04:00
|
|
|
|
2011-06-17 21:10:52 +04:00
|
|
|
if seq1 is None or seq2 is None:
|
2011-06-17 21:12:47 +04:00
|
|
|
return None
|
2011-05-24 19:03:21 +04:00
|
|
|
else:
|
|
|
|
ratio = round(seqMatcher.quick_ratio(), 3)
|
2010-03-10 17:14:27 +03:00
|
|
|
|
2009-02-09 13:28:03 +03: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 12:51:34 +03:00
|
|
|
if kb.matchRatio is None:
|
2011-04-18 01:58:34 +04:00
|
|
|
if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND:
|
2010-12-18 12:51:34 +03:00
|
|
|
kb.matchRatio = ratio
|
|
|
|
logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio)
|
2010-01-02 05:02:12 +03:00
|
|
|
|
2009-02-09 13:28:03 +03:00
|
|
|
# If it has been requested to return the ratio and not a comparison
|
|
|
|
# response
|
2011-02-04 02:25:56 +03:00
|
|
|
if getRatioValue:
|
2009-02-09 13:28:03 +03:00
|
|
|
return ratio
|
|
|
|
|
2010-12-27 21:27:42 +03:00
|
|
|
elif ratio > UPPER_RATIO_BOUND:
|
2010-11-05 16:14:12 +03:00
|
|
|
return True
|
|
|
|
|
2010-12-18 12:51:34 +03:00
|
|
|
elif kb.matchRatio is None:
|
2010-11-10 02:38:29 +03:00
|
|
|
return None
|
|
|
|
|
2008-12-20 04:54:08 +03:00
|
|
|
else:
|
2011-04-18 01:58:34 +04:00
|
|
|
return (ratio - kb.matchRatio) > DIFF_TOLERANCE
|