mirror of
				https://github.com/sqlmapproject/sqlmap.git
				synced 2025-11-04 09:57:38 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			173 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
"""
 | 
						|
Copyright (c) 2006-2015 sqlmap developers (http://sqlmap.org/)
 | 
						|
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
 | 
						|
from lib.core.common import removeDynamicContent
 | 
						|
from lib.core.common import wasLastResponseDBMSError
 | 
						|
from lib.core.common import wasLastResponseHTTPError
 | 
						|
from lib.core.data import conf
 | 
						|
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
 | 
						|
from lib.core.settings import DIFF_TOLERANCE
 | 
						|
from lib.core.settings import HTML_TITLE_REGEX
 | 
						|
from lib.core.settings import MIN_RATIO
 | 
						|
from lib.core.settings import MAX_RATIO
 | 
						|
from lib.core.settings import REFLECTED_VALUE_MARKER
 | 
						|
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):
 | 
						|
    _ = _adjust(_comparison(page, headers, code, getRatioValue, pageLength), getRatioValue)
 | 
						|
    return _
 | 
						|
 | 
						|
def _adjust(condition, getRatioValue):
 | 
						|
    if not any((conf.string, conf.notString, conf.regexp, conf.code)):
 | 
						|
        # 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
 | 
						|
        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:
 | 
						|
        threadData.lastComparisonHeaders = listToStrValue(headers.headers) if headers else ""
 | 
						|
        threadData.lastComparisonPage = page
 | 
						|
 | 
						|
    if page is None and pageLength is None:
 | 
						|
        return None
 | 
						|
 | 
						|
    seqMatcher = threadData.seqMatcher
 | 
						|
    seqMatcher.set_seq1(kb.pageTemplate)
 | 
						|
 | 
						|
    if any((conf.string, conf.notString, conf.regexp)):
 | 
						|
        rawResponse = "%s%s" % (listToStrValue(headers.headers) if headers else "", page)
 | 
						|
 | 
						|
        # String to match in page when the query is True and/or valid
 | 
						|
        if conf.string:
 | 
						|
            return conf.string in rawResponse
 | 
						|
 | 
						|
        # String to match in page when the query is False and/or invalid
 | 
						|
        if conf.notString:
 | 
						|
            return conf.notString not in rawResponse
 | 
						|
 | 
						|
        # 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
 | 
						|
 | 
						|
    # HTTP code to match when the query is valid
 | 
						|
    if conf.code:
 | 
						|
        return conf.code == code
 | 
						|
 | 
						|
    if page:
 | 
						|
        # In case of an DBMS error page return None
 | 
						|
        if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()):
 | 
						|
            return None
 | 
						|
 | 
						|
        # Dynamic content lines to be excluded before comparison
 | 
						|
        if not kb.nullConnection:
 | 
						|
            page = removeDynamicContent(page)
 | 
						|
            seqMatcher.set_seq1(removeDynamicContent(kb.pageTemplate))
 | 
						|
 | 
						|
        if not pageLength:
 | 
						|
            pageLength = len(page)
 | 
						|
 | 
						|
    if kb.nullConnection and pageLength:
 | 
						|
        if not seqMatcher.a:
 | 
						|
            errMsg = "problem occurred while retrieving original page content "
 | 
						|
            errMsg += "which prevents sqlmap from continuation. Please rerun, "
 | 
						|
            errMsg += "and if the problem persists turn off any optimization switches"
 | 
						|
            raise SqlmapNoneDataException(errMsg)
 | 
						|
 | 
						|
        ratio = 1. * pageLength / len(seqMatcher.a)
 | 
						|
 | 
						|
        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')
 | 
						|
 | 
						|
        seq1, seq2 = None, None
 | 
						|
 | 
						|
        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
 | 
						|
 | 
						|
        seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
 | 
						|
        seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
 | 
						|
 | 
						|
        count = 0
 | 
						|
        while count < min(len(seq1), len(seq2)):
 | 
						|
            if seq1[count] == seq2[count]:
 | 
						|
                count += 1
 | 
						|
            else:
 | 
						|
                break
 | 
						|
        if count:
 | 
						|
            seq1 = seq1[count:]
 | 
						|
            seq2 = seq2[count:]
 | 
						|
 | 
						|
        while True:
 | 
						|
            try:
 | 
						|
                seqMatcher.set_seq1(seq1)
 | 
						|
            except MemoryError:
 | 
						|
                seq1 = seq1[:len(seq1) / 1024]
 | 
						|
            else:
 | 
						|
                break
 | 
						|
 | 
						|
        while True:
 | 
						|
            try:
 | 
						|
                seqMatcher.set_seq2(seq2)
 | 
						|
            except MemoryError:
 | 
						|
                seq2 = seq2[:len(seq2) / 1024]
 | 
						|
            else:
 | 
						|
                break
 | 
						|
 | 
						|
        ratio = round(seqMatcher.quick_ratio(), 3)
 | 
						|
 | 
						|
    # If the url is stable and we did not set yet the match ratio and the
 | 
						|
    # current injected value changes the url page content
 | 
						|
    if kb.matchRatio is None:
 | 
						|
        if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND:
 | 
						|
            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
 | 
						|
    if getRatioValue:
 | 
						|
        return ratio
 | 
						|
 | 
						|
    elif ratio > UPPER_RATIO_BOUND:
 | 
						|
        return True
 | 
						|
 | 
						|
    elif kb.matchRatio is None:
 | 
						|
        return None
 | 
						|
 | 
						|
    else:
 | 
						|
        return (ratio - kb.matchRatio) > DIFF_TOLERANCE
 |