refactoring, code clearing and removal of obsolete switch --longest-common

This commit is contained in:
Miroslav Stampar 2011-01-14 14:37:03 +00:00
parent 534f51f9fc
commit fb9d7cdfaa
11 changed files with 31 additions and 131 deletions

View File

@ -48,9 +48,6 @@ from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapNoneDataException from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUserQuitException from lib.core.exception import sqlmapUserQuitException
from lib.core.session import setDynamicMarkings from lib.core.session import setDynamicMarkings
from lib.core.session import setString
from lib.core.session import setRegexp
from lib.core.session import setTextOnly
from lib.core.settings import CONSTANT_RATIO from lib.core.settings import CONSTANT_RATIO
from lib.core.settings import UPPER_RATIO_BOUND from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
@ -424,9 +421,14 @@ def checkSqlInjection(place, parameter, value):
injection.data[stype].where = where injection.data[stype].where = where
injection.data[stype].vector = vector injection.data[stype].vector = vector
injection.data[stype].comment = comment injection.data[stype].comment = comment
injection.data[stype].matchRatio = kb.matchRatio
injection.data[stype].templatePayload = templatePayload injection.data[stype].templatePayload = templatePayload
injection.data[stype].conf = advancedDict()
injection.data[stype].conf.matchRatio = kb.matchRatio
injection.data[stype].conf.textOnly = conf.textOnly
injection.data[stype].conf.string = conf.string
injection.data[stype].conf.regexp = conf.regexp
if hasattr(test, "details"): if hasattr(test, "details"):
for detailKey, detailValue in test.details.items(): for detailKey, detailValue in test.details.items():
if detailKey == "dbms" and injection.dbms is None: if detailKey == "dbms" and injection.dbms is None:
@ -585,12 +587,6 @@ def checkDynamicContent(firstPage, secondPage):
logger.debug(debugMsg) logger.debug(debugMsg)
return return
if conf.longestCommon:
debugMsg = "dynamic content checking skipped "
debugMsg += "because longest common comparison used"
logger.debug(debugMsg)
return
conf.seqMatcher.set_seq1(firstPage) conf.seqMatcher.set_seq1(firstPage)
conf.seqMatcher.set_seq2(secondPage) conf.seqMatcher.set_seq2(secondPage)
@ -608,7 +604,6 @@ def checkDynamicContent(firstPage, secondPage):
logger.warn(warnMsg) logger.warn(warnMsg)
conf.textOnly = True conf.textOnly = True
setTextOnly()
return return
warnMsg = "target url is heavily dynamic" warnMsg = "target url is heavily dynamic"
@ -677,7 +672,6 @@ def checkStability():
if test: if test:
conf.string = test conf.string = test
setString()
if kb.nullConnection: if kb.nullConnection:
debugMsg = "turning off NULL connection " debugMsg = "turning off NULL connection "
@ -695,7 +689,6 @@ def checkStability():
if test: if test:
conf.regex = test conf.regex = test
setRegexp()
if kb.nullConnection: if kb.nullConnection:
debugMsg = "turning off NULL connection " debugMsg = "turning off NULL connection "
@ -709,7 +702,6 @@ def checkStability():
elif test and test[0] in ("t", "T"): elif test and test[0] in ("t", "T"):
conf.textOnly = True conf.textOnly = True
setTextOnly()
if kb.nullConnection: if kb.nullConnection:
debugMsg = "turning off NULL connection " debugMsg = "turning off NULL connection "
@ -727,24 +719,13 @@ def checkString():
if not conf.string: if not conf.string:
return True return True
condition = (
kb.resumedQueries.has_key(conf.url) and
kb.resumedQueries[conf.url].has_key("String") and
kb.resumedQueries[conf.url]["String"][:-1] == conf.string
)
if condition:
return True
infoMsg = "testing if the provided string is within the " infoMsg = "testing if the provided string is within the "
infoMsg += "target URL page content" infoMsg += "target URL page content"
logger.info(infoMsg) logger.info(infoMsg)
page, _ = Request.queryPage(content=True) page, _ = Request.queryPage(content=True)
if conf.string in page: if conf.string not in page:
setString()
else:
warnMsg = "you provided '%s' as the string to " % conf.string warnMsg = "you provided '%s' as the string to " % conf.string
warnMsg += "match, but such a string is not within the target " warnMsg += "match, but such a string is not within the target "
warnMsg += "URL page content original request, sqlmap will " warnMsg += "URL page content original request, sqlmap will "
@ -757,24 +738,13 @@ def checkRegexp():
if not conf.regexp: if not conf.regexp:
return True return True
condition = (
kb.resumedQueries.has_key(conf.url) and
kb.resumedQueries[conf.url].has_key("Regular expression") and
kb.resumedQueries[conf.url]["Regular expression"][:-1] == conf.regexp
)
if condition:
return True
infoMsg = "testing if the provided regular expression matches within " infoMsg = "testing if the provided regular expression matches within "
infoMsg += "the target URL page content" infoMsg += "the target URL page content"
logger.info(infoMsg) logger.info(infoMsg)
page, _ = Request.queryPage(content=True) page, _ = Request.queryPage(content=True)
if re.search(conf.regexp, page, re.I | re.M): if not re.search(conf.regexp, page, re.I | re.M):
setRegexp()
else:
warnMsg = "you provided '%s' as the regular expression to " % conf.regexp warnMsg = "you provided '%s' as the regular expression to " % conf.regexp
warnMsg += "match, but such a regular expression does not have any " warnMsg += "match, but such a regular expression does not have any "
warnMsg += "match within the target URL page content, sqlmap " warnMsg += "match within the target URL page content, sqlmap "

View File

@ -1943,7 +1943,20 @@ def initTechnique(technique=None):
if data: if data:
kb.pageTemplate, kb.errorIsNone = getPageTemplate(data.templatePayload, kb.injection.place) kb.pageTemplate, kb.errorIsNone = getPageTemplate(data.templatePayload, kb.injection.place)
kb.matchRatio = data.matchRatio
kb.matchRatio = data.conf.matchRatio
if data.conf.textOnly:
conf.textOnly = True
debugMsg = "restoring switch --text-only"
logger.debug(debugMsg)
if data.conf.string:
conf.string = data.conf.string
debugMsg = "restoring option --string '%s'" % data.conf.string
logger.debug(debugMsg)
if data.conf.regexp:
conf.regexp = data.conf.regexp
debugMsg = "restoring option --regexp '%s'" % data.conf.regexp
logger.debug(debugMsg)
else: else:
warnMsg = "there is no injection data available for technique " warnMsg = "there is no injection data available for technique "
warnMsg += "'%s'" % enumValueToNameLookup(PAYLOAD.TECHNIQUE, technique) warnMsg += "'%s'" % enumValueToNameLookup(PAYLOAD.TECHNIQUE, technique)

View File

@ -80,3 +80,4 @@ class injectionDict(advancedDict):
self.dbms = None self.dbms = None
self.dbms_version = None self.dbms_version = None
self.os = None self.os = None

View File

@ -1045,7 +1045,7 @@ def __cleanupOptions():
if conf.optimize: if conf.optimize:
#conf.predictOutput = True #conf.predictOutput = True
conf.keepAlive = True conf.keepAlive = True
conf.nullConnection = not (conf.textOnly or conf.longestCommon) conf.nullConnection = not conf.textOnly
conf.threads = 4 if conf.threads < 2 else conf.threads conf.threads = 4 if conf.threads < 2 else conf.threads
if conf.realTest: if conf.realTest:
@ -1320,10 +1320,6 @@ def __basicOptionValidation():
errMsg = "switch --text-only is incompatible with switch --null-connection" errMsg = "switch --text-only is incompatible with switch --null-connection"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
if conf.longestCommon and conf.nullConnection:
errMsg = "switch --longest-common is incompatible with switch --null-connection"
raise sqlmapSyntaxException, errMsg
if conf.data and conf.nullConnection: if conf.data and conf.nullConnection:
errMsg = "switch --data is incompatible with switch --null-connection" errMsg = "switch --data is incompatible with switch --null-connection"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg

View File

@ -70,8 +70,7 @@ optDict = {
"eString": "string", "eString": "string",
"eRegexp": "string", "eRegexp": "string",
"thold": "float", "thold": "float",
"textOnly": "boolean", "textOnly": "boolean"
"longestCommon": "boolean"
}, },
"Techniques": { "Techniques": {

View File

@ -42,48 +42,6 @@ def unSafeFormatString(value):
retVal = retVal.replace("__LEFT_SQUARE_BRACKET__", "[").replace("__RIGHT_SQUARE_BRACKET__", "]") retVal = retVal.replace("__LEFT_SQUARE_BRACKET__", "[").replace("__RIGHT_SQUARE_BRACKET__", "]")
return retVal return retVal
def setTextOnly():
"""
Save text only option to session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Text only") )
)
if condition:
dataToSessionFile("[%s][None][None][Text only][True]\n" % conf.url)
kb.originalPage = getFilteredPageContent(kb.originalPage)
kb.pageTemplates.clear()
def setString():
"""
Save string to match in session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("String") )
)
if condition:
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, safeFormatString(conf.string)))
def setRegexp():
"""
Save regular expression to match in session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Regular expression") )
)
if condition:
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, safeFormatString(conf.regexp)))
def setInjection(inj): def setInjection(inj):
""" """
Save information retrieved about injection place and parameter in the Save information retrieved about injection place and parameter in the
@ -202,23 +160,7 @@ def setRemoteTempPath():
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(conf.tmpPath))) dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(conf.tmpPath)))
def resumeConfKb(expression, url, value): def resumeConfKb(expression, url, value):
if expression == "Text only" and url == conf.url: if expression == "String" and url == conf.url:
value = unSafeFormatString(value[:-1])
logMsg = "resuming text only option '%s' from session file" % value
logger.info(logMsg)
if value and not conf.textOnly:
message = "you did not turned on --text-only switch this time "
message += "which could potentially lead to different "
message += "and/or unstable results. "
message += "Do you want to turn it on? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
conf.textOnly = value
elif expression == "String" and url == conf.url:
string = unSafeFormatString(value[:-1]) string = unSafeFormatString(value[:-1])
logMsg = "resuming string match '%s' from session file" % string logMsg = "resuming string match '%s' from session file" % string

View File

@ -30,7 +30,6 @@ from lib.core.exception import sqlmapSyntaxException
from lib.core.option import __setDBMS from lib.core.option import __setDBMS
from lib.core.option import __setKnowledgeBaseAttributes from lib.core.option import __setKnowledgeBaseAttributes
from lib.core.session import resumeConfKb from lib.core.session import resumeConfKb
from lib.core.session import setTextOnly
from lib.core.xmldump import dumper as xmldumper from lib.core.xmldump import dumper as xmldumper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
@ -265,13 +264,6 @@ def __createTargetDirs():
__createFilesDir() __createFilesDir()
__configureDumper() __configureDumper()
def __saveSwitches():
"""
Store critical switches to the session file.
"""
if conf.textOnly:
setTextOnly()
def __restoreCmdLineOptions(): def __restoreCmdLineOptions():
""" """
Restore command line options that could be possibly Restore command line options that could be possibly
@ -302,4 +294,3 @@ def setupTargetEnv():
__createTargetDirs() __createTargetDirs()
__setRequestParams() __setRequestParams()
__setOutputResume() __setOutputResume()
__saveSwitches()

View File

@ -214,10 +214,6 @@ def cmdLineParser():
action="store_true", default=False, action="store_true", default=False,
help="Compare pages based only on their textual content") help="Compare pages based only on their textual content")
detection.add_option("--longest-common", dest="longestCommon",
action="store_true", default=False,
help="Compare pages based on their longest common match")
# Techniques options # Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can " techniques = OptionGroup(parser, "Techniques", "These options can "

View File

@ -11,6 +11,7 @@ import re
from difflib import SequenceMatcher from difflib import SequenceMatcher
from lib.core.common import getFilteredPageContent
from lib.core.common import removeDynamicContent from lib.core.common import removeDynamicContent
from lib.core.common import wasLastRequestDBMSError from lib.core.common import wasLastRequestDBMSError
from lib.core.common import wasLastRequestHTTPError from lib.core.common import wasLastRequestHTTPError
@ -63,7 +64,7 @@ def comparison(page, headers=None, getSeqMatcher=False, pageLength=None):
return None return None
# Dynamic content lines to be excluded before comparison # Dynamic content lines to be excluded before comparison
if not kb.nullConnection and not conf.longestCommon: if not kb.nullConnection:
page = removeDynamicContent(page) page = removeDynamicContent(page)
conf.seqMatcher.set_seq1(removeDynamicContent(kb.pageTemplate)) conf.seqMatcher.set_seq1(removeDynamicContent(kb.pageTemplate))
@ -73,12 +74,10 @@ def comparison(page, headers=None, getSeqMatcher=False, pageLength=None):
if kb.locks.seqLock: if kb.locks.seqLock:
kb.locks.seqLock.acquire() kb.locks.seqLock.acquire()
if conf.longestCommon: if conf.textOnly:
(firstPage, secondPage) = (conf.seqMatcher.a, page) (conf.seqMatcher.a, page) = map(getFilteredPageContent, (conf.seqMatcher.a, page))
match = SequenceMatcher(None, firstPage, secondPage).find_longest_match(0, len(firstPage), 0, len(secondPage))
ratio = round(SequenceMatcher(None, firstPage[match[0]:match[0]+match[2]], secondPage[match[1]:match[1]+match[2]]).ratio(), 3)
elif not conf.eRegexp and not conf.eString and kb.nullConnection and pageLength: if not conf.eRegexp and not conf.eString and kb.nullConnection and pageLength:
ratio = 1. * pageLength / len(conf.seqMatcher.a) ratio = 1. * pageLength / len(conf.seqMatcher.a)
if ratio > 1.: if ratio > 1.:

View File

@ -458,9 +458,6 @@ class Connect:
threadData.lastQueryDuration = calculateDeltaSeconds(start) threadData.lastQueryDuration = calculateDeltaSeconds(start)
if conf.textOnly:
page = getFilteredPageContent(page)
if kb.testMode: if kb.testMode:
kb.testQueryCount += 1 kb.testQueryCount += 1

View File

@ -236,10 +236,6 @@ thold =
# Valid: True or False # Valid: True or False
textOnly = False textOnly = False
# Compare pages based on their longest common match
# Valid: True or False
longestCommon = False
# These options can be used to test for specific SQL injection technique # These options can be used to test for specific SQL injection technique
# or to use one of them to exploit the affected parameter(s) rather than # or to use one of them to exploit the affected parameter(s) rather than