diff --git a/lib/core/agent.py b/lib/core/agent.py index e678627d4..0ac2434b3 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -347,6 +347,12 @@ class Agent(object): if payload: payload = payload.replace(SLEEP_TIME_MARKER, str(conf.timeSec)) + for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)): + payload = payload.replace(_, str(randomInt())) + + for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): + payload = payload.replace(_, randomStr()) + return payload def getComment(self, request): diff --git a/lib/core/common.py b/lib/core/common.py index 2446dcd63..f695172a4 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1118,6 +1118,13 @@ def sanitizeStr(value): return getUnicode(value).replace("\n", " ").replace("\r", "") def getHeader(headers, key): + """ + Returns header value ignoring the letter case + + >>> getHeader({"Foo": "bar"}, "foo") + 'bar' + """ + retVal = None for _ in (headers or {}): if _.upper() == key.upper(): @@ -1619,6 +1626,13 @@ def getRemoteIP(): return retVal def getFileType(filePath): + """ + Returns "magic" file type for given file path + + >>> getFileType(__file__) + 'text' + """ + try: _ = magic.from_file(filePath) except: @@ -2597,13 +2611,13 @@ def runningAsAdmin(): return isAdmin -def logHTTPTraffic(requestLogMsg, responseLogMsg): +def logHTTPTraffic(requestLogMsg, responseLogMsg, startTime=None, endTime=None): """ Logs HTTP traffic to the output file """ if conf.harFile: - conf.httpCollector.collectRequest(requestLogMsg, responseLogMsg) + conf.httpCollector.collectRequest(requestLogMsg, responseLogMsg, startTime, endTime) if not conf.trafficFile: with kb.locks.log: @@ -3535,11 +3549,11 @@ def safeSQLIdentificatorNaming(name, isTable=False): if retVal.upper() in kb.keywords or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ("." if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS): retVal = "`%s`" % retVal.strip("`") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.SQLITE, DBMS.INFORMIX, DBMS.HSQLDB): retVal = "\"%s\"" % retVal.strip("\"") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.strip("\"").upper() - elif Backend.getIdentifiedDbms() in (DBMS.MSSQL,) and ((retVal or " ")[0].isdigit() or not re.match(r"\A\w+\Z", retVal, re.U)): + elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and ((retVal or " ")[0].isdigit() or not re.match(r"\A\w+\Z", retVal, re.U)): retVal = "[%s]" % retVal.strip("[]") if _ and DEFAULT_MSSQL_SCHEMA not in retVal and '.' not in re.sub(r"\[[^]]+\]", "", retVal): @@ -4387,6 +4401,9 @@ def getSafeExString(ex, encoding=None): """ Safe way how to get the proper exception represtation as a string (Note: errors to be avoided: 1) "%s" % Exception(u'\u0161') and 2) "%s" % str(Exception(u'\u0161')) + + >>> getSafeExString(Exception('foobar')) + u'foobar' """ retVal = ex diff --git a/lib/core/settings.py b/lib/core/settings.py index f1773e695..3ea2fb9ed 100755 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME from lib.core.enums import OS # sqlmap version (...) -VERSION = "1.1.7.3" +VERSION = "1.1.7.15" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) @@ -453,6 +453,9 @@ LOW_TEXT_PERCENT = 20 # Reference: http://dev.mysql.com/doc/refman/5.1/en/function-resolution.html IGNORE_SPACE_AFFECTED_KEYWORDS = ("CAST", "COUNT", "EXTRACT", "GROUP_CONCAT", "MAX", "MID", "MIN", "SESSION_USER", "SUBSTR", "SUBSTRING", "SUM", "SYSTEM_USER", "TRIM") +# Keywords expected to be in UPPERCASE in getValue() +GET_VALUE_UPPERCASE_KEYWORDS = ("SELECT", "FROM", "WHERE", "DISTINCT", "COUNT") + LEGAL_DISCLAIMER = "Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program" # After this number of misses reflective removal mechanism is turned off (for speed up reasons) diff --git a/lib/core/target.py b/lib/core/target.py index 43cbabbf9..1a2d0421b 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -20,6 +20,7 @@ from lib.core.common import getSafeExString from lib.core.common import getUnicode from lib.core.common import hashDBRetrieve from lib.core.common import intersect +from lib.core.common import isNumPosStrValue from lib.core.common import normalizeUnicode from lib.core.common import openFile from lib.core.common import paramToDict @@ -436,7 +437,7 @@ def _resumeHashDBValues(): 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(): + if isNumPosStrValue(kb.errorChunkLength): kb.errorChunkLength = int(kb.errorChunkLength) else: kb.errorChunkLength = None diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 5d920efb5..f35e4893c 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -31,7 +31,6 @@ from lib.core.settings import BASIC_HELP_ITEMS from lib.core.settings import DUMMY_URL from lib.core.settings import IS_WIN from lib.core.settings import MAX_HELP_OPTION_LENGTH -from lib.core.settings import UNICODE_ENCODING from lib.core.settings import VERSION_STRING from lib.core.shell import autoCompletion from lib.core.shell import clearHistory diff --git a/lib/request/connect.py b/lib/request/connect.py index e73839e73..58688d640 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -223,6 +223,8 @@ class Connect(object): the target URL page content """ + start = time.time() + if isinstance(conf.delay, (int, float)) and conf.delay > 0: time.sleep(conf.delay) @@ -288,7 +290,7 @@ class Connect(object): status = None _ = urlparse.urlsplit(url) - requestMsg = u"HTTP request [#%d]:\n%s " % (threadData.lastRequestUID, method or (HTTPMETHOD.POST if post is not None else HTTPMETHOD.GET)) + requestMsg = u"HTTP request [#%d]:\r\n%s " % (threadData.lastRequestUID, method or (HTTPMETHOD.POST if post is not None else HTTPMETHOD.GET)) requestMsg += getUnicode(("%s%s" % (_.path or "/", ("?%s" % _.query) if _.query else "")) if not any((refreshing, crawling, checking)) else url) responseMsg = u"HTTP response " requestHeaders = u"" @@ -413,13 +415,13 @@ class Connect(object): responseHeaders = _(ws.getheaders()) responseHeaders.headers = ["%s: %s\r\n" % (_[0].capitalize(), _[1]) for _ in responseHeaders.items()] - requestHeaders += "\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()]) - requestMsg += "\n%s" % requestHeaders + requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()]) + requestMsg += "\r\n%s" % requestHeaders if post is not None: - requestMsg += "\n\n%s" % getUnicode(post) + requestMsg += "\r\n\r\n%s" % getUnicode(post) - requestMsg += "\n" + requestMsg += "\r\n" threadData.lastRequestMsg = requestMsg @@ -432,26 +434,26 @@ class Connect(object): else: req = urllib2.Request(url, post, headers) - requestHeaders += "\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in req.header_items()]) + requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in req.header_items()]) if not getRequestHeader(req, HTTP_HEADER.COOKIE) and conf.cj: conf.cj._policy._now = conf.cj._now = int(time.time()) cookies = conf.cj._cookies_for_request(req) - requestHeaders += "\n%s" % ("Cookie: %s" % ";".join("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value)) for cookie in cookies)) + requestHeaders += "\r\n%s" % ("Cookie: %s" % ";".join("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value)) for cookie in cookies)) if post is not None: if not getRequestHeader(req, HTTP_HEADER.CONTENT_LENGTH): - requestHeaders += "\n%s: %d" % (string.capwords(HTTP_HEADER.CONTENT_LENGTH), len(post)) + requestHeaders += "\r\n%s: %d" % (string.capwords(HTTP_HEADER.CONTENT_LENGTH), len(post)) if not getRequestHeader(req, HTTP_HEADER.CONNECTION): - requestHeaders += "\n%s: %s" % (HTTP_HEADER.CONNECTION, "close" if not conf.keepAlive else "keep-alive") + requestHeaders += "\r\n%s: %s" % (HTTP_HEADER.CONNECTION, "close" if not conf.keepAlive else "keep-alive") - requestMsg += "\n%s" % requestHeaders + requestMsg += "\r\n%s" % requestHeaders if post is not None: - requestMsg += "\n\n%s" % getUnicode(post) + requestMsg += "\r\n\r\n%s" % getUnicode(post) - requestMsg += "\n" + requestMsg += "\r\n" if not multipart: threadData.lastRequestMsg = requestMsg @@ -576,19 +578,19 @@ class Connect(object): threadData.lastHTTPError = (threadData.lastRequestUID, code, status) kb.httpErrorCodes[code] = kb.httpErrorCodes.get(code, 0) + 1 - responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, code, status) + responseMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, status) if responseHeaders: - logHeaders = "\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()]) + logHeaders = "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()]) - logHTTPTraffic(requestMsg, "%s%s\n\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE])) + logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]), start, time.time()) skipLogTraffic = True if conf.verbose <= 5: responseMsg += getUnicode(logHeaders) elif conf.verbose > 5: - responseMsg += "%s\n\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]) + responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]) if not multipart: logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) @@ -737,20 +739,20 @@ class Connect(object): requestMsg = re.sub("(?i)Content-length: \d+\n", "", requestMsg) requestMsg = re.sub("(?s)\n\n.+", "\n", requestMsg) - responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, conn.code, status) + responseMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, conn.code, status) else: - responseMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, code, status) + responseMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, status) if responseHeaders: - logHeaders = "\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()]) + logHeaders = "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in responseHeaders.items()]) if not skipLogTraffic: - logHTTPTraffic(requestMsg, "%s%s\n\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE])) + logHTTPTraffic(requestMsg, "%s%s\r\n\r\n%s" % (responseMsg, logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]), start, time.time()) if conf.verbose <= 5: responseMsg += getUnicode(logHeaders) elif conf.verbose > 5: - responseMsg += "%s\n\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]) + responseMsg += "%s\r\n\r\n%s" % (logHeaders, (page or "")[:MAX_CONNECTION_CHUNK_SIZE]) if not multipart: logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) diff --git a/lib/request/inject.py b/lib/request/inject.py index c51cdb735..bf2f6cbe6 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -42,6 +42,7 @@ from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapNotVulnerableException from lib.core.exception import SqlmapUserQuitException +from lib.core.settings import GET_VALUE_UPPERCASE_KEYWORDS from lib.core.settings import MAX_TECHNIQUES_PER_VALUE from lib.core.settings import SQL_SCALAR_REGEX from lib.core.threads import getCurrentThreadData @@ -345,6 +346,9 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue + for keyword in GET_VALUE_UPPERCASE_KEYWORDS: + expression = re.sub("(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword, r"\g<1>%s\g<2>" % keyword, expression) + if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput @@ -356,7 +360,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression - if expression.upper().startswith("SELECT "): + if expression.startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) @@ -414,7 +418,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsDomain: - _ = "".join(filter(None, (key if isTechniqueAvailable(value) else None for key, value in {"E": PAYLOAD.TECHNIQUE.ERROR, "Q": PAYLOAD.TECHNIQUE.QUERY, "U": PAYLOAD.TECHNIQUE.UNION}.items()))) + _ = "".join(filter(None, (key if isTechniqueAvailable(value) else None for key, value in {'E': PAYLOAD.TECHNIQUE.ERROR, 'Q': PAYLOAD.TECHNIQUE.QUERY, 'U': PAYLOAD.TECHNIQUE.UNION}.items()))) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index a6e560bcf..4dca0f113 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission """ import re +import time import types import urllib2 import urlparse @@ -69,6 +70,7 @@ class SmartRedirectHandler(urllib2.HTTPRedirectHandler): return urllib2.Request(newurl, data=req.data, headers=req.headers, origin_req_host=req.get_origin_req_host()) def http_error_302(self, req, fp, code, msg, headers): + start = time.time() content = None redurl = self._get_header_redirect(headers) if not conf.ignoreRedirects else None @@ -92,18 +94,18 @@ class SmartRedirectHandler(urllib2.HTTPRedirectHandler): threadData.lastRedirectMsg = (threadData.lastRequestUID, content) redirectMsg = "HTTP redirect " - redirectMsg += "[#%d] (%d %s):\n" % (threadData.lastRequestUID, code, getUnicode(msg)) + redirectMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, getUnicode(msg)) if headers: - logHeaders = "\n".join("%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in headers.items()) + logHeaders = "\r\n".join("%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in headers.items()) else: logHeaders = "" redirectMsg += logHeaders if content: - redirectMsg += "\n\n%s" % getUnicode(content[:MAX_CONNECTION_CHUNK_SIZE]) + redirectMsg += "\r\n\r\n%s" % getUnicode(content[:MAX_CONNECTION_CHUNK_SIZE]) - logHTTPTraffic(threadData.lastRequestMsg, redirectMsg) + logHTTPTraffic(threadData.lastRequestMsg, redirectMsg, start, time.time()) logger.log(CUSTOM_LOGGING.TRAFFIC_IN, redirectMsg) if redurl: diff --git a/lib/utils/api.py b/lib/utils/api.py index 9c41412c8..829c2fff3 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -736,7 +736,7 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT): if not res["success"]: logger.error("Failed to execute command %s" % command) dataToStdout("%s\n" % raw) - + elif command.startswith("option"): if not taskid: logger.error("No task ID in use") diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index 27fc8fbdb..747aaf1e6 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -112,10 +112,10 @@ def crawl(target): threadData.shared.deeper.add(url) if re.search(r"(.*?)\?(.+)", url): threadData.shared.value.add(url) - except ValueError: # for non-valid links - pass except UnicodeEncodeError: # for non-HTML files pass + except ValueError: # for non-valid links + pass finally: if conf.forms: findPageForms(content, current, False, True) diff --git a/lib/utils/har.py b/lib/utils/har.py index 5630ec4d2..3d3579053 100644 --- a/lib/utils/har.py +++ b/lib/utils/har.py @@ -7,28 +7,31 @@ See the file 'doc/COPYING' for copying permission import base64 import BaseHTTPServer +import datetime import httplib import re import StringIO +import time -from lib.core.data import logger +from lib.core.bigarray import BigArray from lib.core.settings import VERSION +# Reference: https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HAR/Overview.html +# http://www.softwareishard.com/har/viewer/ + class HTTPCollectorFactory: def __init__(self, harFile=False): self.harFile = harFile def create(self): - collector = HTTPCollector() - - return collector + return HTTPCollector() class HTTPCollector: def __init__(self): - self.messages = [] + self.messages = BigArray() - def collectRequest(self, requestMessage, responseMessage): - self.messages.append(RawPair(requestMessage, responseMessage)) + def collectRequest(self, requestMessage, responseMessage, startTime=None, endTime=None): + self.messages.append(RawPair(requestMessage, responseMessage, startTime, endTime)) def obtain(self): return {"log": { @@ -38,23 +41,30 @@ class HTTPCollector: }} class RawPair: - def __init__(self, request, response): + def __init__(self, request, response, startTime=None, endTime=None): self.request = request self.response = response + self.startTime = startTime + self.endTime = endTime def toEntry(self): - return Entry(request=Request.parse(self.request), - response=Response.parse(self.response)) + return Entry(request=Request.parse(self.request), response=Response.parse(self.response), startTime=self.startTime, endTime=self.endTime) class Entry: - def __init__(self, request, response): + def __init__(self, request, response, startTime, endTime): self.request = request self.response = response + self.startTime = startTime or 0 + self.endTime = endTime or 0 def toDict(self): return { "request": self.request.toDict(), "response": self.response.toDict(), + "cache": {}, + "timings": [], + "time": int(1000 * (self.endTime - self.startTime)), + "startedDateTime": "%s%s" % (datetime.datetime.fromtimestamp(self.startTime).isoformat(), time.strftime("%z")) if self.startTime else None } class Request: @@ -64,7 +74,7 @@ class Request: self.httpVersion = httpVersion self.headers = headers or {} self.postBody = postBody - self.comment = comment + self.comment = comment.strip() if comment else comment self.raw = raw @classmethod @@ -89,6 +99,10 @@ class Request: "method": self.method, "url": self.url, "headers": [dict(name=key.capitalize(), value=value) for key, value in self.headers.items()], + "cookies": [], + "queryString": [], + "headersSize": -1, + "bodySize": -1, "comment": self.comment, } @@ -111,7 +125,7 @@ class Response: self.statusText = statusText self.headers = headers self.content = content - self.comment = comment + self.comment = comment.strip() if comment else comment @classmethod def parse(cls, raw): @@ -124,7 +138,7 @@ class Response: parts = cls.extract_status.search(first_line) status_line = "HTTP/1.0 %s %s" % (parts.group(1), parts.group(2)) remain = io.read() - altered = status_line + "\n" + remain + altered = status_line + "\r\n" + remain comment = first_line response = httplib.HTTPResponse(FakeSocket(altered)) @@ -133,7 +147,7 @@ class Response: try: content = response.read(-1) except httplib.IncompleteRead: - content = raw[raw.find("\n\n") + 2:].rstrip("\r\n") + content = raw[raw.find("\r\n\r\n") + 4:].rstrip("\r\n") return cls(httpVersion="HTTP/1.1" if response.version == 11 else "HTTP/1.0", status=response.status, @@ -147,6 +161,7 @@ class Response: content = { "mimeType": self.headers.get("Content-Type"), "text": self.content, + "size": len(self.content or "") } binary = set(['\0', '\1']) @@ -159,7 +174,11 @@ class Response: "status": self.status, "statusText": self.statusText, "headers": [dict(name=key.capitalize(), value=value) for key, value in self.headers.items() if key.lower() != "uri"], + "cookies": [], "content": content, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "", "comment": self.comment, } diff --git a/plugins/dbms/oracle/enumeration.py b/plugins/dbms/oracle/enumeration.py index 0cc0059c7..8c619cecc 100644 --- a/plugins/dbms/oracle/enumeration.py +++ b/plugins/dbms/oracle/enumeration.py @@ -67,7 +67,7 @@ class Enumeration(GenericEnumeration): user = None roles = set() - for count in xrange(0, len(value)): + for count in xrange(0, len(value or [])): # The first column is always the username if count == 0: user = value[count] diff --git a/plugins/generic/connector.py b/plugins/generic/connector.py index 5ebbd0b82..79f242f01 100644 --- a/plugins/generic/connector.py +++ b/plugins/generic/connector.py @@ -11,7 +11,6 @@ from lib.core.data import conf from lib.core.data import logger from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapUndefinedMethod -from lib.core.settings import UNICODE_ENCODING class Connector: """ diff --git a/plugins/generic/users.py b/plugins/generic/users.py index b09169dff..a6c8be7c7 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -393,7 +393,7 @@ class Users: user = None privileges = set() - for count in xrange(0, len(value)): + for count in xrange(0, len(value or [])): # The first column is always the username if count == 0: user = value[count] diff --git a/sqlmap.py b/sqlmap.py index 5d859f611..4664ef813 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -9,7 +9,10 @@ import sys sys.dont_write_bytecode = True -__import__("lib.utils.versioncheck") # this has to be the first non-standard import +try: + __import__("lib.utils.versioncheck") # this has to be the first non-standard import +except ImportError: + exit("[!] wrong installation detected (missing modules). Visit 'https://github.com/sqlmapproject/sqlmap/#installation' for further details") import bdb import distutils @@ -284,6 +287,9 @@ def main(): elif "valueStack.pop" in excMsg and kb.get("dumpKeyboardInterrupt"): raise SystemExit + elif any(_ in excMsg for _ in ("Broken pipe",)): + raise SystemExit + for match in re.finditer(r'File "(.+?)", line', excMsg): file_ = match.group(1) file_ = os.path.relpath(file_, os.path.dirname(__file__)) @@ -329,9 +335,9 @@ def main(): except KeyboardInterrupt: pass - if conf.harFile: + if conf.get("harFile"): with openFile(conf.harFile, "w+b") as f: - f.write(json.dumps(conf.httpCollector.obtain(), indent=4, separators=(',', ': '))) + json.dump(conf.httpCollector.obtain(), fp=f, indent=4, separators=(',', ': ')) if cmdLineOptions.get("sqlmapShell"): cmdLineOptions.clear() diff --git a/tamper/space2mysqlblank.py b/tamper/space2mysqlblank.py index caddab148..e7f96b0fb 100644 --- a/tamper/space2mysqlblank.py +++ b/tamper/space2mysqlblank.py @@ -33,7 +33,7 @@ def tamper(payload, **kwargs): >>> random.seed(0) >>> tamper('SELECT id FROM users') - 'SELECT%0Bid%0DFROM%0Cusers' + 'SELECT%A0id%0BFROM%0Cusers' """ # ASCII table: diff --git a/txt/checksum.md5 b/txt/checksum.md5 index c3dacbf10..9512c1645 100644 --- a/txt/checksum.md5 +++ b/txt/checksum.md5 @@ -25,9 +25,9 @@ f77daa397016460433d5e06704efd538 lib/controller/checks.py 130d1c16708668b8d89605b6b5b38bf5 lib/controller/controller.py a97df93b552ee4e4ba3692eae870de7c lib/controller/handler.py 310efc965c862cfbd7b0da5150a5ad36 lib/controller/__init__.py -d58e85ffeac2471ef3af729076b3b5f7 lib/core/agent.py +bc51363cbbe4b4d6bafef04508046c31 lib/core/agent.py 6cc95a117fbd34ef31b9aa25520f0e31 lib/core/bigarray.py -d40de0812b667b7be9d1755f82e18f17 lib/core/common.py +852ed8b5f19401b7fe21b8032104e3dd lib/core/common.py 5065a4242a8cccf72f91e22e1007ae63 lib/core/convert.py a8143dab9d3a27490f7d49b6b29ea530 lib/core/data.py 7936d78b1a7f1f008ff92bf2f88574ba lib/core/datatype.py @@ -46,10 +46,10 @@ b9ff4e622c416116bee6024c0f050349 lib/core/enums.py d8e9250f3775119df07e9070eddccd16 lib/core/replication.py 785f86e3f963fa3798f84286a4e83ff2 lib/core/revision.py 40c80b28b3a5819b737a5a17d4565ae9 lib/core/session.py -191a4cb7eea0a46315c894abd9491bcf lib/core/settings.py +68eee8e5cded862a7b123de3d7a94584 lib/core/settings.py d91291997d2bd2f6028aaf371bf1d3b6 lib/core/shell.py 2ad85c130cc5f2b3701ea85c2f6bbf20 lib/core/subprocessng.py -baa3f47efa6701076d026e43a6874a51 lib/core/target.py +4416fdcab26b286a5a3a88e75aa60044 lib/core/target.py 8970b88627902239d695280b1160e16c lib/core/testing.py b8306192d980abdc8d669c024511e9a1 lib/core/threads.py ad74fc58fc7214802fd27067bce18dd2 lib/core/unescaper.py @@ -57,7 +57,7 @@ ad74fc58fc7214802fd27067bce18dd2 lib/core/unescaper.py 4d13ed693401a498b6d073a2a494bd83 lib/core/wordlist.py 310efc965c862cfbd7b0da5150a5ad36 lib/__init__.py 8c4b04062db2245d9e190b413985202a lib/parse/banner.py -0557c5fee58f2578e0dd502b1839e3a3 lib/parse/cmdline.py +d548e2bff2edae0b0e40364a439bb6d4 lib/parse/cmdline.py 3a31657bc38f277d0016ff6d50bde61f lib/parse/configfile.py 14539f1be714d4f1ed042067d63bc50a lib/parse/handler.py 64e5bb3ecbdd75144500588b437ba8da lib/parse/headers.py @@ -68,16 +68,16 @@ ad74fc58fc7214802fd27067bce18dd2 lib/core/unescaper.py 403d873f1d2fd0c7f73d83f104e41850 lib/request/basicauthhandler.py 3ba1c71e68953d34fc526a9d79d5a457 lib/request/basic.py ef48de622b0a6b4a71df64b0d2785ef8 lib/request/comparison.py -4b056460279e65eef5f4f4fe293e657b lib/request/connect.py +bfd08465f7bc259cc9af008da0ffb4c3 lib/request/connect.py fb6b788d0016ab4ec5e5f661f0f702ad lib/request/direct.py cc1163d38e9b7ee5db2adac6784c02bb lib/request/dns.py 5dcdb37823a0b5eff65cd1018bcf09e4 lib/request/httpshandler.py 310efc965c862cfbd7b0da5150a5ad36 lib/request/__init__.py -70ec3f5bce37cdd7bf085ba2ddda30ac lib/request/inject.py +f7660e11e23e977b00922e241b1a3000 lib/request/inject.py dc1e0af84ee8eb421797d61c8cb8f172 lib/request/methodrequest.py bb9c165b050f7696b089b96b5947fac3 lib/request/pkihandler.py 602d4338a9fceaaee40c601410d8ac0b lib/request/rangehandler.py -111b3ee936f23167b5654a5f72e9731b lib/request/redirecthandler.py +3ba71e1571d105386d4d30746f5d6ab2 lib/request/redirecthandler.py b373770137dc885889e495de95169b93 lib/request/templates.py 992a02767d12254784f15501a7ab8dd8 lib/takeover/abstraction.py c6bc7961a186baabe0a9f5b7e0d8974b lib/takeover/icmpsh.py @@ -98,12 +98,12 @@ d3da4c7ceaf57c4687a052d58722f6bb lib/techniques/dns/use.py 310efc965c862cfbd7b0da5150a5ad36 lib/techniques/union/__init__.py d71e48e6fd08f75cc612bf8b260994ce lib/techniques/union/test.py db3090ff9a740ba096ba676fcf44ebfc lib/techniques/union/use.py -a73c3ddd0de359507a8ad59b363aa963 lib/utils/api.py +9e903297f6d6bb11660af5c7b109ccab lib/utils/api.py 7d10ba0851da8ee9cd3c140dcd18798e lib/utils/brute.py -ed70f1ca9113664043ec9e6778e48078 lib/utils/crawler.py +c08d2487a53a1db8170178ebcf87c864 lib/utils/crawler.py ba12c69a90061aa14d848b8396e79191 lib/utils/deps.py 3b9fd519164e0bf275d5fd361c3f11ff lib/utils/getch.py -3b93150eea78ea84fa0461a55e3e48ec lib/utils/har.py +7143c26b3e18973bc5169c202b775245 lib/utils/har.py ccfdad414ce2ec0c394c3deaa39a82bf lib/utils/hashdb.py 12e0e0ab70c6fe5786bc561c35dc067f lib/utils/hash.py e76a08237ee6a4cd6855af79610ea8a5 lib/utils/htmlentities.py @@ -174,7 +174,7 @@ e43fda42decf2a70bad470b884674fbe plugins/dbms/mysql/fingerprint.py 96dfafcc4aecc1c574148ac05dbdb6da plugins/dbms/mysql/syntax.py 33b2dc28075ab560fd8a4dc898682a0d plugins/dbms/mysql/takeover.py ea4b9cd238075b79945bd2607810934a plugins/dbms/oracle/connector.py -73fc1502dff934f008e3e2590b2609e7 plugins/dbms/oracle/enumeration.py +0471e3bf8310064e28e7c36064056e8d plugins/dbms/oracle/enumeration.py dc5962a1d4d69d4206b6c03e00e7f33d plugins/dbms/oracle/filesystem.py 525381f48505095b14e567c1f59ca9c7 plugins/dbms/oracle/fingerprint.py 25a99a9dd7072b6b7346438599c78050 plugins/dbms/oracle/__init__.py @@ -201,7 +201,7 @@ deed74334b637767fc9de8f74b37647a plugins/dbms/sybase/fingerprint.py 45436a42c2bb8075e1482a950d993d55 plugins/dbms/sybase/__init__.py 89412a921c8c598c19d36762d5820f05 plugins/dbms/sybase/syntax.py 654cd5e69cf5e5c644bfa5d284e61206 plugins/dbms/sybase/takeover.py -3371edd2292e3daec8df238034684232 plugins/generic/connector.py +f700954549ad8ebf77f5187262fb9af0 plugins/generic/connector.py 5390591ca955036d492de11355b52e8f plugins/generic/custom.py 4ad4bccc03256b8f3d21ba4f8f759404 plugins/generic/databases.py 106f19c1d895963e2efa8ee193a537ec plugins/generic/entries.py @@ -213,7 +213,7 @@ deed74334b637767fc9de8f74b37647a plugins/dbms/sybase/fingerprint.py 070f58c52e2a04e7a9896b42b2d17dc2 plugins/generic/search.py 562cfa80a15d5f7f1d52e10c5736d7e2 plugins/generic/syntax.py fca9946e960942cc9b22ef26e12b8b3a plugins/generic/takeover.py -bc0b47ced3db9f6746966d8dfc423b56 plugins/generic/users.py +f97b84b8dcbe80b2d86bc26829aed23b plugins/generic/users.py 310efc965c862cfbd7b0da5150a5ad36 plugins/__init__.py b04db3e861edde1f9dd0a3850d5b96c8 shell/backdoor.asp_ 158bfa168128393dde8d6ed11fe9a1b8 shell/backdoor.aspx_ @@ -224,7 +224,7 @@ c3cc8b7727161e64ab59f312c33b541a shell/stager.aspx_ 1f7f125f30e0e800beb21e2ebbab18e1 shell/stager.jsp_ 01e3505e796edf19aad6a996101c81c9 shell/stager.php_ 0751a45ac4c130131f2cdb74d866b664 sqlmapapi.py -290b98e6923960e17bdef3db0a05b44c sqlmap.py +a41c8ad1a5a8f9535d094a637c2990fd sqlmap.py 08c711a470d7e0bf705320ba3c48b886 tamper/apostrophemask.py e8509df10d3f1c28014d7825562d32dd tamper/apostrophenullencode.py bb27f7dc980ea07fcfedbd7da5e5e029 tamper/appendnullbyte.py @@ -265,7 +265,7 @@ b2331640743170f82be9a8c27f65b206 tamper/space2morecomment.py 507a174c64345df8df003ddba93c8cd1 tamper/space2morehash.py 0ce89b0d602abbd64344ab038be8acbc tamper/space2mssqlblank.py fa66af20648b5538289748abe7a08fe6 tamper/space2mssqlhash.py -9dde72d94ce42bf71e3615108fe0214f tamper/space2mysqlblank.py +b5abc11a45e9646cd0e296548c42e787 tamper/space2mysqlblank.py 038b8ea90f9a3a45b9bc67fcdff38511 tamper/space2mysqldash.py 5665c217ef8998bfd18f9ef1d8c617bd tamper/space2plus.py a30fa43203d960c7a9d8709bf24ca401 tamper/space2randomblank.py @@ -460,4 +460,4 @@ a279656ea3fcb85c727249b02f828383 xml/livetests.xml 3194e2688a7576e1f877d5b137f7c260 xml/payloads/stacked_queries.xml c2d8dd03db5a663e79eabb4495dd0723 xml/payloads/time_blind.xml ac649aff0e7db413e4937e446e398736 xml/payloads/union_query.xml -7fa7db2c2296baa5e9ea381d4880492f xml/queries.xml +8f984712da3f23f105fc0b3391114e4b xml/queries.xml diff --git a/xml/queries.xml b/xml/queries.xml index bc36a8ad8..f4a177485 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -283,7 +283,7 @@ - + @@ -506,7 +506,7 @@ - + @@ -563,7 +563,7 @@ - + @@ -586,7 +586,7 @@ - + @@ -601,7 +601,7 @@ - + @@ -611,23 +611,23 @@ - + - + - + - + @@ -635,19 +635,19 @@ - + - + - + - +