mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-02-09 08:00:36 +03:00
lots of refactoring regarding removal of already obsolete session file mechanism
This commit is contained in:
parent
1e67b4f0b9
commit
ec44e88db8
|
@ -738,13 +738,6 @@ def dataToStdout(data, forceOutput=False):
|
||||||
logging._releaseLock()
|
logging._releaseLock()
|
||||||
setFormatterPrependFlag(len(data) == 1 and data not in ('\n', '\r') or len(data) > 2 and data[0] == '\r' and data[-1] != '\n')
|
setFormatterPrependFlag(len(data) == 1 and data not in ('\n', '\r') or len(data) > 2 and data[0] == '\r' and data[-1] != '\n')
|
||||||
|
|
||||||
def dataToSessionFile(data):
|
|
||||||
if not conf.sessionFile or kb.suppressSession:
|
|
||||||
return
|
|
||||||
|
|
||||||
conf.sessionFP.write(data)
|
|
||||||
conf.sessionFP.flush()
|
|
||||||
|
|
||||||
def dataToTrafficFile(data):
|
def dataToTrafficFile(data):
|
||||||
if not conf.trafficFile:
|
if not conf.trafficFile:
|
||||||
return
|
return
|
||||||
|
|
|
@ -143,14 +143,16 @@ class EXPECTED:
|
||||||
INT = "int"
|
INT = "int"
|
||||||
|
|
||||||
class HASHDB_KEYS:
|
class HASHDB_KEYS:
|
||||||
KB_ABS_FILE_PATHS = "KB_ABS_FILE_PATHS"
|
DBMS = "DBMS"
|
||||||
KB_CHARS = "KB_CHARS"
|
|
||||||
KB_BRUTE_TABLES = "KB_BRUTE_TABLES"
|
|
||||||
KB_BRUTE_COLUMNS = "KB_BRUTE_COLUMNS"
|
|
||||||
CONF_TMP_PATH = "CONF_TMP_PATH"
|
CONF_TMP_PATH = "CONF_TMP_PATH"
|
||||||
KB_XP_CMDSHELL_AVAILABLE = "KB_XP_CMDSHELL_AVAILABLE"
|
KB_ABS_FILE_PATHS = "KB_ABS_FILE_PATHS"
|
||||||
KB_INJECTIONS = "KB_INJECTIONS"
|
KB_BRUTE_COLUMNS = "KB_BRUTE_COLUMNS"
|
||||||
|
KB_BRUTE_TABLES = "KB_BRUTE_TABLES"
|
||||||
|
KB_CHARS = "KB_CHARS"
|
||||||
KB_DYNAMIC_MARKINGS = "KB_DYNAMIC_MARKINGS"
|
KB_DYNAMIC_MARKINGS = "KB_DYNAMIC_MARKINGS"
|
||||||
|
KB_INJECTIONS = "KB_INJECTIONS"
|
||||||
|
KB_XP_CMDSHELL_AVAILABLE = "KB_XP_CMDSHELL_AVAILABLE"
|
||||||
|
OS = "OS"
|
||||||
|
|
||||||
class REDIRECTION:
|
class REDIRECTION:
|
||||||
YES = "Y"
|
YES = "Y"
|
||||||
|
|
|
@ -1497,13 +1497,11 @@ def __setKnowledgeBaseAttributes(flushAll=True):
|
||||||
kb.reflectiveMechanism = True
|
kb.reflectiveMechanism = True
|
||||||
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS:0, REFLECTIVE_COUNTER.HIT:0}
|
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS:0, REFLECTIVE_COUNTER.HIT:0}
|
||||||
kb.responseTimes = []
|
kb.responseTimes = []
|
||||||
kb.resumedQueries = {}
|
|
||||||
kb.resumeValues = True
|
kb.resumeValues = True
|
||||||
kb.safeCharEncode = False
|
kb.safeCharEncode = False
|
||||||
kb.singleLogFlags = set()
|
kb.singleLogFlags = set()
|
||||||
kb.skipOthersDbms = None
|
kb.skipOthersDbms = None
|
||||||
kb.stickyFlag = False
|
kb.stickyFlag = False
|
||||||
kb.suppressSession = False
|
|
||||||
kb.suppressResumeInfo = False
|
kb.suppressResumeInfo = False
|
||||||
kb.technique = None
|
kb.technique = None
|
||||||
kb.testMode = False
|
kb.testMode = False
|
||||||
|
|
|
@ -11,7 +11,7 @@ import re
|
||||||
|
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
from lib.core.common import Format
|
from lib.core.common import Format
|
||||||
from lib.core.common import dataToSessionFile
|
from lib.core.common import hashDBWrite
|
||||||
from lib.core.common import intersect
|
from lib.core.common import intersect
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
|
@ -20,42 +20,25 @@ from lib.core.convert import base64unpickle
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
|
from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import OS
|
from lib.core.enums import OS
|
||||||
from lib.core.settings import SUPPORTED_DBMS
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import UNKNOWN_DBMS_VERSION
|
from lib.core.settings import UNKNOWN_DBMS_VERSION
|
||||||
|
|
||||||
def safeFormatString(value):
|
|
||||||
retVal = value
|
|
||||||
if retVal:
|
|
||||||
retVal = retVal.replace("[", "__LEFT_SQUARE_BRACKET__").replace("]", "__RIGHT_SQUARE_BRACKET__")
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
def unSafeFormatString(value):
|
|
||||||
retVal = value
|
|
||||||
if retVal:
|
|
||||||
retVal = retVal.replace("__LEFT_SQUARE_BRACKET__", "[").replace("__RIGHT_SQUARE_BRACKET__", "]")
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
def setDbms(dbms):
|
def setDbms(dbms):
|
||||||
"""
|
"""
|
||||||
@param dbms: database management system to be set into the knowledge
|
@param dbms: database management system to be set into the knowledge
|
||||||
base as fingerprint.
|
base as fingerprint.
|
||||||
@type dbms: C{str}
|
@type dbms: C{str}
|
||||||
"""
|
"""
|
||||||
condition = (
|
|
||||||
not kb.resumedQueries
|
|
||||||
or ( kb.resumedQueries.has_key(conf.url) and
|
|
||||||
not kb.resumedQueries[conf.url].has_key("DBMS") )
|
|
||||||
)
|
|
||||||
|
|
||||||
if condition:
|
hashDBWrite(HASHDB_KEYS.DBMS, dbms)
|
||||||
dataToSessionFile("[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(dbms)))
|
|
||||||
|
|
||||||
firstRegExp = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
|
_ = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
|
||||||
dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)
|
_ = re.search("^%s" % _, dbms, re.I)
|
||||||
|
|
||||||
if dbmsRegExp:
|
if _:
|
||||||
dbms = dbmsRegExp.group(1)
|
dbms = _.group(1)
|
||||||
|
|
||||||
Backend.setDbms(dbms)
|
Backend.setDbms(dbms)
|
||||||
|
|
||||||
|
@ -76,11 +59,6 @@ def setOs():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
infoMsg = ""
|
infoMsg = ""
|
||||||
condition = (
|
|
||||||
not kb.resumedQueries
|
|
||||||
or ( kb.resumedQueries.has_key(conf.url) and
|
|
||||||
not kb.resumedQueries[conf.url].has_key("OS") )
|
|
||||||
)
|
|
||||||
|
|
||||||
if not kb.bannerFp:
|
if not kb.bannerFp:
|
||||||
return
|
return
|
||||||
|
@ -105,82 +83,4 @@ def setOs():
|
||||||
if infoMsg:
|
if infoMsg:
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if condition:
|
hashDBWrite(HASHDB_KEYS.OS, Backend.getOs())
|
||||||
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), Backend.getOs()))
|
|
||||||
|
|
||||||
def resumeConfKb(expression, url, value):
|
|
||||||
if expression == "Dynamic markings" and url == conf.url:
|
|
||||||
kb.dynamicMarkings = base64unpickle(value[:-1])
|
|
||||||
infoMsg = "resuming dynamic markings from session file"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
elif expression == "DBMS" and url == conf.url:
|
|
||||||
dbms = unSafeFormatString(value[:-1])
|
|
||||||
dbms = dbms.lower()
|
|
||||||
dbmsVersion = [UNKNOWN_DBMS_VERSION]
|
|
||||||
|
|
||||||
firstRegExp = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
|
|
||||||
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, dbms)
|
|
||||||
|
|
||||||
if dbmsRegExp:
|
|
||||||
dbms = dbmsRegExp.group(1)
|
|
||||||
dbmsVersion = [ dbmsRegExp.group(2) ]
|
|
||||||
|
|
||||||
if conf.dbms and conf.dbms.lower() != dbms:
|
|
||||||
message = "you provided '%s' as back-end DBMS, " % conf.dbms
|
|
||||||
message += "but from a past scan information on the target URL "
|
|
||||||
message += "sqlmap assumes the back-end DBMS is %s. " % dbms
|
|
||||||
message += "Do you really want to force the back-end "
|
|
||||||
message += "DBMS value? [y/N] "
|
|
||||||
test = readInput(message, default="N")
|
|
||||||
|
|
||||||
if not test or test[0] in ("n", "N"):
|
|
||||||
conf.dbms = None
|
|
||||||
Backend.setDbms(dbms)
|
|
||||||
Backend.setVersionList(dbmsVersion)
|
|
||||||
else:
|
|
||||||
infoMsg = "resuming back-end DBMS '%s' " % dbms
|
|
||||||
infoMsg += "from session file"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
Backend.setDbms(dbms)
|
|
||||||
Backend.setVersionList(dbmsVersion)
|
|
||||||
|
|
||||||
elif expression == "OS" and url == conf.url:
|
|
||||||
os = unSafeFormatString(value[:-1])
|
|
||||||
|
|
||||||
if os and os != 'None':
|
|
||||||
infoMsg = "resuming back-end DBMS operating system '%s' " % os
|
|
||||||
infoMsg += "from session file"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
if conf.os and conf.os.lower() != os.lower():
|
|
||||||
message = "you provided '%s' as back-end DBMS operating " % conf.os
|
|
||||||
message += "system, but from a past scan information on the "
|
|
||||||
message += "target URL sqlmap assumes the back-end DBMS "
|
|
||||||
message += "operating system is %s. " % os
|
|
||||||
message += "Do you really want to force the back-end DBMS "
|
|
||||||
message += "OS value? [y/N] "
|
|
||||||
test = readInput(message, default="N")
|
|
||||||
|
|
||||||
if not test or test[0] in ("n", "N"):
|
|
||||||
conf.os = os
|
|
||||||
else:
|
|
||||||
conf.os = os
|
|
||||||
|
|
||||||
Backend.setOs(conf.os)
|
|
||||||
|
|
||||||
elif expression == "Remote temp path" and url == conf.url and conf.tmpPath is None:
|
|
||||||
conf.tmpPath = unSafeFormatString(value[:-1])
|
|
||||||
|
|
||||||
infoMsg = "resuming remote absolute path of temporary "
|
|
||||||
infoMsg += "files directory '%s' from session file" % conf.tmpPath
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
elif conf.freshQueries:
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif expression == "xp_cmdshell availability" and url == conf.url:
|
|
||||||
kb.xpCmdshellAvailable = True if unSafeFormatString(value[:-1]).lower() == "true" else False
|
|
||||||
infoMsg = "resuming xp_cmdshell availability"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import re
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from lib.core.common import dataToSessionFile
|
from lib.core.common import Backend
|
||||||
from lib.core.common import hashDBRetrieve
|
from lib.core.common import hashDBRetrieve
|
||||||
from lib.core.common import intersect
|
from lib.core.common import intersect
|
||||||
from lib.core.common import paramToDict
|
from lib.core.common import paramToDict
|
||||||
|
@ -37,14 +37,15 @@ from lib.core.exception import sqlmapUserQuitException
|
||||||
from lib.core.option import authHandler
|
from lib.core.option import authHandler
|
||||||
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.settings import CUSTOM_INJECTION_MARK_CHAR
|
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
|
||||||
from lib.core.settings import HOST_ALIASES
|
from lib.core.settings import HOST_ALIASES
|
||||||
from lib.core.settings import REFERER_ALIASES
|
from lib.core.settings import REFERER_ALIASES
|
||||||
from lib.core.settings import RESULTS_FILE_FORMAT
|
from lib.core.settings import RESULTS_FILE_FORMAT
|
||||||
from lib.core.settings import SOAP_REGEX
|
from lib.core.settings import SOAP_REGEX
|
||||||
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import UNENCODED_ORIGINAL_VALUE
|
from lib.core.settings import UNENCODED_ORIGINAL_VALUE
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
from lib.core.settings import UNICODE_ENCODING
|
||||||
|
from lib.core.settings import UNKNOWN_DBMS_VERSION
|
||||||
from lib.core.settings import URI_INJECTABLE_REGEX
|
from lib.core.settings import URI_INJECTABLE_REGEX
|
||||||
from lib.core.settings import USER_AGENT_ALIASES
|
from lib.core.settings import USER_AGENT_ALIASES
|
||||||
from lib.utils.hashdb import HashDB
|
from lib.utils.hashdb import HashDB
|
||||||
|
@ -243,78 +244,79 @@ def __resumeHashDBValues():
|
||||||
if injection not in kb.injections:
|
if injection not in kb.injections:
|
||||||
kb.injections.append(injection)
|
kb.injections.append(injection)
|
||||||
|
|
||||||
def __setOutputResume():
|
__resumeDBMS()
|
||||||
|
__resumeOS()
|
||||||
|
|
||||||
|
def __resumeDBMS():
|
||||||
"""
|
"""
|
||||||
Check and set the output text file and the resume functionality.
|
Resume stored DBMS information from HashDB
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not conf.sessionFile:
|
value = hashDBRetrieve(HASHDB_KEYS.DBMS)
|
||||||
conf.sessionFile = "%s%ssession" % (conf.outputPath, os.sep)
|
|
||||||
|
|
||||||
logger.info("using '%s' as a session file" % conf.sessionFile)
|
if not value:
|
||||||
|
return
|
||||||
|
|
||||||
if os.path.exists(conf.sessionFile):
|
dbms = value.lower()
|
||||||
if not conf.flushSession:
|
dbmsVersion = [UNKNOWN_DBMS_VERSION]
|
||||||
try:
|
_ = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS]))
|
||||||
readSessionFP = codecs.open(conf.sessionFile, "r", UNICODE_ENCODING, 'replace')
|
_ = re.search("%s ([\d\.]+)" % _, dbms, re.I)
|
||||||
__url_cache = set()
|
|
||||||
__expression_cache = {}
|
|
||||||
|
|
||||||
for line in readSessionFP.readlines(): # xreadlines doesn't return unicode strings when codec.open() is used
|
if _:
|
||||||
if line.count("][") == 4:
|
dbms = _.group(1).lower()
|
||||||
line = line.split("][")
|
dbmsVersion = [_.group(2)]
|
||||||
|
|
||||||
if len(line) != 5:
|
if conf.dbms:
|
||||||
continue
|
if conf.dbms.lower() != dbms:
|
||||||
|
message = "you provided '%s' as back-end DBMS, " % conf.dbms
|
||||||
|
message += "but from a past scan information on the target URL "
|
||||||
|
message += "sqlmap assumes the back-end DBMS is %s. " % dbms
|
||||||
|
message += "Do you really want to force the back-end "
|
||||||
|
message += "DBMS value? [y/N] "
|
||||||
|
test = readInput(message, default="N")
|
||||||
|
|
||||||
url, _, _, expression, value = line
|
if not test or test[0] in ("n", "N"):
|
||||||
|
conf.dbms = None
|
||||||
|
Backend.setDbms(dbms)
|
||||||
|
Backend.setVersionList(dbmsVersion)
|
||||||
|
else:
|
||||||
|
infoMsg = "resuming back-end DBMS '%s' " % dbms
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if not value:
|
Backend.setDbms(dbms)
|
||||||
continue
|
Backend.setVersionList(dbmsVersion)
|
||||||
|
|
||||||
if url[0] == "[":
|
def __resumeOS():
|
||||||
url = url[1:]
|
"""
|
||||||
|
Resume stored OS information from HashDB
|
||||||
|
"""
|
||||||
|
|
||||||
value = value.rstrip('\r\n') # Strips both chars independently
|
value = hashDBRetrieve(HASHDB_KEYS.OS)
|
||||||
|
|
||||||
if url not in ( conf.url, conf.hostname ):
|
if not value:
|
||||||
continue
|
return
|
||||||
|
|
||||||
if url not in __url_cache:
|
os = value
|
||||||
kb.resumedQueries[url] = {}
|
|
||||||
kb.resumedQueries[url][expression] = value
|
|
||||||
__url_cache.add(url)
|
|
||||||
__expression_cache[url] = set(expression)
|
|
||||||
|
|
||||||
resumeConfKb(expression, url, value)
|
if os and os != 'None':
|
||||||
|
infoMsg = "resuming back-end DBMS operating system '%s' " % os
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if expression not in __expression_cache[url]:
|
if conf.os and conf.os.lower() != os.lower():
|
||||||
kb.resumedQueries[url][expression] = value
|
message = "you provided '%s' as back-end DBMS operating " % conf.os
|
||||||
__expression_cache[url].add(value)
|
message += "system, but from a past scan information on the "
|
||||||
elif len(value) >= len(kb.resumedQueries[url][expression]):
|
message += "target URL sqlmap assumes the back-end DBMS "
|
||||||
kb.resumedQueries[url][expression] = value
|
message += "operating system is %s. " % os
|
||||||
|
message += "Do you really want to force the back-end DBMS "
|
||||||
|
message += "OS value? [y/N] "
|
||||||
|
test = readInput(message, default="N")
|
||||||
|
|
||||||
if kb.injection.place is not None and kb.injection.parameter is not None:
|
if not test or test[0] in ("n", "N"):
|
||||||
kb.injections.append(kb.injection)
|
conf.os = os
|
||||||
except IOError, msg:
|
|
||||||
errMsg = "unable to properly open the session file (%s)" % msg
|
|
||||||
raise sqlmapFilePathException, errMsg
|
|
||||||
else:
|
|
||||||
readSessionFP.close()
|
|
||||||
else:
|
else:
|
||||||
try:
|
conf.os = os
|
||||||
os.remove(conf.sessionFile)
|
|
||||||
logger.info("flushing session file")
|
|
||||||
except OSError, msg:
|
|
||||||
errMsg = "unable to flush the session file (%s)" % msg
|
|
||||||
raise sqlmapFilePathException, errMsg
|
|
||||||
|
|
||||||
try:
|
Backend.setOs(conf.os)
|
||||||
conf.sessionFP = codecs.open(conf.sessionFile, "a", UNICODE_ENCODING)
|
|
||||||
dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
|
|
||||||
except IOError:
|
|
||||||
errMsg = "unable to write on the session file specified"
|
|
||||||
raise sqlmapFilePathException, errMsg
|
|
||||||
|
|
||||||
def __setResultsFile():
|
def __setResultsFile():
|
||||||
"""
|
"""
|
||||||
|
@ -435,7 +437,6 @@ def initTargetEnv():
|
||||||
|
|
||||||
conf.paramDict = {}
|
conf.paramDict = {}
|
||||||
conf.parameters = {}
|
conf.parameters = {}
|
||||||
conf.sessionFile = None
|
|
||||||
conf.hashDBFile = None
|
conf.hashDBFile = None
|
||||||
|
|
||||||
__setKnowledgeBaseAttributes(False)
|
__setKnowledgeBaseAttributes(False)
|
||||||
|
@ -445,7 +446,6 @@ def initTargetEnv():
|
||||||
def setupTargetEnv():
|
def setupTargetEnv():
|
||||||
__createTargetDirs()
|
__createTargetDirs()
|
||||||
__setRequestParams()
|
__setRequestParams()
|
||||||
__setOutputResume()
|
|
||||||
__setHashDB()
|
__setHashDB()
|
||||||
__resumeHashDBValues()
|
__resumeHashDBValues()
|
||||||
__setResultsFile()
|
__setResultsFile()
|
||||||
|
|
|
@ -126,7 +126,6 @@ def liveTest():
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
log = []
|
log = []
|
||||||
session = []
|
|
||||||
switches = dict(global_)
|
switches = dict(global_)
|
||||||
|
|
||||||
if case.hasAttribute("name"):
|
if case.hasAttribute("name"):
|
||||||
|
@ -143,14 +142,9 @@ def liveTest():
|
||||||
if item.hasAttribute("value"):
|
if item.hasAttribute("value"):
|
||||||
log.append(replaceVars(item.getAttribute("value"), vars_))
|
log.append(replaceVars(item.getAttribute("value"), vars_))
|
||||||
|
|
||||||
if case.getElementsByTagName("session"):
|
|
||||||
for item in case.getElementsByTagName("session")[0].getElementsByTagName("item"):
|
|
||||||
if item.hasAttribute("value"):
|
|
||||||
session.append(replaceVars(item.getAttribute("value"), vars_))
|
|
||||||
|
|
||||||
msg = "running live test case '%s' (%d/%d)" % (name, count, length)
|
msg = "running live test case '%s' (%d/%d)" % (name, count, length)
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
result = runCase(switches, log, session)
|
result = runCase(switches, log)
|
||||||
if result:
|
if result:
|
||||||
logger.info("test passed")
|
logger.info("test passed")
|
||||||
else:
|
else:
|
||||||
|
@ -178,7 +172,6 @@ def initCase(switches=None):
|
||||||
if key in cmdLineOptions.__dict__:
|
if key in cmdLineOptions.__dict__:
|
||||||
cmdLineOptions.__dict__[key] = value
|
cmdLineOptions.__dict__[key] = value
|
||||||
|
|
||||||
conf.sessionFile = None
|
|
||||||
init(cmdLineOptions, True)
|
init(cmdLineOptions, True)
|
||||||
__setVerbosity()
|
__setVerbosity()
|
||||||
|
|
||||||
|
@ -190,7 +183,7 @@ def cleanCase():
|
||||||
conf.verbose = 1
|
conf.verbose = 1
|
||||||
__setVerbosity()
|
__setVerbosity()
|
||||||
|
|
||||||
def runCase(switches=None, log=None, session=None):
|
def runCase(switches=None, log=None):
|
||||||
retVal = True
|
retVal = True
|
||||||
initCase(switches)
|
initCase(switches)
|
||||||
|
|
||||||
|
@ -198,19 +191,6 @@ def runCase(switches=None, log=None, session=None):
|
||||||
if result == False: #if None ignore
|
if result == False: #if None ignore
|
||||||
retVal = False
|
retVal = False
|
||||||
|
|
||||||
if session and retVal:
|
|
||||||
ifile = open(conf.sessionFile, 'r')
|
|
||||||
content = ifile.read()
|
|
||||||
ifile.close()
|
|
||||||
for item in session:
|
|
||||||
if item.startswith("r'") and item.endswith("'"):
|
|
||||||
if not re.search(item[2:-1], content, re.DOTALL):
|
|
||||||
retVal = False
|
|
||||||
break
|
|
||||||
elif content.find(item) < 0:
|
|
||||||
retVal = False
|
|
||||||
break
|
|
||||||
|
|
||||||
if log and retVal:
|
if log and retVal:
|
||||||
ifile = open(conf.dumper.getOutputFile(), 'r')
|
ifile = open(conf.dumper.getOutputFile(), 'r')
|
||||||
content = ifile.read()
|
content = ifile.read()
|
||||||
|
|
|
@ -50,12 +50,11 @@ from lib.core.unescaper import unescaper
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.request.direct import direct
|
from lib.request.direct import direct
|
||||||
from lib.techniques.blind.inference import bisection
|
from lib.techniques.blind.inference import bisection
|
||||||
|
from lib.techniques.blind.inference import queryOutputLength
|
||||||
from lib.techniques.dns.test import dnsTest
|
from lib.techniques.dns.test import dnsTest
|
||||||
from lib.techniques.dns.use import dnsUse
|
from lib.techniques.dns.use import dnsUse
|
||||||
from lib.techniques.error.use import errorUse
|
from lib.techniques.error.use import errorUse
|
||||||
from lib.techniques.union.use import unionUse
|
from lib.techniques.union.use import unionUse
|
||||||
from lib.utils.resume import queryOutputLength
|
|
||||||
from lib.utils.resume import resume
|
|
||||||
|
|
||||||
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False):
|
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
@ -488,8 +487,4 @@ def goStacked(expression, silent=False):
|
||||||
Request.queryPage(payload, content=False, silent=silent, noteResponseTime=False, timeBasedCompare=True)
|
Request.queryPage(payload, content=False, silent=silent, noteResponseTime=False, timeBasedCompare=True)
|
||||||
|
|
||||||
def checkBooleanExpression(expression, expectingNone=True):
|
def checkBooleanExpression(expression, expectingNone=True):
|
||||||
kb.suppressSession = True
|
return getValue(unescaper.unescape(expression), expected=EXPECTED.BOOL, suppressOutput=True, expectingNone=expectingNone)
|
||||||
value = getValue(unescaper.unescape(expression), expected=EXPECTED.BOOL, suppressOutput=True, expectingNone=expectingNone)
|
|
||||||
kb.suppressSession = False
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
|
@ -7,12 +7,14 @@ Copyright (c) 2006-2012 sqlmap developers (http://www.sqlmap.org/)
|
||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from extra.safe2bin.safe2bin import safecharencode
|
from extra.safe2bin.safe2bin import safecharencode
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
|
from lib.core.common import calculateDeltaSeconds
|
||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import decodeHexValue
|
from lib.core.common import decodeHexValue
|
||||||
from lib.core.common import decodeIntToUnicode
|
from lib.core.common import decodeIntToUnicode
|
||||||
|
@ -24,6 +26,7 @@ from lib.core.common import getPartRun
|
||||||
from lib.core.common import hashDBRetrieve
|
from lib.core.common import hashDBRetrieve
|
||||||
from lib.core.common import hashDBWrite
|
from lib.core.common import hashDBWrite
|
||||||
from lib.core.common import incrementCounter
|
from lib.core.common import incrementCounter
|
||||||
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import safeStringFormat
|
from lib.core.common import safeStringFormat
|
||||||
from lib.core.common import setFormatterPrependFlag
|
from lib.core.common import setFormatterPrependFlag
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
|
@ -31,6 +34,7 @@ from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
|
from lib.core.enums import CHARSET_TYPE
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.exception import sqlmapThreadException
|
from lib.core.exception import sqlmapThreadException
|
||||||
|
@ -546,3 +550,56 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
|
|
||||||
_ = finalValue or partialValue
|
_ = finalValue or partialValue
|
||||||
return getCounter(kb.technique), safecharencode(_) if kb.safeCharEncode else _
|
return getCounter(kb.technique), safecharencode(_) if kb.safeCharEncode else _
|
||||||
|
|
||||||
|
def queryOutputLength(expression, payload):
|
||||||
|
"""
|
||||||
|
Returns the query output length.
|
||||||
|
"""
|
||||||
|
|
||||||
|
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
|
||||||
|
select = re.search("\ASELECT\s+", expression, re.I)
|
||||||
|
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
||||||
|
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
|
||||||
|
selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
|
||||||
|
selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
|
||||||
|
miscExpr = re.search("\A(.+)", expression, re.I)
|
||||||
|
|
||||||
|
if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
|
||||||
|
if selectTopExpr:
|
||||||
|
regExpr = selectTopExpr.groups()[0]
|
||||||
|
elif selectDistinctExpr:
|
||||||
|
regExpr = selectDistinctExpr.groups()[0]
|
||||||
|
elif selectFromExpr:
|
||||||
|
regExpr = selectFromExpr.groups()[0]
|
||||||
|
elif selectExpr:
|
||||||
|
regExpr = selectExpr.groups()[0]
|
||||||
|
elif miscExpr:
|
||||||
|
regExpr = miscExpr.groups()[0]
|
||||||
|
|
||||||
|
if ( select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I) ) or len(regExpr) <= 1:
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
if selectDistinctExpr:
|
||||||
|
lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr, expression)
|
||||||
|
|
||||||
|
if Backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.PGSQL ):
|
||||||
|
lengthExpr += " AS %s" % randomStr(lowercase=True)
|
||||||
|
elif select:
|
||||||
|
lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
|
||||||
|
else:
|
||||||
|
lengthExpr = lengthQuery % expression
|
||||||
|
|
||||||
|
infoMsg = "retrieving the length of query output"
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
lengthExprUnescaped = unescaper.unescape(lengthExpr)
|
||||||
|
count, length = bisection(payload, lengthExprUnescaped, charsetType=CHARSET_TYPE.DIGITS)
|
||||||
|
|
||||||
|
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
if length == " ":
|
||||||
|
length = 0
|
||||||
|
|
||||||
|
return count, length, regExpr
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
"""
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Copyright (c) 2006-2012 sqlmap developers (http://www.sqlmap.org/)
|
|
||||||
See the file 'doc/COPYING' for copying permission
|
|
||||||
"""
|
|
||||||
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
|
|
||||||
from lib.core.common import calculateDeltaSeconds
|
|
||||||
from lib.core.common import dataToSessionFile
|
|
||||||
from lib.core.common import dataToStdout
|
|
||||||
from lib.core.common import Backend
|
|
||||||
from lib.core.common import safeStringFormat
|
|
||||||
from lib.core.common import randomStr
|
|
||||||
from lib.core.common import replaceNewlineTabs
|
|
||||||
from lib.core.common import restoreDumpMarkedChars
|
|
||||||
from lib.core.data import conf
|
|
||||||
from lib.core.data import kb
|
|
||||||
from lib.core.data import logger
|
|
||||||
from lib.core.data import queries
|
|
||||||
from lib.core.enums import DBMS
|
|
||||||
from lib.core.enums import CHARSET_TYPE
|
|
||||||
from lib.core.unescaper import unescaper
|
|
||||||
from lib.techniques.blind.inference import bisection
|
|
||||||
|
|
||||||
def queryOutputLength(expression, payload):
|
|
||||||
"""
|
|
||||||
Returns the query output length.
|
|
||||||
"""
|
|
||||||
|
|
||||||
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
|
|
||||||
select = re.search("\ASELECT\s+", expression, re.I)
|
|
||||||
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
|
||||||
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
|
|
||||||
selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
|
|
||||||
selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
|
|
||||||
miscExpr = re.search("\A(.+)", expression, re.I)
|
|
||||||
|
|
||||||
if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
|
|
||||||
if selectTopExpr:
|
|
||||||
regExpr = selectTopExpr.groups()[0]
|
|
||||||
elif selectDistinctExpr:
|
|
||||||
regExpr = selectDistinctExpr.groups()[0]
|
|
||||||
elif selectFromExpr:
|
|
||||||
regExpr = selectFromExpr.groups()[0]
|
|
||||||
elif selectExpr:
|
|
||||||
regExpr = selectExpr.groups()[0]
|
|
||||||
elif miscExpr:
|
|
||||||
regExpr = miscExpr.groups()[0]
|
|
||||||
|
|
||||||
if ( select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I) ) or len(regExpr) <= 1:
|
|
||||||
return None, None, None
|
|
||||||
|
|
||||||
if selectDistinctExpr:
|
|
||||||
lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr, expression)
|
|
||||||
|
|
||||||
if Backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.PGSQL ):
|
|
||||||
lengthExpr += " AS %s" % randomStr(lowercase=True)
|
|
||||||
elif select:
|
|
||||||
lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1)
|
|
||||||
else:
|
|
||||||
lengthExpr = lengthQuery % expression
|
|
||||||
|
|
||||||
infoMsg = "retrieving the length of query output"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
start = time.time()
|
|
||||||
lengthExprUnescaped = unescaper.unescape(lengthExpr)
|
|
||||||
count, length = bisection(payload, lengthExprUnescaped, charsetType=CHARSET_TYPE.DIGITS)
|
|
||||||
|
|
||||||
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
if length == " ":
|
|
||||||
length = 0
|
|
||||||
|
|
||||||
return count, length, regExpr
|
|
||||||
|
|
||||||
def resume(expression, payload):
|
|
||||||
"""
|
|
||||||
This function can be called to resume part or entire output of a
|
|
||||||
SQL injection query output.
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
if "sqlmapfile" in expression or "sqlmapoutput" in expression or conf.freshQueries:
|
|
||||||
return None
|
|
||||||
|
|
||||||
condition = (
|
|
||||||
kb.resumedQueries and conf.url in kb.resumedQueries
|
|
||||||
and expression in kb.resumedQueries[conf.url]
|
|
||||||
)
|
|
||||||
|
|
||||||
if not condition:
|
|
||||||
return None
|
|
||||||
|
|
||||||
resumedValue = kb.resumedQueries[conf.url][expression]
|
|
||||||
|
|
||||||
if not resumedValue:
|
|
||||||
return None
|
|
||||||
|
|
||||||
resumedValue = restoreDumpMarkedChars(resumedValue, True)
|
|
||||||
|
|
||||||
if resumedValue[-1] == "]":
|
|
||||||
resumedValue = resumedValue[:-1]
|
|
||||||
|
|
||||||
infoMsg = "read from file '%s': " % conf.sessionFile
|
|
||||||
|
|
||||||
if "\n" in resumedValue:
|
|
||||||
infoMsg += "%s..." % resumedValue.split("\n")[0]
|
|
||||||
else:
|
|
||||||
infoMsg += resumedValue
|
|
||||||
|
|
||||||
if not kb.suppressResumeInfo:
|
|
||||||
dataToStdout("[%s] [INFO] %s\n" % (time.strftime("%X"), infoMsg))
|
|
||||||
|
|
||||||
return resumedValue
|
|
||||||
|
|
||||||
# If we called this function without providing a payload it means
|
|
||||||
# that we have called it from lib/request/inject __goInband() or
|
|
||||||
# from __goError() function so we return to the calling function
|
|
||||||
# so that the query output will be retrieved taking advantage
|
|
||||||
# of either error-based or inband SQL injection vulnerability.
|
|
||||||
if not payload:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not Backend.getIdentifiedDbms():
|
|
||||||
return None
|
|
||||||
|
|
||||||
substringQuery = queries[Backend.getIdentifiedDbms()].substring.query
|
|
||||||
select = re.search("\ASELECT ", expression, re.I)
|
|
||||||
|
|
||||||
_, length, regExpr = queryOutputLength(expression, payload)
|
|
||||||
|
|
||||||
if not length:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if len(resumedValue) == int(length):
|
|
||||||
infoMsg = "read from file '%s': " % conf.sessionFile
|
|
||||||
infoMsg += "%s" % resumedValue.split("\n")[0]
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(resumedValue)))
|
|
||||||
|
|
||||||
return resumedValue
|
|
||||||
elif len(resumedValue) < int(length):
|
|
||||||
infoMsg = "resumed from file '%s': " % conf.sessionFile
|
|
||||||
infoMsg += "%s..." % resumedValue.split("\n")[0]
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
dataToSessionFile("[%s][%s][%s][%s][%s" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(resumedValue)))
|
|
||||||
|
|
||||||
if select:
|
|
||||||
newExpr = expression.replace(regExpr, safeStringFormat(substringQuery, (regExpr, len(resumedValue) + 1, int(length))), 1)
|
|
||||||
else:
|
|
||||||
newExpr = safeStringFormat(substringQuery, (expression, len(resumedValue) + 1, int(length)))
|
|
||||||
|
|
||||||
missingCharsLength = int(length) - len(resumedValue)
|
|
||||||
|
|
||||||
infoMsg = "retrieving pending %d query " % missingCharsLength
|
|
||||||
infoMsg += "output characters"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
start = time.time()
|
|
||||||
count, finalValue = bisection(payload, newExpr, length=missingCharsLength)
|
|
||||||
|
|
||||||
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
if len(finalValue) != ( int(length) - len(resumedValue) ):
|
|
||||||
warnMsg = "the total length of the query is not "
|
|
||||||
warnMsg += "right, sqlmap is going to retrieve the "
|
|
||||||
warnMsg += "query value from the beginning now"
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
return "%s%s" % (resumedValue, finalValue)
|
|
||||||
|
|
||||||
return None
|
|
||||||
except ValueError:
|
|
||||||
errMsg = "invalid resume value for expression: '%s'" % expression
|
|
||||||
logger.error(errMsg)
|
|
||||||
return None
|
|
Loading…
Reference in New Issue
Block a user