sqlmap/lib/request/comparison.py

129 lines
4.6 KiB
Python
Raw Normal View History

#!/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
"""
import re
from lib.core.common import extractRegexResult
from lib.core.common import getFilteredPageContent
from lib.core.common import listToStrValue
2010-12-04 13:13:18 +03:00
from lib.core.common import removeDynamicContent
from lib.core.common import wasLastRequestDBMSError
2010-12-26 16:20:52 +03:00
from lib.core.common import wasLastRequestHTTPError
from lib.core.data import conf
2010-09-13 17:31:01 +04:00
from lib.core.data import kb
from lib.core.data import logger
2011-02-22 16:18:47 +03:00
from lib.core.exception import sqlmapNoneDataException
from lib.core.settings import DEFAULT_PAGE_ENCODING
2010-11-10 01:49:31 +03:00
from lib.core.settings import DIFF_TOLERANCE
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
from lib.core.threads import getCurrentThreadData
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
seqMatcher = getCurrentThreadData().seqMatcher
seqMatcher.set_seq1(kb.pageTemplate)
def _(condition):
#condition = not condition if kb.negativeLogic else condition
return condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO)
if any([conf.string, conf.regexp]):
rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
# String to match in page when the query is valid
if conf.string:
return _(conf.string in rawResponse)
# Regular expression to match in page when the query is valid
if conf.regexp:
return _(re.search(conf.regexp, rawResponse, re.I | re.M) is not None)
2010-11-04 00:51:36 +03:00
# HTTP code to match when the query is valid
if isinstance(code, int) and conf.code:
return _(conf.code == code)
if page:
# In case of an DBMS error page return None
2010-12-26 16:20:52 +03:00
if kb.errorIsNone and (wasLastRequestDBMSError() or wasLastRequestHTTPError()):
return None
2010-11-07 03:12:00 +03:00
# Dynamic content lines to be excluded before comparison
if not kb.nullConnection:
2010-12-04 13:13:18 +03:00
page = removeDynamicContent(page)
seqMatcher.set_seq1(removeDynamicContent(kb.pageTemplate))
2010-11-04 00:51:36 +03:00
if not pageLength:
pageLength = len(page)
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
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:
# 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):
page = page.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
2011-06-17 20:58:50 +04:00
seq1, seq2 = None, None
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-17 21:10:52 +04:00
if seq1 is None or seq2 is None:
2011-06-17 21:12:47 +04:00
return None
else:
ratio = round(seqMatcher.quick_ratio(), 3)
2010-03-10 17:14:27 +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:
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)
# If it has been requested to return the ratio and not a comparison
# response
2011-02-04 02:25:56 +03:00
if getRatioValue:
return ratio
2010-12-27 21:27:42 +03:00
elif ratio > UPPER_RATIO_BOUND:
return True
2010-12-18 12:51:34 +03:00
elif kb.matchRatio is None:
return None
else:
return (ratio - kb.matchRatio) > DIFF_TOLERANCE