diff --git a/.travis.yml b/.travis.yml index 7bfe0cef7..192acbf75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,7 @@ language: python +sudo: false +git: + depth: 1 python: - "2.6" - "2.7" diff --git a/extra/icmpsh/icmpsh_m.py b/extra/icmpsh/icmpsh_m.py index 6e96952b3..23a60b865 100644 --- a/extra/icmpsh/icmpsh_m.py +++ b/extra/icmpsh/icmpsh_m.py @@ -125,8 +125,12 @@ def main(src, dst): # Have the IP packet contain the ICMP packet (along with its payload) ip.contains(icmp) - # Send it to the target host - sock.sendto(ip.get_packet(), (dst, 0)) + try: + # Send it to the target host + sock.sendto(ip.get_packet(), (dst, 0)) + except socket.error, ex: + sys.stderr.write("'%s'\n" % ex) + sys.stderr.flush() if __name__ == '__main__': if len(sys.argv) < 3: diff --git a/extra/shutils/newlines.py b/extra/shutils/newlines.py new file mode 100644 index 000000000..5fd91f969 --- /dev/null +++ b/extra/shutils/newlines.py @@ -0,0 +1,31 @@ +#! /usr/bin/env python + +# Runs pylint on all python scripts found in a directory tree +# Reference: http://rowinggolfer.blogspot.com/2009/08/pylint-recursively.html + +import os +import re +import sys + +def check(filepath): + if filepath.endswith(".py"): + content = open(filepath, "rb").read() + #if re.search(r"\r?\n\r?\n", content): + if "\n\n\n" in content: + index = content.find("\n\n\n") + print filepath, repr(content[index-30:index+30]) + +if __name__ == "__main__": + try: + BASE_DIRECTORY = sys.argv[1] + except IndexError: + print "no directory specified, defaulting to current working directory" + BASE_DIRECTORY = os.getcwd() + + print "looking for *.py scripts in subdirectories of ", BASE_DIRECTORY + for root, dirs, files in os.walk(BASE_DIRECTORY): + if any(_ in root for _ in ("extra", "thirdparty")): + continue + for name in files: + filepath = os.path.join(root, name) + check(filepath) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index ff238e978..d1a26ade3 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -47,6 +47,7 @@ from lib.core.common import unArrayizeValue from lib.core.common import urlencode from lib.core.common import wasLastResponseDBMSError from lib.core.common import wasLastResponseHTTPError +from lib.core.convert import unicodeencode from lib.core.defaults import defaults from lib.core.data import conf from lib.core.data import kb @@ -54,6 +55,7 @@ from lib.core.data import logger from lib.core.datatype import AttribDict from lib.core.datatype import InjectionDict from lib.core.decorators import cachedmethod +from lib.core.decorators import stackedmethod from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import DBMS from lib.core.enums import HASHDB_KEYS @@ -146,8 +148,7 @@ def checkSqlInjection(place, parameter, value): # error message, simple heuristic check or via DBMS-specific # payload), ask the user to limit the tests to the fingerprinted # DBMS - if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), \ - SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms): + if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms): msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms) msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]" kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y', boolean=True) else [] @@ -156,9 +157,7 @@ def checkSqlInjection(place, parameter, value): # message, via simple heuristic check or via DBMS-specific # payload), ask the user to extend the tests to all DBMS-specific, # regardless of --level and --risk values provided - if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) \ - and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or \ - kb.heuristicDbms or injection.dbms): + if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms): msg = "for the remaining tests, do you want to include all tests " msg += "for '%s' extending provided " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms) msg += "level (%d)" % conf.level if conf.level < 5 else "" @@ -206,7 +205,7 @@ def checkSqlInjection(place, parameter, value): continue match = re.search(r"(\d+)-(\d+)", test.request.columns) - if injection.data and match: + if match and injection.data: lower, upper = int(match.group(1)), int(match.group(2)) for _ in (lower, upper): if _ > 1: @@ -242,9 +241,7 @@ def checkSqlInjection(place, parameter, value): # Skip tests if title, vector or DBMS is not included by the # given test filter - if conf.testFilter and not any(conf.testFilter in str(item) or \ - re.search(conf.testFilter, str(item), re.I) for item in \ - (test.title, test.vector, payloadDbms)): + if conf.testFilter and not any(conf.testFilter in str(item) or re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector, payloadDbms)): debugMsg = "skipping test '%s' because its " % title debugMsg += "name/vector/DBMS is not included by the given filter" logger.debug(debugMsg) @@ -252,9 +249,7 @@ def checkSqlInjection(place, parameter, value): # Skip tests if title, vector or DBMS is included by the # given skip filter - if conf.testSkip and any(conf.testSkip in str(item) or \ - re.search(conf.testSkip, str(item), re.I) for item in \ - (test.title, test.vector, payloadDbms)): + if conf.testSkip and any(conf.testSkip in str(item) or re.search(conf.testSkip, str(item), re.I) for item in (test.title, test.vector, payloadDbms)): debugMsg = "skipping test '%s' because its " % title debugMsg += "name/vector/DBMS is included by the given skip filter" logger.debug(debugMsg) @@ -336,6 +331,23 @@ def checkSqlInjection(place, parameter, value): logger.debug(debugMsg) continue + if stype == PAYLOAD.TECHNIQUE.UNION: + match = re.search(r"(\d+)-(\d+)", test.request.columns) + if match and not injection.data: + _ = test.request.columns.split('-')[-1] + if conf.uCols is None and _.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 = not readInput(msg, default='Y', boolean=True) + + if kb.futileUnion is False: + debugMsg = "skipping test '%s'" % title + logger.debug(debugMsg) + continue + infoMsg = "testing '%s'" % title logger.info(infoMsg) @@ -442,11 +454,13 @@ def checkSqlInjection(place, parameter, value): 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: + stripPayload = re.sub(r"(\A|\b|_)([A-Za-z]{4}((?.\g<4>", reqPayload) + if stripPayload in seenPayload: continue else: - seenPayload.add(reqPayload) + seenPayload.add(stripPayload) else: reqPayload = None @@ -498,12 +512,16 @@ def checkSqlInjection(place, parameter, value): errorResult = Request.queryPage(errorPayload, place, raise404=False) if errorResult: continue - elif not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): + elif kb.heuristicPage and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): _ = comparison(kb.heuristicPage, None, getRatioValue=True) if _ > kb.matchRatio: kb.matchRatio = _ logger.debug("adjusting match ratio for current parameter to %.3f" % kb.matchRatio) + # Reducing false-positive "appears" messages in heavily dynamic environment + if kb.heavilyDynamic and not Request.queryPage(reqPayload, place, raise404=False): + continue + injectable = True elif threadData.lastComparisonRatio > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): @@ -588,10 +606,10 @@ def checkSqlInjection(place, parameter, value): # body for the test's regular expression try: page, headers, _ = Request.queryPage(reqPayload, place, content=True, raise404=False) - output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) \ - or extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None, re.DOTALL | re.IGNORECASE) \ - or extractRegexResult(check, listToStrValue((headers[key] for key in headers.keys() if key.lower() != URI_HTTP_HEADER.lower()) if headers else None), re.DOTALL | re.IGNORECASE) \ - or extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE) + output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) + output = output or extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None, re.DOTALL | re.IGNORECASE) + output = output or extractRegexResult(check, listToStrValue((headers[key] for key in headers.keys() if key.lower() != URI_HTTP_HEADER.lower()) if headers else None), re.DOTALL | re.IGNORECASE) + output = output or extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE) if output: result = output == "1" @@ -660,18 +678,6 @@ 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 = not readInput(msg, default='Y', boolean=True) - if kb.futileUnion is False: - continue # Test for UNION query SQL injection reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix) @@ -688,7 +694,7 @@ def checkSqlInjection(place, parameter, value): kb.previousMethod = method - if conf.dummy or conf.offline: + if conf.offline: injectable = False # If the injection test was successful feed the injection @@ -830,6 +836,7 @@ def checkSqlInjection(place, parameter, value): return injection +@stackedmethod def heuristicCheckDbms(injection): """ This functions is called when boolean-based blind is identified with a @@ -866,6 +873,7 @@ def heuristicCheckDbms(injection): return retVal +@stackedmethod def checkFalsePositives(injection): """ Checks for false positives (only in single special cases) @@ -873,8 +881,7 @@ def checkFalsePositives(injection): retVal = True - 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): + 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 @@ -928,6 +935,7 @@ def checkFalsePositives(injection): return retVal +@stackedmethod def checkSuhosinPatch(injection): """ Checks for existence of Suhosin-patch (and alike) protection mechanism(s) @@ -951,6 +959,7 @@ def checkSuhosinPatch(injection): kb.injection = popValue() +@stackedmethod def checkFilteredChars(injection): debugMsg = "checking for filtered characters" logger.debug(debugMsg) @@ -971,7 +980,7 @@ def checkFilteredChars(injection): # inference techniques depend on character '>' if not any(_ in injection.data for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.QUERY)): - if not checkBooleanExpression("%d>%d" % (randInt+1, randInt)): + if not checkBooleanExpression("%d>%d" % (randInt + 1, randInt)): warnMsg = "it appears that the character '>' is " warnMsg += "filtered by the back-end server. You are strongly " warnMsg += "advised to rerun with the '--tamper=between'" @@ -985,6 +994,11 @@ def heuristicCheckSqlInjection(place, parameter): logger.debug(debugMsg) return None + if kb.heavilyDynamic: + debugMsg = "heuristic check skipped because of heavy dynamicity" + logger.debug(debugMsg) + return None + origValue = conf.paramDict[place][parameter] paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place @@ -1171,6 +1185,8 @@ def checkDynamicContent(firstPage, secondPage): warnMsg += "sqlmap is going to retry the request(s)" singleTimeLogMessage(warnMsg, logging.CRITICAL) + kb.heavilyDynamic = True + secondPage, _, _ = Request.queryPage(content=True) findDynamicContent(firstPage, secondPage) @@ -1306,6 +1322,7 @@ def checkRegexp(): return True +@stackedmethod def checkWaf(): """ Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse @@ -1332,14 +1349,19 @@ def checkWaf(): retVal = False payload = "%d %s" % (randomInt(), IDS_WAF_CHECK_PAYLOAD) - value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER - value += agent.addPayloadDelimiters("%s=%s" % (randomStr(), payload)) + if PLACE.URI in conf.parameters: + place = PLACE.POST + value = "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload)) + else: + place = PLACE.GET + value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER + value += "%s=%s" % (randomStr(), agent.addPayloadDelimiters(payload)) pushValue(conf.timeout) conf.timeout = IDS_WAF_CHECK_TIMEOUT try: - retVal = Request.queryPage(place=PLACE.GET, value=value, getRatioValue=True, noteResponseTime=False, silent=True)[1] < IDS_WAF_CHECK_RATIO + retVal = Request.queryPage(place=place, value=value, getRatioValue=True, noteResponseTime=False, silent=True, disableTampering=True)[1] < IDS_WAF_CHECK_RATIO except SqlmapConnectionException: retVal = True finally: @@ -1366,6 +1388,7 @@ def checkWaf(): return retVal +@stackedmethod def identifyWaf(): if not conf.identifyWaf: return None @@ -1450,6 +1473,7 @@ def identifyWaf(): return retVal +@stackedmethod def checkNullConnection(): """ Reference: http://www.wisec.it/sectou.php?id=472f952d79293 @@ -1498,18 +1522,19 @@ def checkNullConnection(): return kb.nullConnection is not None def checkConnection(suppressOutput=False): - if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)): - try: - debugMsg = "resolving hostname '%s'" % conf.hostname - logger.debug(debugMsg) - socket.getaddrinfo(conf.hostname, None) - except socket.gaierror: - errMsg = "host '%s' does not exist" % conf.hostname - raise SqlmapConnectionException(errMsg) - except socket.error, ex: - errMsg = "problem occurred while " - errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex)) - raise SqlmapConnectionException(errMsg) + if not re.search(r"\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z", conf.hostname): + if not any((conf.proxy, conf.tor, conf.dummy, conf.offline)): + try: + debugMsg = "resolving hostname '%s'" % conf.hostname + logger.debug(debugMsg) + socket.getaddrinfo(conf.hostname, None) + except socket.gaierror: + errMsg = "host '%s' does not exist" % conf.hostname + raise SqlmapConnectionException(errMsg) + except socket.error, ex: + errMsg = "problem occurred while " + errMsg += "resolving a host name '%s' ('%s')" % (conf.hostname, getSafeExString(ex)) + raise SqlmapConnectionException(errMsg) if not suppressOutput and not conf.dummy and not conf.offline: infoMsg = "testing connection to the target URL" @@ -1537,6 +1562,15 @@ def checkConnection(suppressOutput=False): else: kb.errorIsNone = True + threadData = getCurrentThreadData() + + if kb.redirectChoice == REDIRECTION.YES and threadData.lastRedirectURL and threadData.lastRedirectURL[0] == threadData.lastRequestUID: + if (threadData.lastRedirectURL[1] or "").startswith("https://") and unicodeencode(conf.hostname) in threadData.lastRedirectURL[1]: + conf.url = re.sub(r"https?://", "https://", conf.url) + match = re.search(r":(\d+)", threadData.lastRedirectURL[1]) + port = match.group(1) if match else 443 + conf.url = re.sub(r":\d+/", ":%s/" % port, conf.url) + except SqlmapConnectionException, ex: if conf.ipv6: warnMsg = "check connection to a provided " @@ -1567,8 +1601,8 @@ def checkInternet(): content = Request.getPage(url=CHECK_INTERNET_ADDRESS, checking=True)[0] return CHECK_INTERNET_VALUE in (content or "") -def setVerbosity(): # Cross-linked function +def setVerbosity(): # Cross-referenced function raise NotImplementedError -def setWafFunctions(): # Cross-linked function +def setWafFunctions(): # Cross-referenced function raise NotImplementedError diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 27708c867..ad12620c7 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -43,6 +43,7 @@ from lib.core.common import urldecode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger +from lib.core.decorators import stackedmethod from lib.core.enums import CONTENT_TYPE from lib.core.enums import HASHDB_KEYS from lib.core.enums import HEURISTIC_TEST @@ -152,7 +153,7 @@ def _formatInjection(inj): vector = "%s%s" % (vector, comment) data += " Type: %s\n" % PAYLOAD.SQLINJECTION[stype] data += " Title: %s\n" % title - data += " Payload: %s\n" % urldecode(payload, unsafe="&", plusspace=(inj.place != PLACE.GET and kb.postSpaceToPlus)) + data += " Payload: %s\n" % urldecode(payload, unsafe="&", spaceplus=(inj.place != PLACE.GET and kb.postSpaceToPlus)) data += " Vector: %s\n\n" % vector if conf.verbose > 1 else "\n" return data @@ -253,6 +254,7 @@ def _saveToResultsFile(): conf.resultsFP.flush() +@stackedmethod def start(): """ This function calls a function that performs checks on both URL @@ -286,7 +288,7 @@ def start(): try: if conf.checkInternet: - infoMsg = "[INFO] checking for Internet connection" + infoMsg = "checking for Internet connection" logger.info(infoMsg) if not checkInternet(): @@ -406,8 +408,7 @@ def start(): if conf.nullConnection: checkNullConnection() - if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) \ - and (kb.injection.place is None or kb.injection.parameter is None): + if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) and (kb.injection.place is None or kb.injection.parameter is None): if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech: # NOTE: this is not needed anymore, leaving only to display diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 988efd12c..6ce752dd2 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -56,19 +56,19 @@ def setHandler(): """ items = [ - (DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, MySQLConn), - (DBMS.ORACLE, ORACLE_ALIASES, OracleMap, OracleConn), - (DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, PostgreSQLConn), - (DBMS.MSSQL, MSSQL_ALIASES, MSSQLServerMap, MSSQLServerConn), - (DBMS.SQLITE, SQLITE_ALIASES, SQLiteMap, SQLiteConn), - (DBMS.ACCESS, ACCESS_ALIASES, AccessMap, AccessConn), - (DBMS.FIREBIRD, FIREBIRD_ALIASES, FirebirdMap, FirebirdConn), - (DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, MaxDBConn), - (DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, SybaseConn), - (DBMS.DB2, DB2_ALIASES, DB2Map, DB2Conn), - (DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn), - (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn), - ] + (DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, MySQLConn), + (DBMS.ORACLE, ORACLE_ALIASES, OracleMap, OracleConn), + (DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, PostgreSQLConn), + (DBMS.MSSQL, MSSQL_ALIASES, MSSQLServerMap, MSSQLServerConn), + (DBMS.SQLITE, SQLITE_ALIASES, SQLiteMap, SQLiteConn), + (DBMS.ACCESS, ACCESS_ALIASES, AccessMap, AccessConn), + (DBMS.FIREBIRD, FIREBIRD_ALIASES, FirebirdMap, FirebirdConn), + (DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, MaxDBConn), + (DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, SybaseConn), + (DBMS.DB2, DB2_ALIASES, DB2Map, DB2Conn), + (DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn), + (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn), + ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else None for _ in items) if _: diff --git a/lib/core/agent.py b/lib/core/agent.py index ac41aadc2..b7bb3c4ea 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -121,8 +121,8 @@ class Agent(object): origValue = _.split('=', 1)[1] if '=' in _ else "" elif place == PLACE.CUSTOM_HEADER: paramString = origValue - origValue = origValue.split(kb.customInjectionMark)[0] origValue = origValue[origValue.find(',') + 1:] + origValue = origValue.split(kb.customInjectionMark)[0] match = re.search(r"([^;]+)=(?P[^;]*);?\Z", origValue) if match: origValue = match.group("value") @@ -294,17 +294,21 @@ class Agent(object): if payload is None: return - _ = ( - ("[DELIMITER_START]", kb.chars.start), ("[DELIMITER_STOP]", kb.chars.stop),\ - ("[AT_REPLACE]", kb.chars.at), ("[SPACE_REPLACE]", kb.chars.space), ("[DOLLAR_REPLACE]", kb.chars.dollar),\ - ("[HASH_REPLACE]", kb.chars.hash_), ("[GENERIC_SQL_COMMENT]", GENERIC_SQL_COMMENT) - ) - payload = reduce(lambda x, y: x.replace(y[0], y[1]), _, payload) + replacements = ( + ("[DELIMITER_START]", kb.chars.start), + ("[DELIMITER_STOP]", kb.chars.stop), + ("[AT_REPLACE]", kb.chars.at), + ("[SPACE_REPLACE]", kb.chars.space), + ("[DOLLAR_REPLACE]", kb.chars.dollar), + ("[HASH_REPLACE]", kb.chars.hash_), + ("[GENERIC_SQL_COMMENT]", GENERIC_SQL_COMMENT) + ) + payload = reduce(lambda x, y: x.replace(y[0], y[1]), replacements, payload) - for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)): + for _ in set(re.findall(r"(?i)\[RANDNUM(?:\d+)?\]", payload)): payload = payload.replace(_, str(randomInt())) - for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): + for _ in set(re.findall(r"(?i)\[RANDSTR(?:\d+)?\]", payload)): payload = payload.replace(_, randomStr()) if origValue is not None and "[ORIGVALUE]" in payload: @@ -928,7 +932,7 @@ class Agent(object): limitedQuery += " %s" % limitStr elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): - if not " ORDER BY " in limitedQuery: + if " ORDER BY " not in limitedQuery: limitStr = limitStr.replace(") WHERE LIMIT", " ORDER BY 1 ASC) WHERE LIMIT") elif " ORDER BY " in limitedQuery and "SELECT " in limitedQuery: limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")] diff --git a/lib/core/bigarray.py b/lib/core/bigarray.py index f733b81cb..f12d23148 100644 --- a/lib/core/bigarray.py +++ b/lib/core/bigarray.py @@ -6,9 +6,9 @@ See the file 'LICENSE' for copying permission """ try: - import cPickle as pickle + import cPickle as pickle except: - import pickle + import pickle import bz2 import itertools @@ -90,7 +90,7 @@ class BigArray(list): except IOError, ex: errMsg = "exception occurred while retrieving data " errMsg += "from a temporary file ('%s')" % ex.message - raise SqlmapSystemException, errMsg + raise SqlmapSystemException(errMsg) return self.chunks[-1].pop() @@ -115,7 +115,7 @@ class BigArray(list): 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" - raise SqlmapSystemException, errMsg + raise SqlmapSystemException(errMsg) def _checkcache(self, index): if (self.cache and self.cache.index != index and self.cache.dirty): @@ -129,7 +129,7 @@ class BigArray(list): except IOError, ex: errMsg = "exception occurred while retrieving data " errMsg += "from a temporary file ('%s')" % ex.message - raise SqlmapSystemException, errMsg + raise SqlmapSystemException(errMsg) def __getstate__(self): return self.chunks, self.filenames diff --git a/lib/core/common.py b/lib/core/common.py index 6b36d1ec0..e877dde50 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -596,9 +596,7 @@ def paramToDict(place, parameters=None): testableParameters[parameter] = "=".join(parts[1:]) if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken): _ = urldecode(testableParameters[parameter], convall=True) - if (_.endswith("'") and _.count("'") == 1 - or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _))\ - and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX): + if (_.endswith("'") and _.count("'") == 1 or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _)) and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX): warnMsg = "it appears that you have provided tainted parameter values " warnMsg += "('%s') with most likely leftover " % element warnMsg += "chars/statements from manual SQL injection test(s). " @@ -651,7 +649,7 @@ def paramToDict(place, parameters=None): message = "it appears that provided value for %s parameter '%s' " % (place, parameter) message += "is JSON deserializable. Do you want to inject inside? [y/N] " - if not readInput(message, default='N', boolean=True): + if readInput(message, default='N', boolean=True): del testableParameters[parameter] testableParameters.update(candidates) break @@ -1017,8 +1015,11 @@ def readInput(message, default=None, checkBatch=True, boolean=False): elif answer is None and retVal: retVal = "%s,%s" % (retVal, getUnicode(item, UNICODE_ENCODING)) + if message and getattr(LOGGER_HANDLER, "is_tty", False): + message = "\r%s" % message + if retVal: - dataToStdout("\r%s%s\n" % (message, retVal), forceOutput=not kb.wizardMode, bold=True) + dataToStdout("%s%s\n" % (message, retVal), forceOutput=not kb.wizardMode, bold=True) debugMsg = "used the given answer" logger.debug(debugMsg) @@ -1032,7 +1033,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False): else: options = unicode() - dataToStdout("\r%s%s\n" % (message, options), forceOutput=not kb.wizardMode, bold=True) + dataToStdout("%s%s\n" % (message, options), forceOutput=not kb.wizardMode, bold=True) debugMsg = "used the default behavior, running in batch mode" logger.debug(debugMsg) @@ -1045,7 +1046,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False): if conf.get("beep"): beep() - dataToStdout("\r%s" % message, forceOutput=not kb.wizardMode, bold=True) + dataToStdout("%s" % message, forceOutput=not kb.wizardMode, bold=True) kb.prependFlag = False retVal = raw_input().strip() or default @@ -1371,7 +1372,7 @@ def parseTargetDirect(): raise SqlmapSyntaxException(errMsg) if dbmsName in (DBMS.MSSQL, DBMS.SYBASE): - import _mssql + __import__("_mssql") import pymssql if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2": @@ -1381,17 +1382,17 @@ def parseTargetDirect(): raise SqlmapMissingDependence(errMsg) elif dbmsName == DBMS.MYSQL: - import pymysql + __import__("pymysql") elif dbmsName == DBMS.PGSQL: - import psycopg2 + __import__("psycopg2") elif dbmsName == DBMS.ORACLE: - import cx_Oracle + __import__("cx_Oracle") elif dbmsName == DBMS.SQLITE: - import sqlite3 + __import__("sqlite3") elif dbmsName == DBMS.ACCESS: - import pyodbc + __import__("pyodbc") elif dbmsName == DBMS.FIREBIRD: - import kinterbasdb + __import__("kinterbasdb") except: if _sqlalchemy and data[3] in _sqlalchemy.dialects.__all__: pass @@ -1419,7 +1420,7 @@ def parseTargetUrl(): raise SqlmapGenericException(errMsg) if not re.search(r"^http[s]*://", conf.url, re.I) and not re.search(r"^ws[s]*://", conf.url, re.I): - if ":443/" in conf.url: + if re.search(r":443\b", conf.url): conf.url = "https://%s" % conf.url else: conf.url = "http://%s" % conf.url @@ -1445,13 +1446,14 @@ def parseTargetUrl(): conf.hostname = conf.hostname.strip("[]").replace(kb.customInjectionMark, "") try: - _ = conf.hostname.encode("idna") - except LookupError: - _ = conf.hostname.encode(UNICODE_ENCODING) - except UnicodeError: - _ = None + conf.hostname.encode("idna") + conf.hostname.encode(UNICODE_ENCODING) + except (LookupError, UnicodeError): + invalid = True + else: + invalid = False - if any((_ is None, re.search(r"\s", conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'), '\n' in originalUrl)): + if any((invalid, re.search(r"\s", conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'), '\n' in originalUrl)): errMsg = "invalid target URL ('%s')" % originalUrl raise SqlmapSyntaxException(errMsg) @@ -1494,6 +1496,23 @@ def parseTargetUrl(): if conf.url != originalUrl: kb.originalUrls[conf.url] = originalUrl +def escapeJsonValue(value): + """ + Escapes JSON value (used in payloads) + + # Reference: https://stackoverflow.com/a/16652683 + """ + + retVal = "" + + for char in value: + if char < ' ' or char == '"': + retVal += json.dumps(char)[1:-1] + else: + retVal += char + + return retVal + def expandAsteriskForColumns(expression): """ If the user provided an asterisk rather than the column(s) @@ -2005,7 +2024,7 @@ def parseXmlFile(xmlFile, handler): errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" - raise SqlmapInstallationException, errMsg + raise SqlmapInstallationException(errMsg) def getSQLSnippet(dbms, sfile, **variables): """ @@ -2536,7 +2555,7 @@ def findMultipartPostBoundary(post): return retVal -def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, plusspace=True): +def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CHAR, convall=False, spaceplus=True): """ URL decodes given value @@ -2554,14 +2573,14 @@ def urldecode(value, encoding=None, unsafe="%%&=;+%s" % CUSTOM_INJECTION_MARK_CH pass finally: if convall: - result = urllib.unquote_plus(value) if plusspace else urllib.unquote(value) + result = urllib.unquote_plus(value) if spaceplus else urllib.unquote(value) else: def _(match): charset = reduce(lambda x, y: x.replace(y, ""), unsafe, string.printable) char = chr(ord(match.group(1).decode("hex"))) return char if char in charset else match.group(0) result = value - if plusspace: + if spaceplus: result = result.replace('+', ' ') # plus sign has a special meaning in URL encoded data (hence the usage of urllib.unquote_plus in convall case) result = re.sub(r"%([0-9a-fA-F]{2})", _, result) @@ -2663,7 +2682,7 @@ def logHTTPTraffic(requestLogMsg, responseLogMsg, startTime=None, endTime=None): dataToTrafficFile("%s%s" % (responseLogMsg, os.linesep)) dataToTrafficFile("%s%s%s%s" % (os.linesep, 76 * '#', os.linesep, os.linesep)) -def getPageTemplate(payload, place): # Cross-linked function +def getPageTemplate(payload, place): # Cross-referenced function raise NotImplementedError @cachedmethod @@ -2996,7 +3015,7 @@ def setOptimize(): Sets options turned on by switch '-o' """ - #conf.predictOutput = True + # conf.predictOutput = True conf.keepAlive = True conf.threads = 3 if conf.threads < 3 else conf.threads conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor)) @@ -3200,9 +3219,7 @@ def showHttpErrorCodes(): if kb.httpErrorCodes: warnMsg = "HTTP error codes detected during run:\n" - warnMsg += ", ".join("%d (%s) - %d times" % (code, httplib.responses[code] \ - if code in httplib.responses else '?', count) \ - for code, count in kb.httpErrorCodes.items()) + warnMsg += ", ".join("%d (%s) - %d times" % (code, httplib.responses[code] if code in httplib.responses else '?', count) for code, count in kb.httpErrorCodes.items()) logger.warn(warnMsg) if any((str(_).startswith('4') or str(_).startswith('5')) and _ != httplib.INTERNAL_SERVER_ERROR and _ != kb.originalCode for _ in kb.httpErrorCodes.keys()): msg = "too many 4xx and/or 5xx HTTP error codes " @@ -3218,8 +3235,7 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="replace", bu return codecs.open(filename, mode, encoding, errors, buffering) except IOError: errMsg = "there has been a file opening error for filename '%s'. " % filename - errMsg += "Please check %s permissions on a file " % ("write" if \ - mode and ('w' in mode or 'a' in mode or '+' in mode) else "read") + errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read") errMsg += "and that it's not locked by another process." raise SqlmapSystemException(errMsg) @@ -3284,14 +3300,17 @@ def checkIntegrity(): logger.debug("running code integrity check") retVal = True - for checksum, _ in (re.split(r'\s+', _) for _ in getFileItems(paths.CHECKSUM_MD5)): - path = os.path.normpath(os.path.join(paths.SQLMAP_ROOT_PATH, _)) - if not os.path.isfile(path): - logger.error("missing file detected '%s'" % path) - retVal = False - elif md5File(path) != checksum: - logger.error("wrong checksum of file '%s' detected" % path) - retVal = False + + if os.path.isfile(paths.CHECKSUM_MD5): + for checksum, _ in (re.split(r'\s+', _) for _ in getFileItems(paths.CHECKSUM_MD5)): + path = os.path.normpath(os.path.join(paths.SQLMAP_ROOT_PATH, _)) + if not os.path.isfile(path): + logger.error("missing file detected '%s'" % path) + retVal = False + elif md5File(path) != checksum: + logger.error("wrong checksum of file '%s' detected" % path) + retVal = False + return retVal def unhandledExceptionMessage(): @@ -3874,7 +3893,7 @@ def asciifyUrl(url, forceQuote=False): # urllib.quote(s.replace('%', '')) != s.replace('%', '') # which would trigger on all %-characters, e.g. "&". if getUnicode(s).encode("ascii", "replace") != s or forceQuote: - return urllib.quote(s.encode(UNICODE_ENCODING), safe=safe) + return urllib.quote(s.encode(UNICODE_ENCODING) if isinstance(s, unicode) else s, safe=safe) return s username = quote(parts.username, '') @@ -3932,6 +3951,9 @@ def isAdminFromPrivileges(privileges): def findPageForms(content, url, raise_=False, addToTargets=False): """ Parses given page content for possible forms + + >>> findPageForms('
', '') + set([(u'/input.php', 'POST', u'id=1', None, None)]) """ class _(StringIO): @@ -3954,8 +3976,6 @@ def findPageForms(content, url, raise_=False, addToTargets=False): try: forms = ParseResponse(response, backwards_compat=False) - except (UnicodeError, ValueError): - pass except ParseError: if re.search(r"(?i) 1: func = self.stack[-2] if func not in PICKLE_REDUCE_WHITELIST: - raise Exception, "abusing reduce() is bad, Mkay!" + raise Exception("abusing reduce() is bad, Mkay!") self.load_reduce() def loads(str): @@ -94,7 +94,7 @@ def base64unpickle(value, unsafe=False): try: retVal = loads(base64decode(value)) - except TypeError: + except TypeError: retVal = loads(base64decode(bytes(value))) return retVal @@ -174,7 +174,7 @@ def htmlunescape(value): pass return retVal -def singleTimeWarnMessage(message): # Cross-linked function +def singleTimeWarnMessage(message): # Cross-referenced function sys.stdout.write(message) sys.stdout.write("\n") sys.stdout.flush() diff --git a/lib/core/decorators.py b/lib/core/decorators.py index c4040f267..1bf5d5127 100644 --- a/lib/core/decorators.py +++ b/lib/core/decorators.py @@ -7,6 +7,8 @@ See the file 'LICENSE' for copying permission import hashlib +from lib.core.threads import getCurrentThreadData + def cachedmethod(f, cache={}): """ Method with a cached content @@ -15,10 +17,25 @@ def cachedmethod(f, cache={}): """ def _(*args, **kwargs): - key = int(hashlib.md5("".join(str(_) for _ in (f, args, kwargs))).hexdigest()[:8], 16) + key = int(hashlib.md5("|".join(str(_) for _ in (f, args, kwargs))).hexdigest(), 16) & 0x7fffffffffffffff if key not in cache: cache[key] = f(*args, **kwargs) return cache[key] return _ + +def stackedmethod(f): + def _(*args, **kwargs): + threadData = getCurrentThreadData() + originalLevel = len(threadData.valueStack) + + try: + result = f(*args, **kwargs) + finally: + if len(threadData.valueStack) > originalLevel: + threadData.valueStack = threadData.valueStack[:originalLevel] + + return result + + return _ \ No newline at end of file diff --git a/lib/core/defaults.py b/lib/core/defaults.py index 209e0999e..6c12164a1 100644 --- a/lib/core/defaults.py +++ b/lib/core/defaults.py @@ -8,20 +8,20 @@ See the file 'LICENSE' for copying permission from lib.core.datatype import AttribDict _defaults = { - "csvDel": ',', - "timeSec": 5, - "googlePage": 1, - "verbose": 1, - "delay": 0, - "timeout": 30, - "retries": 3, - "saFreq": 0, - "threads": 1, - "level": 1, - "risk": 1, - "dumpFormat": "CSV", - "tech": "BEUSTQ", - "torType": "SOCKS5", + "csvDel": ',', + "timeSec": 5, + "googlePage": 1, + "verbose": 1, + "delay": 0, + "timeout": 30, + "retries": 3, + "saFreq": 0, + "threads": 1, + "level": 1, + "risk": 1, + "dumpFormat": "CSV", + "tech": "BEUSTQ", + "torType": "SOCKS5", } defaults = AttribDict(_defaults) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index d999fb072..c07f65ff4 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -208,54 +208,60 @@ FROM_DUMMY_TABLE = { } SQL_STATEMENTS = { - "SQL SELECT statement": ( - "select ", - "show ", - " top ", - " distinct ", - " from ", - " from dual", - " where ", - " group by ", - " order by ", - " having ", - " limit ", - " offset ", - " union all ", - " rownum as ", - "(case ", ), + "SQL SELECT statement": ( + "select ", + "show ", + " top ", + " distinct ", + " from ", + " from dual", + " where ", + " group by ", + " order by ", + " having ", + " limit ", + " offset ", + " union all ", + " rownum as ", + "(case ", + ), - "SQL data definition": ( + "SQL data definition": ( "create ", "declare ", "drop ", "truncate ", - "alter ", ), + "alter ", + ), "SQL data manipulation": ( - "bulk ", - "insert ", - "update ", - "delete ", - "merge ", - "load ", ), + "bulk ", + "insert ", + "update ", + "delete ", + "merge ", + "load ", + ), - "SQL data control": ( - "grant ", - "revoke ", ), + "SQL data control": ( + "grant ", + "revoke ", + ), - "SQL data execution": ( - "exec ", - "execute ", - "values ", - "call ", ), + "SQL data execution": ( + "exec ", + "execute ", + "values ", + "call ", + ), - "SQL transaction": ( - "start transaction ", - "begin work ", - "begin transaction ", - "commit ", - "rollback ", ), + "SQL transaction": ( + "start transaction ", + "begin work ", + "begin transaction ", + "commit ", + "rollback ", + ), } POST_HINT_CONTENT_TYPES = { diff --git a/lib/core/dump.py b/lib/core/dump.py index 33f68e63d..b3e876c42 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -415,7 +415,7 @@ class Dump(object): elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if not os.path.isdir(dumpDbPath): try: - os.makedirs(dumpDbPath, 0755) + os.makedirs(dumpDbPath) except: warnFile = True @@ -424,7 +424,7 @@ class Dump(object): if not os.path.isdir(dumpDbPath): try: - os.makedirs(dumpDbPath, 0755) + os.makedirs(dumpDbPath) except Exception, ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapdb") @@ -612,7 +612,7 @@ class Dump(object): mimetype = magic.from_buffer(value, mime=True) if any(mimetype.startswith(_) for _ in ("application", "image")): if not os.path.isdir(dumpDbPath): - os.makedirs(dumpDbPath, 0755) + os.makedirs(dumpDbPath) _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column))) filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8))) diff --git a/lib/core/enums.py b/lib/core/enums.py index 775998684..638b80bbb 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -242,40 +242,40 @@ class REDIRECTION: class PAYLOAD: SQLINJECTION = { - 1: "boolean-based blind", - 2: "error-based", - 3: "inline query", - 4: "stacked queries", - 5: "AND/OR time-based blind", - 6: "UNION query", - } + 1: "boolean-based blind", + 2: "error-based", + 3: "inline query", + 4: "stacked queries", + 5: "AND/OR time-based blind", + 6: "UNION query", + } PARAMETER = { - 1: "Unescaped numeric", - 2: "Single quoted string", - 3: "LIKE single quoted string", - 4: "Double quoted string", - 5: "LIKE double quoted string", - } + 1: "Unescaped numeric", + 2: "Single quoted string", + 3: "LIKE single quoted string", + 4: "Double quoted string", + 5: "LIKE double quoted string", + } RISK = { - 0: "No risk", - 1: "Low risk", - 2: "Medium risk", - 3: "High risk", - } + 0: "No risk", + 1: "Low risk", + 2: "Medium risk", + 3: "High risk", + } CLAUSE = { - 0: "Always", - 1: "WHERE", - 2: "GROUP BY", - 3: "ORDER BY", - 4: "LIMIT", - 5: "OFFSET", - 6: "TOP", - 7: "Table name", - 8: "Column name", - } + 0: "Always", + 1: "WHERE", + 2: "GROUP BY", + 3: "ORDER BY", + 4: "LIMIT", + 5: "OFFSET", + 6: "TOP", + 7: "Table name", + 8: "Column name", + } class METHOD: COMPARISON = "comparison" diff --git a/lib/core/option.py b/lib/core/option.py index 0cfc3caa1..23daf5761 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -337,7 +337,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): if not host: errMsg = "invalid format of a request file" - raise SqlmapSyntaxException, errMsg + raise SqlmapSyntaxException(errMsg) if not url.startswith("http"): url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url) @@ -402,7 +402,7 @@ def _loadQueries(): errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" - raise SqlmapInstallationException, errMsg + raise SqlmapInstallationException(errMsg) for node in tree.findall("*"): queries[node.attrib['value']] = iterate(node) @@ -687,7 +687,7 @@ def _setMetasploit(): if IS_WIN: try: - import win32file + __import__("win32file") except ImportError: errMsg = "sqlmap requires third-party module 'pywin32' " errMsg += "in order to use Metasploit functionalities on " @@ -700,7 +700,7 @@ def _setMetasploit(): retVal = None try: - from _winreg import ConnectRegistry, OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE + from _winreg import ConnectRegistry, OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE _ = ConnectRegistry(None, HKEY_LOCAL_MACHINE) _ = OpenKey(_, key) retVal = QueryValueEx(_, value)[0] @@ -918,7 +918,7 @@ def _setTamperingFunctions(): dirname, filename = os.path.split(script) dirname = os.path.abspath(dirname) - infoMsg = "loading tamper script '%s'" % filename[:-3] + infoMsg = "loading tamper module '%s'" % filename[:-3] logger.info(infoMsg) if not os.path.exists(os.path.join(dirname, "__init__.py")): @@ -932,7 +932,7 @@ def _setTamperingFunctions(): try: module = __import__(filename[:-3].encode(sys.getfilesystemencoding() or UNICODE_ENCODING)) except Exception, ex: - raise SqlmapSyntaxException("cannot import tamper script '%s' (%s)" % (filename[:-3], getSafeExString(ex))) + raise SqlmapSyntaxException("cannot import tamper module '%s' (%s)" % (filename[:-3], getSafeExString(ex))) priority = PRIORITY.NORMAL if not hasattr(module, "__priority__") else module.__priority__ @@ -962,7 +962,12 @@ def _setTamperingFunctions(): break elif name == "dependencies": - function() + try: + function() + except Exception, ex: + errMsg = "error occurred while checking dependencies " + errMsg += "for tamper module '%s' ('%s')" % (filename[:-3], getSafeExString(ex)) + raise SqlmapGenericException(errMsg) if not found: errMsg = "missing function 'tamper(payload, **kwargs)' " @@ -1128,7 +1133,7 @@ def _setHTTPHandlers(): _ = urlparse.urlsplit(conf.proxy) except Exception, ex: errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex)) - raise SqlmapSyntaxException, errMsg + raise SqlmapSyntaxException(errMsg) hostnamePort = _.netloc.split(":") @@ -1255,7 +1260,7 @@ def _setSafeVisit(): kb.safeReq.post = None else: errMsg = "invalid format of a safe request file" - raise SqlmapSyntaxException, errMsg + raise SqlmapSyntaxException(errMsg) else: if not re.search(r"\Ahttp[s]*://", conf.safeUrl): if ":443/" in conf.safeUrl: @@ -1580,7 +1585,7 @@ def _createTemporaryDirectory(): except (OSError, IOError), ex: errMsg = "there has been a problem while accessing " errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex) - raise SqlmapSystemException, errMsg + raise SqlmapSystemException(errMsg) else: try: if not os.path.isdir(tempfile.gettempdir()): @@ -1607,7 +1612,7 @@ def _createTemporaryDirectory(): except (OSError, IOError, WindowsError), ex: errMsg = "there has been a problem while setting " errMsg += "temporary directory location ('%s')" % getSafeExString(ex) - raise SqlmapSystemException, errMsg + raise SqlmapSystemException(errMsg) def _cleanupOptions(): """ @@ -1945,6 +1950,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.forcePartialUnion = False kb.forceWhere = None kb.futileUnion = None + kb.heavilyDynamic = False kb.headersFp = {} kb.heuristicDbms = None kb.heuristicExtendedDbms = None @@ -2316,7 +2322,6 @@ def _setTorHttpProxySettings(): errMsg = "can't establish connection with the Tor HTTP proxy. " errMsg += "Please make sure that you have Tor (bundle) installed and setup " errMsg += "so you could be able to successfully use switch '--tor' " - raise SqlmapConnectionException(errMsg) if not conf.checkTor: @@ -2337,7 +2342,6 @@ def _setTorSocksProxySettings(): errMsg = "can't establish connection with the Tor SOCKS proxy. " errMsg += "Please make sure that you have Tor service installed and setup " errMsg += "so you could be able to successfully use switch '--tor' " - raise SqlmapConnectionException(errMsg) # SOCKS5 to prevent DNS leaks (http://en.wikipedia.org/wiki/Tor_%28anonymity_network%29) @@ -2350,7 +2354,7 @@ def _checkWebSocket(): from websocket import ABNF except ImportError: errMsg = "sqlmap requires third-party module 'websocket-client' " - errMsg += "in order to use WebSocket funcionality" + errMsg += "in order to use WebSocket functionality" raise SqlmapMissingDependence(errMsg) def _checkTor(): @@ -2542,11 +2546,11 @@ def _basicOptionValidation(): raise SqlmapSyntaxException(errMsg) if conf.checkTor and not any((conf.tor, conf.proxy)): - errMsg = "switch '--check-tor' requires usage of switch '--tor' (or option '--proxy' with HTTP proxy address using Tor)" + errMsg = "switch '--check-tor' requires usage of switch '--tor' (or option '--proxy' with HTTP proxy address of Tor service)" raise SqlmapSyntaxException(errMsg) if conf.torPort is not None and not (isinstance(conf.torPort, int) and conf.torPort >= 0 and conf.torPort <= 65535): - errMsg = "value for option '--tor-port' must be in range 0-65535" + errMsg = "value for option '--tor-port' must be in range [0, 65535]" raise SqlmapSyntaxException(errMsg) if conf.torType not in getPublicTypeMembers(PROXY_TYPE, True): diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index e71e4b3f1..b1f80398a 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -6,250 +6,252 @@ See the file 'LICENSE' for copying permission """ optDict = { - # Format: - # Family: { "parameter name": "parameter datatype" }, - # Or: - # Family: { "parameter name": ("parameter datatype", "category name used for common outputs feature") }, - "Target": { - "direct": "string", - "url": "string", - "logFile": "string", - "bulkFile": "string", - "requestFile": "string", - "sessionFile": "string", - "googleDork": "string", - "configFile": "string", - "sitemapUrl": "string", - }, + # Family: {"parameter name": "parameter datatype"}, + # --OR-- + # Family: {"parameter name": ("parameter datatype", "category name used for common outputs feature")}, - "Request": { - "method": "string", - "data": "string", - "paramDel": "string", - "cookie": "string", - "cookieDel": "string", - "loadCookies": "string", - "dropSetCookie": "boolean", - "agent": "string", - "randomAgent": "boolean", - "host": "string", - "referer": "string", - "headers": "string", - "authType": "string", - "authCred": "string", - "authFile": "string", - "ignoreCode": "integer", - "ignoreProxy": "boolean", - "ignoreRedirects": "boolean", - "ignoreTimeouts": "boolean", - "proxy": "string", - "proxyCred": "string", - "proxyFile": "string", - "tor": "boolean", - "torPort": "integer", - "torType": "string", - "checkTor": "boolean", - "delay": "float", - "timeout": "float", - "retries": "integer", - "rParam": "string", - "safeUrl": "string", - "safePost": "string", - "safeReqFile": "string", - "safeFreq": "integer", - "skipUrlEncode": "boolean", - "csrfToken": "string", - "csrfUrl": "string", - "forceSSL": "boolean", - "hpp": "boolean", - "evalCode": "string", - }, + "Target": { + "direct": "string", + "url": "string", + "logFile": "string", + "bulkFile": "string", + "requestFile": "string", + "sessionFile": "string", + "googleDork": "string", + "configFile": "string", + "sitemapUrl": "string", + }, - "Optimization": { - "optimize": "boolean", - "predictOutput": "boolean", - "keepAlive": "boolean", - "nullConnection": "boolean", - "threads": "integer", - }, + "Request": { + "method": "string", + "data": "string", + "paramDel": "string", + "cookie": "string", + "cookieDel": "string", + "loadCookies": "string", + "dropSetCookie": "boolean", + "agent": "string", + "randomAgent": "boolean", + "host": "string", + "referer": "string", + "headers": "string", + "authType": "string", + "authCred": "string", + "authFile": "string", + "ignoreCode": "integer", + "ignoreProxy": "boolean", + "ignoreRedirects": "boolean", + "ignoreTimeouts": "boolean", + "proxy": "string", + "proxyCred": "string", + "proxyFile": "string", + "tor": "boolean", + "torPort": "integer", + "torType": "string", + "checkTor": "boolean", + "delay": "float", + "timeout": "float", + "retries": "integer", + "rParam": "string", + "safeUrl": "string", + "safePost": "string", + "safeReqFile": "string", + "safeFreq": "integer", + "skipUrlEncode": "boolean", + "csrfToken": "string", + "csrfUrl": "string", + "forceSSL": "boolean", + "hpp": "boolean", + "evalCode": "string", + }, - "Injection": { - "testParameter": "string", - "skip": "string", - "skipStatic": "boolean", - "paramExclude": "string", - "dbms": "string", - "dbmsCred": "string", - "os": "string", - "invalidBignum": "boolean", - "invalidLogical": "boolean", - "invalidString": "boolean", - "noCast": "boolean", - "noEscape": "boolean", - "prefix": "string", - "suffix": "string", - "tamper": "string", - }, + "Optimization": { + "optimize": "boolean", + "predictOutput": "boolean", + "keepAlive": "boolean", + "nullConnection": "boolean", + "threads": "integer", + }, - "Detection": { - "level": "integer", - "risk": "integer", - "string": "string", - "notString": "string", - "regexp": "string", - "code": "integer", - "textOnly": "boolean", - "titles": "boolean", - }, + "Injection": { + "testParameter": "string", + "skip": "string", + "skipStatic": "boolean", + "paramExclude": "string", + "dbms": "string", + "dbmsCred": "string", + "os": "string", + "invalidBignum": "boolean", + "invalidLogical": "boolean", + "invalidString": "boolean", + "noCast": "boolean", + "noEscape": "boolean", + "prefix": "string", + "suffix": "string", + "tamper": "string", + }, - "Techniques": { - "tech": "string", - "timeSec": "integer", - "uCols": "string", - "uChar": "string", - "uFrom": "string", - "dnsDomain": "string", - "secondOrder": "string", - }, + "Detection": { + "level": "integer", + "risk": "integer", + "string": "string", + "notString": "string", + "regexp": "string", + "code": "integer", + "textOnly": "boolean", + "titles": "boolean", + }, - "Fingerprint": { - "extensiveFp": "boolean", - }, + "Techniques": { + "tech": "string", + "timeSec": "integer", + "uCols": "string", + "uChar": "string", + "uFrom": "string", + "dnsDomain": "string", + "secondOrder": "string", + }, - "Enumeration": { - "getAll": "boolean", - "getBanner": ("boolean", "Banners"), - "getCurrentUser": ("boolean", "Users"), - "getCurrentDb": ("boolean", "Databases"), - "getHostname": "boolean", - "isDba": "boolean", - "getUsers": ("boolean", "Users"), - "getPasswordHashes": ("boolean", "Passwords"), - "getPrivileges": ("boolean", "Privileges"), - "getRoles": ("boolean", "Roles"), - "getDbs": ("boolean", "Databases"), - "getTables": ("boolean", "Tables"), - "getColumns": ("boolean", "Columns"), - "getSchema": "boolean", - "getCount": "boolean", - "dumpTable": "boolean", - "dumpAll": "boolean", - "search": "boolean", - "getComments": "boolean", - "db": "string", - "tbl": "string", - "col": "string", - "exclude": "string", - "pivotColumn": "string", - "dumpWhere": "string", - "user": "string", - "excludeSysDbs": "boolean", - "limitStart": "integer", - "limitStop": "integer", - "firstChar": "integer", - "lastChar": "integer", - "query": "string", - "sqlShell": "boolean", - "sqlFile": "string", - }, + "Fingerprint": { + "extensiveFp": "boolean", + }, - "Brute": { - "commonTables": "boolean", - "commonColumns": "boolean", - }, + "Enumeration": { + "getAll": "boolean", + "getBanner": ("boolean", "Banners"), + "getCurrentUser": ("boolean", "Users"), + "getCurrentDb": ("boolean", "Databases"), + "getHostname": "boolean", + "isDba": "boolean", + "getUsers": ("boolean", "Users"), + "getPasswordHashes": ("boolean", "Passwords"), + "getPrivileges": ("boolean", "Privileges"), + "getRoles": ("boolean", "Roles"), + "getDbs": ("boolean", "Databases"), + "getTables": ("boolean", "Tables"), + "getColumns": ("boolean", "Columns"), + "getSchema": "boolean", + "getCount": "boolean", + "dumpTable": "boolean", + "dumpAll": "boolean", + "search": "boolean", + "getComments": "boolean", + "db": "string", + "tbl": "string", + "col": "string", + "exclude": "string", + "pivotColumn": "string", + "dumpWhere": "string", + "user": "string", + "excludeSysDbs": "boolean", + "limitStart": "integer", + "limitStop": "integer", + "firstChar": "integer", + "lastChar": "integer", + "query": "string", + "sqlShell": "boolean", + "sqlFile": "string", + }, - "User-defined function": { - "udfInject": "boolean", - "shLib": "string", - }, + "Brute": { + "commonTables": "boolean", + "commonColumns": "boolean", + }, - "File system": { - "rFile": "string", - "wFile": "string", - "dFile": "string", - }, + "User-defined function": { + "udfInject": "boolean", + "shLib": "string", + }, - "Takeover": { - "osCmd": "string", - "osShell": "boolean", - "osPwn": "boolean", - "osSmb": "boolean", - "osBof": "boolean", - "privEsc": "boolean", - "msfPath": "string", - "tmpPath": "string", - }, + "File system": { + "rFile": "string", + "wFile": "string", + "dFile": "string", + }, - "Windows": { - "regRead": "boolean", - "regAdd": "boolean", - "regDel": "boolean", - "regKey": "string", - "regVal": "string", - "regData": "string", - "regType": "string", - }, + "Takeover": { + "osCmd": "string", + "osShell": "boolean", + "osPwn": "boolean", + "osSmb": "boolean", + "osBof": "boolean", + "privEsc": "boolean", + "msfPath": "string", + "tmpPath": "string", + }, - "General": { - #"xmlFile": "string", - "trafficFile": "string", - "batch": "boolean", - "binaryFields": "string", - "charset": "string", - "checkInternet": "boolean", - "crawlDepth": "integer", - "crawlExclude": "string", - "csvDel": "string", - "dumpFormat": "string", - "encoding": "string", - "eta": "boolean", - "flushSession": "boolean", - "forms": "boolean", - "freshQueries": "boolean", - "harFile": "string", - "hexConvert": "boolean", - "outputDir": "string", - "parseErrors": "boolean", - "saveConfig": "string", - "scope": "string", - "testFilter": "string", - "testSkip": "string", - "updateAll": "boolean", - }, + "Windows": { + "regRead": "boolean", + "regAdd": "boolean", + "regDel": "boolean", + "regKey": "string", + "regVal": "string", + "regData": "string", + "regType": "string", + }, - "Miscellaneous": { - "alert": "string", - "answers": "string", - "beep": "boolean", - "cleanup": "boolean", - "dependencies": "boolean", - "disableColoring": "boolean", - "googlePage": "integer", - "identifyWaf": "boolean", - "mobile": "boolean", - "offline": "boolean", - "purgeOutput": "boolean", - "skipWaf": "boolean", - "smart": "boolean", - "tmpDir": "string", - "webRoot": "string", - "wizard": "boolean", - "verbose": "integer", - }, - "Hidden": { - "dummy": "boolean", - "disablePrecon": "boolean", - "profile": "boolean", - "forceDns": "boolean", - "murphyRate": "integer", - "smokeTest": "boolean", - "liveTest": "boolean", - "stopFail": "boolean", - "runCase": "string", - }, - "API": { - "api": "boolean", - "taskid": "string", - "database": "string", - } - } + "General": { + # "xmlFile": "string", + "trafficFile": "string", + "batch": "boolean", + "binaryFields": "string", + "charset": "string", + "checkInternet": "boolean", + "crawlDepth": "integer", + "crawlExclude": "string", + "csvDel": "string", + "dumpFormat": "string", + "encoding": "string", + "eta": "boolean", + "flushSession": "boolean", + "forms": "boolean", + "freshQueries": "boolean", + "harFile": "string", + "hexConvert": "boolean", + "outputDir": "string", + "parseErrors": "boolean", + "saveConfig": "string", + "scope": "string", + "testFilter": "string", + "testSkip": "string", + "updateAll": "boolean", + }, + + "Miscellaneous": { + "alert": "string", + "answers": "string", + "beep": "boolean", + "cleanup": "boolean", + "dependencies": "boolean", + "disableColoring": "boolean", + "googlePage": "integer", + "identifyWaf": "boolean", + "mobile": "boolean", + "offline": "boolean", + "purgeOutput": "boolean", + "skipWaf": "boolean", + "smart": "boolean", + "tmpDir": "string", + "webRoot": "string", + "wizard": "boolean", + "verbose": "integer", + }, + + "Hidden": { + "dummy": "boolean", + "disablePrecon": "boolean", + "profile": "boolean", + "forceDns": "boolean", + "murphyRate": "integer", + "smokeTest": "boolean", + "liveTest": "boolean", + "stopFail": "boolean", + "runCase": "string", + }, + + "API": { + "api": "boolean", + "taskid": "string", + "database": "string", + } +} diff --git a/lib/core/profiling.py b/lib/core/profiling.py index c8ede5a2d..c1bd8acd5 100644 --- a/lib/core/profiling.py +++ b/lib/core/profiling.py @@ -20,9 +20,9 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None): """ try: + __import__("gobject") from thirdparty.gprof2dot import gprof2dot from thirdparty.xdot import xdot - import gobject import gtk import pydot except ImportError, e: diff --git a/lib/core/readlineng.py b/lib/core/readlineng.py index d7e2f3a62..2ff8b70c8 100644 --- a/lib/core/readlineng.py +++ b/lib/core/readlineng.py @@ -14,11 +14,11 @@ _readline = None try: from readline import * import readline as _readline -except ImportError: +except: try: from pyreadline import * import pyreadline as _readline - except ImportError: + except: pass if IS_WIN and _readline: diff --git a/lib/core/settings.py b/lib/core/settings.py index 803276e9f..7d292f43f 100644 --- 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.2.3.4" +VERSION = "1.2.5.2" 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) @@ -27,8 +27,9 @@ DESCRIPTION = "automatic SQL injection and database takeover tool" SITE = "http://sqlmap.org" DEV_EMAIL_ADDRESS = "dev@sqlmap.org" ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new" -GIT_REPOSITORY = "git://github.com/sqlmapproject/sqlmap.git" +GIT_REPOSITORY = "https://github.com/sqlmapproject/sqlmap.git" GIT_PAGE = "https://github.com/sqlmapproject/sqlmap" +ZIPBALL_PAGE = "https://github.com/sqlmapproject/sqlmap/zipball/master" # colorful banner BANNER = """\033[01;33m\ @@ -82,7 +83,7 @@ SELECT_FROM_TABLE_REGEX = r"\bSELECT\b.+?\bFROM\s+(?P([\w.]|`[^`<>]+`)+) TEXT_CONTENT_TYPE_REGEX = r"(?i)(text|form|message|xml|javascript|ecmascript|json)" # Regular expression used for recognition of generic permission messages -PERMISSION_DENIED_REGEX = r"(command|permission|access)\s*(was|is)?\s*denied" +PERMISSION_DENIED_REGEX = r"(?P(command|permission|access)\s*(was|is)?\s*denied)" # Regular expression used in recognition of generic protection mechanisms GENERIC_PROTECTION_REGEX = r"(?i)\b(rejected|blocked|protection|incident|denied|detected|dangerous|firewall)\b" @@ -224,7 +225,7 @@ PYVERSION = sys.version.split()[0] MSSQL_SYSTEM_DBS = ("Northwind", "master", "model", "msdb", "pubs", "tempdb") MYSQL_SYSTEM_DBS = ("information_schema", "mysql", "performance_schema") PGSQL_SYSTEM_DBS = ("information_schema", "pg_catalog", "pg_toast", "pgagent") -ORACLE_SYSTEM_DBS = ("ANONYMOUS", "APEX_PUBLIC_USER", "CTXSYS", "DBSNMP", "DIP", "EXFSYS", "FLOWS_%", "FLOWS_FILES", "LBACSYS", "MDDATA", "MDSYS", "MGMT_VIEW", "OLAPSYS", "ORACLE_OCM", "ORDDATA", "ORDPLUGINS", "ORDSYS", "OUTLN", "OWBSYS", "SI_INFORMTN_SCHEMA", "SPATIAL_CSW_ADMIN_USR", "SPATIAL_WFS_ADMIN_USR", "SYS", "SYSMAN", "SYSTEM", "WKPROXY", "WKSYS", "WK_TEST", "WMSYS", "XDB", "XS$NULL") # Reference: https://blog.vishalgupta.com/2011/06/19/predefined-oracle-system-schemas/ +ORACLE_SYSTEM_DBS = ('ANONYMOUS', 'APEX_030200', 'APEX_PUBLIC_USER', 'APPQOSSYS', 'BI', 'CTXSYS', 'DBSNMP', 'DIP', 'EXFSYS', 'FLOWS_%', 'FLOWS_FILES', 'HR', 'IX', 'LBACSYS', 'MDDATA', 'MDSYS', 'MGMT_VIEW', 'OC', 'OE', 'OLAPSYS', 'ORACLE_OCM', 'ORDDATA', 'ORDPLUGINS', 'ORDSYS', 'OUTLN', 'OWBSYS', 'PM', 'SCOTT', 'SH', 'SI_INFORMTN_SCHEMA', 'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR', 'SYS', 'SYSMAN', 'SYSTEM', 'WKPROXY', 'WKSYS', 'WK_TEST', 'WMSYS', 'XDB', 'XS$NULL') SQLITE_SYSTEM_DBS = ("sqlite_master", "sqlite_temp_master") ACCESS_SYSTEM_DBS = ("MSysAccessObjects", "MSysACEs", "MSysObjects", "MSysQueries", "MSysRelationships", "MSysAccessStorage", "MSysAccessXML", "MSysModules", "MSysModules2") FIREBIRD_SYSTEM_DBS = ("RDB$BACKUP_HISTORY", "RDB$CHARACTER_SETS", "RDB$CHECK_CONSTRAINTS", "RDB$COLLATIONS", "RDB$DATABASE", "RDB$DEPENDENCIES", "RDB$EXCEPTIONS", "RDB$FIELDS", "RDB$FIELD_DIMENSIONS", " RDB$FILES", "RDB$FILTERS", "RDB$FORMATS", "RDB$FUNCTIONS", "RDB$FUNCTION_ARGUMENTS", "RDB$GENERATORS", "RDB$INDEX_SEGMENTS", "RDB$INDICES", "RDB$LOG_FILES", "RDB$PAGES", "RDB$PROCEDURES", "RDB$PROCEDURE_PARAMETERS", "RDB$REF_CONSTRAINTS", "RDB$RELATIONS", "RDB$RELATION_CONSTRAINTS", "RDB$RELATION_FIELDS", "RDB$ROLES", "RDB$SECURITY_CLASSES", "RDB$TRANSACTIONS", "RDB$TRIGGERS", "RDB$TRIGGER_MESSAGES", "RDB$TYPES", "RDB$USER_PRIVILEGES", "RDB$VIEW_RELATIONS") @@ -321,7 +322,7 @@ FILE_PATH_REGEXES = (r"(?P[^<>]+?) on line \d+", r"in (?P # Regular expressions used for parsing error messages (--parse-errors) ERROR_PARSING_REGEXES = ( r"[^<]*(fatal|error|warning|exception)[^<]*:?\s*(?P.+?)", - r"(?m)^(fatal|error|warning|exception):?\s*(?P[^\n]+?)$", + r"(?m)^\s*(fatal|error|warning|exception):?\s*(?P[^\n]+?)$", r"(?P[^\n>]*SQL Syntax[^\n<]+)", r"
  • Error Type:
    (?P.+?)
  • ", r"CDbCommand (?P[^<>\n]*SQL[^<>\n]+)", @@ -639,7 +640,7 @@ NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH = 6 MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024 # Maximum response total page size (trimmed if larger) -MAX_CONNECTION_TOTAL_SIZE = 50 * 1024 * 1024 +MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024 # For preventing MemoryError exceptions (caused when using large sequences in difflib.SequenceMatcher) MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024 diff --git a/lib/core/shell.py b/lib/core/shell.py index b6c200755..3920d68f9 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -104,20 +104,20 @@ def autoCompletion(completion=None, os=None, commands=None): if os == OS.WINDOWS: # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands completer = CompleterNG({ - "copy": None, "del": None, "dir": None, - "echo": None, "md": None, "mem": None, - "move": None, "net": None, "netstat -na": None, - "ver": None, "xcopy": None, "whoami": None, - }) + "copy": None, "del": None, "dir": None, + "echo": None, "md": None, "mem": None, + "move": None, "net": None, "netstat -na": None, + "ver": None, "xcopy": None, "whoami": None, + }) else: # Reference: http://en.wikipedia.org/wiki/List_of_Unix_commands completer = CompleterNG({ - "cp": None, "rm": None, "ls": None, - "echo": None, "mkdir": None, "free": None, - "mv": None, "ifconfig": None, "netstat -natu": None, - "pwd": None, "uname": None, "id": None, - }) + "cp": None, "rm": None, "ls": None, + "echo": None, "mkdir": None, "free": None, + "mv": None, "ifconfig": None, "netstat -natu": None, + "pwd": None, "uname": None, "id": None, + }) readline.set_completer(completer.complete) readline.parse_and_bind("tab: complete") diff --git a/lib/core/subprocessng.py b/lib/core/subprocessng.py index e82f172cd..b51a64bba 100644 --- a/lib/core/subprocessng.py +++ b/lib/core/subprocessng.py @@ -8,7 +8,6 @@ See the file 'LICENSE' for copying permission import errno import os import subprocess -import sys import time from lib.core.settings import IS_WIN @@ -24,11 +23,6 @@ else: import select import fcntl - if (sys.hexversion >> 16) >= 0x202: - FCNTL = fcntl - else: - import FCNTL - def blockingReadFromFD(fd): # Quick twist around original Twisted function # Blocking read from a non-blocking file descriptor diff --git a/lib/core/target.py b/lib/core/target.py index 146f3de47..abddc9428 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -142,7 +142,7 @@ def _setRequestParams(): if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) - conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*"[^"]*)"', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data) + conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*".+?)"(?%s"' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*)(-?\d[\d\.]*)\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) match = re.search(r'(?P[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data) @@ -230,9 +230,9 @@ def _setRequestParams(): if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found conf.parameters[PLACE.POST] = conf.data - kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in conf.data) else kb.processUserMarks + kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in (conf.data or "")) else kb.processUserMarks - if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and not kb.customInjectionMark in (conf.data or "") and conf.url.startswith("http"): + if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and kb.customInjectionMark not in (conf.data or "") and conf.url.startswith("http"): warnMsg = "you've provided target URL without any GET " warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') " warnMsg += "and without providing any POST parameters " @@ -377,7 +377,7 @@ def _setRequestParams(): if condition: conf.parameters[PLACE.CUSTOM_HEADER] = str(conf.httpHeaders) conf.paramDict[PLACE.CUSTOM_HEADER] = {httpHeader: "%s,%s%s" % (httpHeader, headerValue, kb.customInjectionMark)} - conf.httpHeaders = [(header, value.replace(kb.customInjectionMark, "")) for header, value in conf.httpHeaders] + conf.httpHeaders = [(_[0], _[1].replace(kb.customInjectionMark, "")) for _ in conf.httpHeaders] testableParameters = True if not conf.parameters: @@ -391,7 +391,7 @@ def _setRequestParams(): raise SqlmapGenericException(errMsg) if conf.csrfToken: - if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(conf.csrfToken), conf.data or "") and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders) and not conf.csrfToken in conf.paramDict.get(PLACE.COOKIE, {}): + if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % re.escape(conf.csrfToken), conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}): errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken errMsg += "found in provided GET, POST, Cookie or header values" raise SqlmapGenericException(errMsg) @@ -449,13 +449,10 @@ def _resumeHashDBValues(): conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH) for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []: - if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and \ - injection.parameter in conf.paramDict[injection.place]: - + if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]: if not conf.tech or intersect(conf.tech, injection.data.keys()): if intersect(conf.tech, injection.data.keys()): injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.tech) - if injection not in kb.injections: kb.injections.append(injection) @@ -581,7 +578,7 @@ def _createFilesDir(): if not os.path.isdir(conf.filePath): try: - os.makedirs(conf.filePath, 0755) + os.makedirs(conf.filePath) except OSError, ex: tempDir = tempfile.mkdtemp(prefix="sqlmapfiles") warnMsg = "unable to create files directory " @@ -603,7 +600,7 @@ def _createDumpDir(): if not os.path.isdir(conf.dumpPath): try: - os.makedirs(conf.dumpPath, 0755) + os.makedirs(conf.dumpPath) except OSError, ex: tempDir = tempfile.mkdtemp(prefix="sqlmapdump") warnMsg = "unable to create dump directory " @@ -624,7 +621,7 @@ def _createTargetDirs(): try: if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH): - os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755) + os.makedirs(paths.SQLMAP_OUTPUT_PATH) _ = os.path.join(paths.SQLMAP_OUTPUT_PATH, randomStr()) open(_, "w+b").close() @@ -654,7 +651,7 @@ def _createTargetDirs(): try: if not os.path.isdir(conf.outputPath): - os.makedirs(conf.outputPath, 0755) + os.makedirs(conf.outputPath) except (OSError, IOError, TypeError), ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") diff --git a/lib/core/update.py b/lib/core/update.py index a41159400..af939aa6c 100644 --- a/lib/core/update.py +++ b/lib/core/update.py @@ -5,21 +5,27 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ +import glob import os import re +import shutil import subprocess import sys import time +import urllib +import zipfile from lib.core.common import dataToStdout from lib.core.common import getSafeExString from lib.core.common import pollProcess +from lib.core.common import readInput from lib.core.data import conf from lib.core.data import logger from lib.core.data import paths from lib.core.revision import getRevisionNumber from lib.core.settings import GIT_REPOSITORY from lib.core.settings import IS_WIN +from lib.core.settings import ZIPBALL_PAGE from lib.core.settings import UNICODE_ENCODING def update(): @@ -29,9 +35,54 @@ def update(): success = False if not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")): - errMsg = "not a git repository. Please checkout the 'sqlmapproject/sqlmap' repository " - errMsg += "from GitHub (e.g. 'git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap')" - logger.error(errMsg) + warnMsg = "not a git repository. It is recommended to clone the 'sqlmapproject/sqlmap' repository " + warnMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY + logger.warn(warnMsg) + + message = "do you want to try to fetch the latest 'zipball' from repository and extract it (experimental) ? [y/N]" + if readInput(message, default='N', boolean=True): + directory = os.path.abspath(paths.SQLMAP_ROOT_PATH) + + try: + open(os.path.join(directory, "sqlmap.py"), "w+b") + except Exception, ex: + errMsg = "unable to update content of directory '%s' ('%s')" % (directory, getSafeExString(ex)) + logger.error(errMsg) + else: + for wildcard in ('*', ".*"): + for _ in glob.glob(os.path.join(directory, wildcard)): + try: + if os.path.isdir(_): + shutil.rmtree(_) + else: + os.remove(_) + except: + pass + + if glob.glob(os.path.join(directory, '*')): + errMsg = "unable to clear the content of directory '%s'" % directory + logger.error(errMsg) + else: + try: + archive = urllib.urlretrieve(ZIPBALL_PAGE)[0] + + with zipfile.ZipFile(archive) as f: + for info in f.infolist(): + info.filename = re.sub(r"\Asqlmap[^/]+", "", info.filename) + if info.filename: + f.extract(info, directory) + + filepath = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "core", "settings.py") + if os.path.isfile(filepath): + with open(filepath, "rb") as f: + version = re.search(r"(?m)^VERSION\s*=\s*['\"]([^'\"]+)", f.read()).group(1) + logger.info("updated to the latest version '%s#dev'" % version) + success = True + except Exception, ex: + logger.error("update could not be completed ('%s')" % getSafeExString(ex)) + else: + if not success: + logger.error("update could not be completed") else: infoMsg = "updating sqlmap to the latest development revision from the " infoMsg += "GitHub repository" @@ -56,7 +107,7 @@ def update(): else: if "Not a git repository" in stderr: errMsg = "not a valid git repository. Please checkout the 'sqlmapproject/sqlmap' repository " - errMsg += "from GitHub (e.g. 'git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap')" + errMsg += "from GitHub (e.g. 'git clone --depth 1 %s sqlmap')" % GIT_REPOSITORY logger.error(errMsg) else: logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", stderr).strip()) @@ -69,7 +120,7 @@ def update(): infoMsg += "download the latest snapshot from " infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads" else: - infoMsg = "for Linux platform it's required " + infoMsg = "for Linux platform it's recommended " infoMsg += "to install a standard 'git' package (e.g.: 'sudo apt-get install git')" logger.info(infoMsg) diff --git a/lib/core/wordlist.py b/lib/core/wordlist.py index 90d26d483..77c779a27 100644 --- a/lib/core/wordlist.py +++ b/lib/core/wordlist.py @@ -47,7 +47,7 @@ class Wordlist(object): errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" - raise SqlmapInstallationException, errMsg + raise SqlmapInstallationException(errMsg) if len(_.namelist()) == 0: errMsg = "no file(s) inside '%s'" % self.current raise SqlmapDataException(errMsg) @@ -73,7 +73,7 @@ class Wordlist(object): errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" - raise SqlmapInstallationException, errMsg + raise SqlmapInstallationException(errMsg) except StopIteration: self.adjust() retVal = self.iter.next().rstrip() diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 83161b686..2631a7b04 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -50,9 +50,7 @@ def cmdLineParser(argv=None): # Reference: https://stackoverflow.com/a/4012683 (Note: previously used "...sys.getfilesystemencoding() or UNICODE_ENCODING") _ = getUnicode(os.path.basename(argv[0]), encoding=sys.stdin.encoding) - usage = "%s%s [options]" % ("python " if not IS_WIN else "", \ - "\"%s\"" % _ if " " in _ else _) - + usage = "%s%s [options]" % ("python " if not IS_WIN else "", "\"%s\"" % _ if " " in _ else _) parser = OptionParser(usage=usage) try: @@ -115,15 +113,13 @@ def cmdLineParser(argv=None): request.add_option("--load-cookies", dest="loadCookies", help="File containing cookies in Netscape/wget format") - request.add_option("--drop-set-cookie", dest="dropSetCookie", - action="store_true", + request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true", help="Ignore Set-Cookie header from response") request.add_option("--user-agent", dest="agent", help="HTTP User-Agent header value") - request.add_option("--random-agent", dest="randomAgent", - action="store_true", + request.add_option("--random-agent", dest="randomAgent", action="store_true", help="Use randomly selected HTTP User-Agent header value") request.add_option("--host", dest="host", @@ -139,62 +135,55 @@ def cmdLineParser(argv=None): help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")") request.add_option("--auth-type", dest="authType", - help="HTTP authentication type " - "(Basic, Digest, NTLM or PKI)") + help="HTTP authentication type (Basic, Digest, NTLM or PKI)") request.add_option("--auth-cred", dest="authCred", - help="HTTP authentication credentials " - "(name:password)") + help="HTTP authentication credentials (name:password)") request.add_option("--auth-file", dest="authFile", help="HTTP authentication PEM cert/private key file") request.add_option("--ignore-code", dest="ignoreCode", type="int", - help="Ignore HTTP error code (e.g. 401)") + help="Ignore HTTP error code (e.g. 401)") request.add_option("--ignore-proxy", dest="ignoreProxy", action="store_true", help="Ignore system default proxy settings") request.add_option("--ignore-redirects", dest="ignoreRedirects", action="store_true", - help="Ignore redirection attempts") + help="Ignore redirection attempts") request.add_option("--ignore-timeouts", dest="ignoreTimeouts", action="store_true", - help="Ignore connection timeouts") + help="Ignore connection timeouts") request.add_option("--proxy", dest="proxy", help="Use a proxy to connect to the target URL") request.add_option("--proxy-cred", dest="proxyCred", - help="Proxy authentication credentials " - "(name:password)") + help="Proxy authentication credentials (name:password)") request.add_option("--proxy-file", dest="proxyFile", help="Load proxy list from a file") - request.add_option("--tor", dest="tor", - action="store_true", - help="Use Tor anonymity network") + request.add_option("--tor", dest="tor", action="store_true", + help="Use Tor anonymity network") request.add_option("--tor-port", dest="torPort", - help="Set Tor proxy port other than default") + help="Set Tor proxy port other than default") request.add_option("--tor-type", dest="torType", - help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))") + help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))") - request.add_option("--check-tor", dest="checkTor", - action="store_true", - help="Check to see if Tor is used properly") + request.add_option("--check-tor", dest="checkTor", action="store_true", + help="Check to see if Tor is used properly") request.add_option("--delay", dest="delay", type="float", help="Delay in seconds between each HTTP request") request.add_option("--timeout", dest="timeout", type="float", - help="Seconds to wait before timeout connection " - "(default %d)" % defaults.timeout) + help="Seconds to wait before timeout connection (default %d)" % defaults.timeout) request.add_option("--retries", dest="retries", type="int", - help="Retries when the connection timeouts " - "(default %d)" % defaults.retries) + help="Retries when the connection timeouts (default %d)" % defaults.retries) request.add_option("--randomize", dest="rParam", help="Randomly change value for given parameter(s)") @@ -211,8 +200,7 @@ def cmdLineParser(argv=None): request.add_option("--safe-freq", dest="safeFreq", type="int", help="Test requests between two visits to a given safe URL") - request.add_option("--skip-urlencode", dest="skipUrlEncode", - action="store_true", + request.add_option("--skip-urlencode", dest="skipUrlEncode", action="store_true", help="Skip URL encoding of payload data") request.add_option("--csrf-token", dest="csrfToken", @@ -221,44 +209,36 @@ def cmdLineParser(argv=None): request.add_option("--csrf-url", dest="csrfUrl", help="URL address to visit to extract anti-CSRF token") - request.add_option("--force-ssl", dest="forceSSL", - action="store_true", + request.add_option("--force-ssl", dest="forceSSL", action="store_true", help="Force usage of SSL/HTTPS") - request.add_option("--hpp", dest="hpp", - action="store_true", - help="Use HTTP parameter pollution method") + request.add_option("--hpp", dest="hpp", action="store_true", + help="Use HTTP parameter pollution method") request.add_option("--eval", dest="evalCode", help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")") # Optimization options - optimization = OptionGroup(parser, "Optimization", "These " - "options can be used to optimize the " - "performance of sqlmap") + optimization = OptionGroup(parser, "Optimization", "These options can be used to optimize the performance of sqlmap") - optimization.add_option("-o", dest="optimize", - action="store_true", - help="Turn on all optimization switches") + optimization.add_option("-o", dest="optimize", action="store_true", + help="Turn on all optimization switches") optimization.add_option("--predict-output", dest="predictOutput", action="store_true", - help="Predict common queries output") + help="Predict common queries output") optimization.add_option("--keep-alive", dest="keepAlive", action="store_true", - help="Use persistent HTTP(s) connections") + help="Use persistent HTTP(s) connections") optimization.add_option("--null-connection", dest="nullConnection", action="store_true", - help="Retrieve page length without actual HTTP response body") + help="Retrieve page length without actual HTTP response body") optimization.add_option("--threads", dest="threads", type="int", - help="Max number of concurrent HTTP(s) " + help="Max number of concurrent HTTP(s) " "requests (default %d)" % defaults.threads) # Injection options - injection = OptionGroup(parser, "Injection", "These options can be " - "used to specify which parameters to test " - "for, provide custom injection payloads and " - "optional tampering scripts") + injection = OptionGroup(parser, "Injection", "These options can be used to specify which parameters to test for, provide custom injection payloads and optional tampering scripts") injection.add_option("-p", dest="testParameter", help="Testable parameter(s)") @@ -270,36 +250,30 @@ def cmdLineParser(argv=None): help="Skip testing parameters that not appear to be dynamic") injection.add_option("--param-exclude", dest="paramExclude", - help="Regexp to exclude parameters from testing (e.g. \"ses\")") + help="Regexp to exclude parameters from testing (e.g. \"ses\")") injection.add_option("--dbms", dest="dbms", help="Force back-end DBMS to this value") injection.add_option("--dbms-cred", dest="dbmsCred", - help="DBMS authentication credentials (user:password)") + help="DBMS authentication credentials (user:password)") injection.add_option("--os", dest="os", - help="Force back-end DBMS operating system " - "to this value") + help="Force back-end DBMS operating system to this value") - injection.add_option("--invalid-bignum", dest="invalidBignum", - action="store_true", + injection.add_option("--invalid-bignum", dest="invalidBignum", action="store_true", help="Use big numbers for invalidating values") - injection.add_option("--invalid-logical", dest="invalidLogical", - action="store_true", + injection.add_option("--invalid-logical", dest="invalidLogical", action="store_true", help="Use logical operations for invalidating values") - injection.add_option("--invalid-string", dest="invalidString", - action="store_true", + injection.add_option("--invalid-string", dest="invalidString", action="store_true", help="Use random strings for invalidating values") - injection.add_option("--no-cast", dest="noCast", - action="store_true", + injection.add_option("--no-cast", dest="noCast", action="store_true", help="Turn off payload casting mechanism") - injection.add_option("--no-escape", dest="noEscape", - action="store_true", + injection.add_option("--no-escape", dest="noEscape", action="store_true", help="Turn off string escaping mechanism") injection.add_option("--prefix", dest="prefix", @@ -312,54 +286,40 @@ def cmdLineParser(argv=None): help="Use given script(s) for tampering injection data") # Detection options - detection = OptionGroup(parser, "Detection", "These options can be " - "used to customize the detection phase") + detection = OptionGroup(parser, "Detection", "These options can be used to customize the detection phase") detection.add_option("--level", dest="level", type="int", - help="Level of tests to perform (1-5, " - "default %d)" % defaults.level) + help="Level of tests to perform (1-5, default %d)" % defaults.level) detection.add_option("--risk", dest="risk", type="int", - help="Risk of tests to perform (1-3, " - "default %d)" % defaults.risk) + help="Risk of tests to perform (1-3, default %d)" % defaults.risk) detection.add_option("--string", dest="string", - help="String to match when " - "query is evaluated to True") + help="String to match when query is evaluated to True") detection.add_option("--not-string", dest="notString", - help="String to match when " - "query is evaluated to False") + help="String to match when query is evaluated to False") detection.add_option("--regexp", dest="regexp", - help="Regexp to match when " - "query is evaluated to True") + help="Regexp to match when query is evaluated to True") detection.add_option("--code", dest="code", type="int", - help="HTTP code to match when " - "query is evaluated to True") + help="HTTP code to match when query is evaluated to True") - detection.add_option("--text-only", dest="textOnly", - action="store_true", + detection.add_option("--text-only", dest="textOnly", action="store_true", help="Compare pages based only on the textual content") - detection.add_option("--titles", dest="titles", - action="store_true", + detection.add_option("--titles", dest="titles", action="store_true", help="Compare pages based only on their titles") # Techniques options - techniques = OptionGroup(parser, "Techniques", "These options can be " - "used to tweak testing of specific SQL " - "injection techniques") + techniques = OptionGroup(parser, "Techniques", "These options can be used to tweak testing of specific SQL injection techniques") techniques.add_option("--technique", dest="tech", - help="SQL injection techniques to use " - "(default \"%s\")" % defaults.tech) + help="SQL injection techniques to use (default \"%s\")" % defaults.tech) - techniques.add_option("--time-sec", dest="timeSec", - type="int", - help="Seconds to delay the DBMS response " - "(default %d)" % defaults.timeSec) + techniques.add_option("--time-sec", dest="timeSec", type="int", + help="Seconds to delay the DBMS response (default %d)" % defaults.timeSec) techniques.add_option("--union-cols", dest="uCols", help="Range of columns to test for UNION query SQL injection") @@ -374,58 +334,45 @@ def cmdLineParser(argv=None): help="Domain name used for DNS exfiltration attack") techniques.add_option("--second-order", dest="secondOrder", - help="Resulting page URL searched for second-order " - "response") + help="Resulting page URL searched for second-order response") # Fingerprint options fingerprint = OptionGroup(parser, "Fingerprint") - fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", - action="store_true", + fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", action="store_true", help="Perform an extensive DBMS version fingerprint") # Enumeration options - enumeration = OptionGroup(parser, "Enumeration", "These options can " - "be used to enumerate the back-end database " - "management system information, structure " - "and data contained in the tables. Moreover " - "you can run your own SQL statements") + enumeration = OptionGroup(parser, "Enumeration", "These options can be used to enumerate the back-end database management system information, structure and data contained in the tables. Moreover you can run your own SQL statements") - enumeration.add_option("-a", "--all", dest="getAll", - action="store_true", help="Retrieve everything") + enumeration.add_option("-a", "--all", dest="getAll", action="store_true", + help="Retrieve everything") - enumeration.add_option("-b", "--banner", dest="getBanner", - action="store_true", help="Retrieve DBMS banner") + enumeration.add_option("-b", "--banner", dest="getBanner", action="store_true", + help="Retrieve DBMS banner") - enumeration.add_option("--current-user", dest="getCurrentUser", - action="store_true", + enumeration.add_option("--current-user", dest="getCurrentUser", action="store_true", help="Retrieve DBMS current user") - enumeration.add_option("--current-db", dest="getCurrentDb", - action="store_true", + enumeration.add_option("--current-db", dest="getCurrentDb", action="store_true", help="Retrieve DBMS current database") - enumeration.add_option("--hostname", dest="getHostname", - action="store_true", + enumeration.add_option("--hostname", dest="getHostname", action="store_true", help="Retrieve DBMS server hostname") - enumeration.add_option("--is-dba", dest="isDba", - action="store_true", + enumeration.add_option("--is-dba", dest="isDba", action="store_true", help="Detect if the DBMS current user is DBA") enumeration.add_option("--users", dest="getUsers", action="store_true", help="Enumerate DBMS users") - enumeration.add_option("--passwords", dest="getPasswordHashes", - action="store_true", + enumeration.add_option("--passwords", dest="getPasswordHashes", action="store_true", help="Enumerate DBMS users password hashes") - enumeration.add_option("--privileges", dest="getPrivileges", - action="store_true", + enumeration.add_option("--privileges", dest="getPrivileges", action="store_true", help="Enumerate DBMS users privileges") - enumeration.add_option("--roles", dest="getRoles", - action="store_true", + enumeration.add_option("--roles", dest="getRoles", action="store_true", help="Enumerate DBMS users roles") enumeration.add_option("--dbs", dest="getDbs", action="store_true", @@ -470,10 +417,8 @@ def cmdLineParser(argv=None): enumeration.add_option("-U", dest="user", help="DBMS user to enumerate") - enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs", - action="store_true", - help="Exclude DBMS system databases when " - "enumerating tables") + enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs", action="store_true", + help="Exclude DBMS system databases when enumerating tables") enumeration.add_option("--pivot-column", dest="pivotColumn", help="Pivot column name") @@ -496,28 +441,23 @@ def cmdLineParser(argv=None): enumeration.add_option("--sql-query", dest="query", help="SQL statement to be executed") - enumeration.add_option("--sql-shell", dest="sqlShell", - action="store_true", + enumeration.add_option("--sql-shell", dest="sqlShell", action="store_true", help="Prompt for an interactive SQL shell") enumeration.add_option("--sql-file", dest="sqlFile", help="Execute SQL statements from given file(s)") # Brute force options - brute = OptionGroup(parser, "Brute force", "These " - "options can be used to run brute force " - "checks") + brute = OptionGroup(parser, "Brute force", "These options can be used to run brute force checks") brute.add_option("--common-tables", dest="commonTables", action="store_true", - help="Check existence of common tables") + help="Check existence of common tables") brute.add_option("--common-columns", dest="commonColumns", action="store_true", - help="Check existence of common columns") + help="Check existence of common columns") # User-defined function options - udf = OptionGroup(parser, "User-defined function injection", "These " - "options can be used to create custom user-defined " - "functions") + udf = OptionGroup(parser, "User-defined function injection", "These options can be used to create custom user-defined functions") udf.add_option("--udf-inject", dest="udfInject", action="store_true", help="Inject custom user-defined functions") @@ -526,167 +466,131 @@ def cmdLineParser(argv=None): help="Local path of the shared library") # File system options - filesystem = OptionGroup(parser, "File system access", "These options " - "can be used to access the back-end database " - "management system underlying file system") + filesystem = OptionGroup(parser, "File system access", "These options can be used to access the back-end database management system underlying file system") filesystem.add_option("--file-read", dest="rFile", - help="Read a file from the back-end DBMS " - "file system") + help="Read a file from the back-end DBMS file system") filesystem.add_option("--file-write", dest="wFile", - help="Write a local file on the back-end " - "DBMS file system") + help="Write a local file on the back-end DBMS file system") filesystem.add_option("--file-dest", dest="dFile", - help="Back-end DBMS absolute filepath to " - "write to") + help="Back-end DBMS absolute filepath to write to") # Takeover options - takeover = OptionGroup(parser, "Operating system access", "These " - "options can be used to access the back-end " - "database management system underlying " - "operating system") + takeover = OptionGroup(parser, "Operating system access", "These options can be used to access the back-end database management system underlying operating system") takeover.add_option("--os-cmd", dest="osCmd", help="Execute an operating system command") - takeover.add_option("--os-shell", dest="osShell", - action="store_true", - help="Prompt for an interactive operating " - "system shell") + takeover.add_option("--os-shell", dest="osShell", action="store_true", + help="Prompt for an interactive operating system shell") - takeover.add_option("--os-pwn", dest="osPwn", - action="store_true", - help="Prompt for an OOB shell, " - "Meterpreter or VNC") + takeover.add_option("--os-pwn", dest="osPwn", action="store_true", + help="Prompt for an OOB shell, Meterpreter or VNC") - takeover.add_option("--os-smbrelay", dest="osSmb", - action="store_true", - help="One click prompt for an OOB shell, " - "Meterpreter or VNC") + takeover.add_option("--os-smbrelay", dest="osSmb", action="store_true", + help="One click prompt for an OOB shell, Meterpreter or VNC") - takeover.add_option("--os-bof", dest="osBof", - action="store_true", + takeover.add_option("--os-bof", dest="osBof", action="store_true", help="Stored procedure buffer overflow " "exploitation") - takeover.add_option("--priv-esc", dest="privEsc", - action="store_true", + takeover.add_option("--priv-esc", dest="privEsc", action="store_true", help="Database process user privilege escalation") takeover.add_option("--msf-path", dest="msfPath", - help="Local path where Metasploit Framework " - "is installed") + help="Local path where Metasploit Framework is installed") takeover.add_option("--tmp-path", dest="tmpPath", - help="Remote absolute path of temporary files " - "directory") + help="Remote absolute path of temporary files directory") # Windows registry options - windows = OptionGroup(parser, "Windows registry access", "These " - "options can be used to access the back-end " - "database management system Windows " - "registry") + windows = OptionGroup(parser, "Windows registry access", "These options can be used to access the back-end database management system Windows registry") - windows.add_option("--reg-read", dest="regRead", - action="store_true", - help="Read a Windows registry key value") + windows.add_option("--reg-read", dest="regRead", action="store_true", + help="Read a Windows registry key value") - windows.add_option("--reg-add", dest="regAdd", - action="store_true", - help="Write a Windows registry key value data") + windows.add_option("--reg-add", dest="regAdd", action="store_true", + help="Write a Windows registry key value data") - windows.add_option("--reg-del", dest="regDel", - action="store_true", - help="Delete a Windows registry key value") + windows.add_option("--reg-del", dest="regDel", action="store_true", + help="Delete a Windows registry key value") windows.add_option("--reg-key", dest="regKey", - help="Windows registry key") + help="Windows registry key") windows.add_option("--reg-value", dest="regVal", - help="Windows registry key value") + help="Windows registry key value") windows.add_option("--reg-data", dest="regData", - help="Windows registry key value data") + help="Windows registry key value data") windows.add_option("--reg-type", dest="regType", - help="Windows registry key value type") + help="Windows registry key value type") # General options - general = OptionGroup(parser, "General", "These options can be used " - "to set some general working parameters") + general = OptionGroup(parser, "General", "These options can be used to set some general working parameters") general.add_option("-s", dest="sessionFile", - help="Load session from a stored (.sqlite) file") + help="Load session from a stored (.sqlite) file") general.add_option("-t", dest="trafficFile", - help="Log all HTTP traffic into a " - "textual file") + help="Log all HTTP traffic into a textual file") - general.add_option("--batch", dest="batch", - action="store_true", - help="Never ask for user input, use the default behavior") + general.add_option("--batch", dest="batch", action="store_true", + help="Never ask for user input, use the default behavior") general.add_option("--binary-fields", dest="binaryFields", - help="Result fields having binary values (e.g. \"digest\")") + help="Result fields having binary values (e.g. \"digest\")") - general.add_option("--check-internet", dest="checkInternet", - action="store_true", - help="Check Internet connection before assessing the target") + general.add_option("--check-internet", dest="checkInternet", action="store_true", + help="Check Internet connection before assessing the target") general.add_option("--crawl", dest="crawlDepth", type="int", - help="Crawl the website starting from the target URL") + help="Crawl the website starting from the target URL") general.add_option("--crawl-exclude", dest="crawlExclude", help="Regexp to exclude pages from crawling (e.g. \"logout\")") general.add_option("--csv-del", dest="csvDel", - help="Delimiting character used in CSV output " - "(default \"%s\")" % defaults.csvDel) + help="Delimiting character used in CSV output (default \"%s\")" % defaults.csvDel) general.add_option("--charset", dest="charset", help="Blind SQL injection charset (e.g. \"0123456789abcdef\")") general.add_option("--dump-format", dest="dumpFormat", - help="Format of dumped data (CSV (default), HTML or SQLITE)") + help="Format of dumped data (CSV (default), HTML or SQLITE)") general.add_option("--encoding", dest="encoding", - help="Character encoding used for data retrieval (e.g. GBK)") + help="Character encoding used for data retrieval (e.g. GBK)") - general.add_option("--eta", dest="eta", - action="store_true", - help="Display for each output the estimated time of arrival") + general.add_option("--eta", dest="eta", action="store_true", + help="Display for each output the estimated time of arrival") - general.add_option("--flush-session", dest="flushSession", - action="store_true", - help="Flush session files for current target") + general.add_option("--flush-session", dest="flushSession", action="store_true", + help="Flush session files for current target") - general.add_option("--forms", dest="forms", - action="store_true", - help="Parse and test forms on target URL") + general.add_option("--forms", dest="forms", action="store_true", + help="Parse and test forms on target URL") - general.add_option("--fresh-queries", dest="freshQueries", - action="store_true", - help="Ignore query results stored in session file") + general.add_option("--fresh-queries", dest="freshQueries", action="store_true", + help="Ignore query results stored in session file") general.add_option("--har", dest="harFile", help="Log all HTTP traffic into a HAR file") - general.add_option("--hex", dest="hexConvert", - action="store_true", - help="Use DBMS hex function(s) for data retrieval") + general.add_option("--hex", dest="hexConvert", action="store_true", + help="Use DBMS hex function(s) for data retrieval") - general.add_option("--output-dir", dest="outputDir", - action="store", - help="Custom output directory path") + general.add_option("--output-dir", dest="outputDir", action="store", + help="Custom output directory path") - general.add_option("--parse-errors", dest="parseErrors", - action="store_true", - help="Parse and display DBMS error messages from responses") + general.add_option("--parse-errors", dest="parseErrors", action="store_true", + help="Parse and display DBMS error messages from responses") general.add_option("--save", dest="saveConfig", - help="Save options to a configuration INI file") + help="Save options to a configuration INI file") general.add_option("--scope", dest="scope", help="Regexp to filter targets from provided proxy log") @@ -697,77 +601,65 @@ def cmdLineParser(argv=None): general.add_option("--test-skip", dest="testSkip", help="Skip tests by payloads and/or titles (e.g. BENCHMARK)") - general.add_option("--update", dest="updateAll", - action="store_true", - help="Update sqlmap") + general.add_option("--update", dest="updateAll", action="store_true", + help="Update sqlmap") # Miscellaneous options miscellaneous = OptionGroup(parser, "Miscellaneous") miscellaneous.add_option("-z", dest="mnemonics", - help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")") + help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")") miscellaneous.add_option("--alert", dest="alert", - help="Run host OS command(s) when SQL injection is found") + help="Run host OS command(s) when SQL injection is found") miscellaneous.add_option("--answers", dest="answers", - help="Set question answers (e.g. \"quit=N,follow=N\")") + help="Set question answers (e.g. \"quit=N,follow=N\")") miscellaneous.add_option("--beep", dest="beep", action="store_true", - help="Beep on question and/or 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", - help="Clean up the DBMS from sqlmap specific " - "UDF and tables") + miscellaneous.add_option("--cleanup", dest="cleanup", action="store_true", + help="Clean up the DBMS from sqlmap specific UDF and tables") - miscellaneous.add_option("--dependencies", dest="dependencies", - action="store_true", - help="Check for missing (non-core) sqlmap dependencies") + miscellaneous.add_option("--dependencies", dest="dependencies", action="store_true", + help="Check for missing (non-core) sqlmap dependencies") - miscellaneous.add_option("--disable-coloring", dest="disableColoring", - action="store_true", - help="Disable console output coloring") + miscellaneous.add_option("--disable-coloring", dest="disableColoring", action="store_true", + help="Disable console output coloring") miscellaneous.add_option("--gpage", dest="googlePage", type="int", - help="Use Google dork results from specified page number") + help="Use Google dork results from specified page number") - miscellaneous.add_option("--identify-waf", dest="identifyWaf", - action="store_true", - help="Make a thorough testing for a WAF/IPS/IDS protection") + miscellaneous.add_option("--identify-waf", dest="identifyWaf", action="store_true", + help="Make a thorough testing for a WAF/IPS/IDS protection") - miscellaneous.add_option("--mobile", dest="mobile", - action="store_true", - help="Imitate smartphone through HTTP User-Agent header") + miscellaneous.add_option("--mobile", dest="mobile", 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("--offline", dest="offline", action="store_true", + help="Work in offline mode (only use session data)") - miscellaneous.add_option("--purge-output", dest="purgeOutput", - action="store_true", - help="Safely remove all content from output directory") + miscellaneous.add_option("--purge-output", dest="purgeOutput", action="store_true", + help="Safely remove all content from output directory") - miscellaneous.add_option("--skip-waf", dest="skipWaf", - action="store_true", - help="Skip heuristic detection of WAF/IPS/IDS protection") + miscellaneous.add_option("--skip-waf", dest="skipWaf", action="store_true", + help="Skip heuristic detection of WAF/IPS/IDS protection") - miscellaneous.add_option("--smart", dest="smart", - action="store_true", - help="Conduct thorough tests only if positive heuristic(s)") + miscellaneous.add_option("--smart", dest="smart", action="store_true", + help="Conduct thorough tests only if positive heuristic(s)") miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true", - help="Prompt for an interactive sqlmap shell") + help="Prompt for an interactive sqlmap shell") miscellaneous.add_option("--tmp-dir", dest="tmpDir", - help="Local directory for storing temporary files") + help="Local directory for storing temporary files") miscellaneous.add_option("--web-root", dest="webRoot", - help="Web server document root directory (e.g. \"/var/www\")") + help="Web server document root directory (e.g. \"/var/www\")") - miscellaneous.add_option("--wizard", dest="wizard", - action="store_true", - help="Simple wizard interface for beginner users") + miscellaneous.add_option("--wizard", dest="wizard", action="store_true", + help="Simple wizard interface for beginner users") # Hidden and/or experimental options parser.add_option("--dummy", dest="dummy", action="store_true", @@ -791,6 +683,9 @@ def cmdLineParser(argv=None): parser.add_option("--force-dns", dest="forceDns", action="store_true", help=SUPPRESS_HELP) + parser.add_option("--force-pivoting", dest="forcePivoting", action="store_true", + help=SUPPRESS_HELP) + parser.add_option("--force-threads", dest="forceThreads", action="store_true", help=SUPPRESS_HELP) @@ -909,7 +804,7 @@ def cmdLineParser(argv=None): 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.message + raise SqlmapSyntaxException("something went wrong during command line parsing ('%s')" % ex.message) for i in xrange(len(argv)): if argv[i] == "-hh": @@ -976,9 +871,7 @@ def cmdLineParser(argv=None): if args.dummy: args.url = args.url or DUMMY_URL - if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, \ - args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.wizard, args.dependencies, \ - args.purgeOutput, args.sitemapUrl)): + if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.liveTest, args.wizard, args.dependencies, args.purgeOutput, args.sitemapUrl)): errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, -x, --wizard, --update, --purge-output or --dependencies), " errMsg += "use -h for basic or -hh for advanced help\n" parser.error(errMsg) diff --git a/lib/parse/headers.py b/lib/parse/headers.py index 58accf9a8..1f42b1717 100644 --- a/lib/parse/headers.py +++ b/lib/parse/headers.py @@ -13,7 +13,6 @@ from lib.core.data import kb from lib.core.data import paths from lib.parse.handler import FingerprintHandler - def headersParser(headers): """ This function calls a class that parses the input HTTP headers to @@ -24,18 +23,16 @@ def headersParser(headers): if not kb.headerPaths: kb.headerPaths = { "microsoftsharepointteamservices": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "sharepoint.xml"), - "server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"), - "servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet-engine.xml"), - "set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "set-cookie.xml"), - "x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"), - "x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"), + "server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"), + "servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet-engine.xml"), + "set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "set-cookie.xml"), + "x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"), + "x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml"), } - for header in itertools.ifilter(lambda x: x in kb.headerPaths, headers): + for header in itertools.ifilter(lambda _: _ in kb.headerPaths, headers): value = headers[header] xmlfile = kb.headerPaths[header] - handler = FingerprintHandler(value, kb.headersFp) - parseXmlFile(xmlfile, handler) parseXmlFile(paths.GENERIC_XML, handler) diff --git a/lib/parse/payloads.py b/lib/parse/payloads.py index 9f8d5a41b..0eda51195 100644 --- a/lib/parse/payloads.py +++ b/lib/parse/payloads.py @@ -78,7 +78,7 @@ def loadBoundaries(): errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" - raise SqlmapInstallationException, errMsg + raise SqlmapInstallationException(errMsg) root = doc.getroot() parseXmlNode(root) @@ -93,7 +93,7 @@ def loadPayloads(): errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" - raise SqlmapInstallationException, errMsg + raise SqlmapInstallationException(errMsg) root = doc.getroot() parseXmlNode(root) diff --git a/lib/parse/sitemap.py b/lib/parse/sitemap.py index 6724ceb0e..3c503f9fb 100644 --- a/lib/parse/sitemap.py +++ b/lib/parse/sitemap.py @@ -32,7 +32,7 @@ def parseSitemap(url, retVal=None): content = Request.getPage(url=url, raise404=True)[0] if not abortedFlag else "" except httplib.InvalidURL: errMsg = "invalid URL given for sitemap ('%s')" % url - raise SqlmapSyntaxException, errMsg + raise SqlmapSyntaxException(errMsg) for match in re.finditer(r"\s*([^<]+)", content or ""): if abortedFlag: diff --git a/lib/request/basic.py b/lib/request/basic.py index d0d6d0bbb..1fe7fd8d3 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -61,7 +61,7 @@ def forgeHeaders(items=None, base=None): if items[_] is None: del items[_] - headers = OrderedDict(base or conf.httpHeaders) + headers = OrderedDict(conf.httpHeaders if base is None else base) headers.update(items.items()) class _str(str): @@ -110,7 +110,9 @@ def forgeHeaders(items=None, base=None): kb.mergeCookies = readInput(message, default='Y', boolean=True) if kb.mergeCookies and kb.injection.place != PLACE.COOKIE: - _ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), x) + def _(value): + return re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), value) + headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE]) if PLACE.COOKIE in conf.parameters: @@ -161,7 +163,7 @@ def checkCharEncoding(encoding, warn=True): return encoding # Reference: http://www.destructor.de/charsets/index.htm - translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"} + translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"} for delimiter in (';', ',', '('): if delimiter in encoding: @@ -332,7 +334,7 @@ def decodePage(page, contentEncoding, contentType): kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page)) - if kb.pageEncoding and kb.pageEncoding.lower() == "utf-8-sig": + if (kb.pageEncoding or "").lower() == "utf-8-sig": kb.pageEncoding = "utf-8" if page and page.startswith("\xef\xbb\xbf"): # Reference: https://docs.python.org/2/library/codecs.html (Note: noticed problems when "utf-8-sig" is left to Python for handling) page = page[3:] diff --git a/lib/request/basicauthhandler.py b/lib/request/basicauthhandler.py index cd115e6fc..81f494313 100644 --- a/lib/request/basicauthhandler.py +++ b/lib/request/basicauthhandler.py @@ -30,10 +30,8 @@ class SmartHTTPBasicAuthHandler(urllib2.HTTPBasicAuthHandler): self.retried_count = 0 else: if self.retried_count > 5: - raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed", - headers, None) + raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed", headers, None) else: self.retried_count += 1 - return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed( - self, auth_header, host, req, headers) + return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(self, auth_header, host, req, headers) diff --git a/lib/request/connect.py b/lib/request/connect.py index 19049bf31..2d6e5dfd0 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -34,6 +34,7 @@ from lib.core.common import calculateDeltaSeconds from lib.core.common import checkSameHost from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout +from lib.core.common import escapeJsonValue from lib.core.common import evaluateCode from lib.core.common import extractRegexResult from lib.core.common import findMultipartPostBoundary @@ -63,6 +64,7 @@ from lib.core.common import urlencode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger +from lib.core.decorators import stackedmethod from lib.core.dicts import POST_HINT_CONTENT_TYPES from lib.core.enums import ADJUST_TIME_DELAY from lib.core.enums import AUTH_TYPE @@ -118,7 +120,6 @@ from lib.request.methodrequest import MethodRequest from thirdparty.odict.odict import OrderedDict from thirdparty.socks.socks import ProxyError - class Connect(object): """ This class defines methods used to perform HTTP requests @@ -187,13 +188,13 @@ class Connect(object): if not kb.dnsMode and conn: headers = conn.info() - if headers and hasattr(headers, "getheader") and (headers.getheader(HTTP_HEADER.CONTENT_ENCODING, "").lower() in ("gzip", "deflate")\ - or "text" not in headers.getheader(HTTP_HEADER.CONTENT_TYPE, "").lower()): + if kb.pageCompress and headers and hasattr(headers, "getheader") and (headers.getheader(HTTP_HEADER.CONTENT_ENCODING, "").lower() in ("gzip", "deflate") or "text" not in headers.getheader(HTTP_HEADER.CONTENT_TYPE, "").lower()): retVal = conn.read(MAX_CONNECTION_TOTAL_SIZE) if len(retVal) == MAX_CONNECTION_TOTAL_SIZE: warnMsg = "large compressed response detected. Disabling compression" singleTimeWarnMessage(warnMsg) kb.pageCompress = False + raise SqlmapCompressionException else: while True: if not conn: @@ -241,27 +242,27 @@ class Connect(object): kb.requestCounter += 1 threadData.lastRequestUID = kb.requestCounter - url = kwargs.get("url", None) or conf.url - get = kwargs.get("get", None) - post = kwargs.get("post", None) - method = kwargs.get("method", None) - cookie = kwargs.get("cookie", None) - ua = kwargs.get("ua", None) or conf.agent - referer = kwargs.get("referer", None) or conf.referer - host = kwargs.get("host", None) or conf.host - direct_ = kwargs.get("direct", False) - multipart = kwargs.get("multipart", None) - silent = kwargs.get("silent", False) - raise404 = kwargs.get("raise404", True) - timeout = kwargs.get("timeout", None) or conf.timeout - auxHeaders = kwargs.get("auxHeaders", None) - response = kwargs.get("response", False) + url = kwargs.get("url", None) or conf.url + get = kwargs.get("get", None) + post = kwargs.get("post", None) + method = kwargs.get("method", None) + cookie = kwargs.get("cookie", None) + ua = kwargs.get("ua", None) or conf.agent + referer = kwargs.get("referer", None) or conf.referer + host = kwargs.get("host", None) or conf.host + direct_ = kwargs.get("direct", False) + multipart = kwargs.get("multipart", None) + silent = kwargs.get("silent", False) + raise404 = kwargs.get("raise404", True) + timeout = kwargs.get("timeout", None) or conf.timeout + auxHeaders = kwargs.get("auxHeaders", None) + response = kwargs.get("response", False) ignoreTimeout = kwargs.get("ignoreTimeout", False) or kb.ignoreTimeout or conf.ignoreTimeouts - refreshing = kwargs.get("refreshing", False) - retrying = kwargs.get("retrying", False) - crawling = kwargs.get("crawling", False) - checking = kwargs.get("checking", False) - skipRead = kwargs.get("skipRead", False) + refreshing = kwargs.get("refreshing", False) + retrying = kwargs.get("retrying", False) + crawling = kwargs.get("crawling", False) + checking = kwargs.get("checking", False) + skipRead = kwargs.get("skipRead", False) if multipart: post = multipart @@ -346,7 +347,7 @@ class Connect(object): requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str # Prepare HTTP headers - headers = forgeHeaders({HTTP_HEADER.COOKIE: cookie, HTTP_HEADER.USER_AGENT: ua, HTTP_HEADER.REFERER: referer, HTTP_HEADER.HOST: host}) + headers = forgeHeaders({HTTP_HEADER.COOKIE: cookie, HTTP_HEADER.USER_AGENT: ua, HTTP_HEADER.REFERER: referer, HTTP_HEADER.HOST: host}, base=None if target else {}) if HTTP_HEADER.COOKIE in headers: cookie = headers[HTTP_HEADER.COOKIE] @@ -428,8 +429,10 @@ class Connect(object): method = unicodeencode(method) req = MethodRequest(url, post, headers) req.set_method(method) - else: + elif url is not None: req = urllib2.Request(url, post, headers) + else: + return None, None, None requestHeaders += "\r\n".join(["%s: %s" % (getUnicode(key.capitalize() if isinstance(key, basestring) else key), getUnicode(value)) for (key, value) in req.header_items()]) @@ -494,7 +497,7 @@ class Connect(object): responseHeaders = {} page = decodePage(page, responseHeaders.get(HTTP_HEADER.CONTENT_ENCODING), responseHeaders.get(HTTP_HEADER.CONTENT_TYPE)) - status = getUnicode(conn.msg) if conn else None + status = getUnicode(conn.msg) if conn and getattr(conn, "msg", None) else None kb.connErrorCounter = 0 @@ -577,7 +580,7 @@ class Connect(object): page = page if isinstance(page, unicode) else getUnicode(page) code = ex.code - status = getUnicode(ex.msg) + status = getSafeExString(ex) kb.originalCode = kb.originalCode or code threadData.lastHTTPError = (threadData.lastRequestUID, code, status) @@ -683,6 +686,9 @@ class Connect(object): status = re.search(r"Handshake status ([\d]{3})", tbMsg) errMsg = "websocket handshake status %s" % status.group(1) if status else "unknown" raise SqlmapConnectionException(errMsg) + elif "SqlmapCompressionException" in tbMsg: + warnMsg = "problems with response (de)compression" + retrying = True else: warnMsg = "unable to connect to the target URL" @@ -765,7 +771,8 @@ class Connect(object): return page, responseHeaders, code @staticmethod - def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): + @stackedmethod + def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True, disableTampering=False): """ This method calls a function to get the target URL page content and returns its page ratio (0 <= ratio <= 1) or a boolean value @@ -812,7 +819,7 @@ class Connect(object): conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) if payload: - if kb.tamperFunctions: + if not disableTampering and kb.tamperFunctions: for function in kb.tamperFunctions: try: payload = function(payload=payload, headers=auxHeaders) @@ -836,16 +843,10 @@ class Connect(object): # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") elif kb.postHint == POST_HINT.JSON: - if payload.startswith('"') and payload.endswith('"'): - payload = json.dumps(payload[1:-1]) - else: - payload = json.dumps(payload)[1:-1] + payload = escapeJsonValue(payload) elif kb.postHint == POST_HINT.JSON_LIKE: payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') - if payload.startswith('"') and payload.endswith('"'): - payload = json.dumps(payload[1:-1]) - else: - payload = json.dumps(payload)[1:-1] + payload = escapeJsonValue(payload) payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') value = agent.replacePayload(value, payload) else: @@ -861,9 +862,9 @@ class Connect(object): skip = True if not skip: - spaceplus = kb.postSpaceToPlus and place in (PLACE.POST, PLACE.CUSTOM_POST) - value = urlencode(value, spaceplus=spaceplus) - payload = urlencode(payload, safe='%', spaceplus=spaceplus) + if place in (PLACE.POST, PLACE.CUSTOM_POST): # potential problems in other cases (e.g. URL encoding of whole URI - including path) + value = urlencode(value, spaceplus=kb.postSpaceToPlus) + payload = urlencode(payload, safe='%', spaceplus=kb.postSpaceToPlus) value = agent.replacePayload(value, payload) postUrlEncode = False @@ -933,9 +934,9 @@ class Connect(object): if value and place == PLACE.CUSTOM_HEADER: if value.split(',')[0].capitalize() == PLACE.COOKIE: - cookie = value.split(',', 1)[1] + cookie = value.split(',', 1)[-1] else: - auxHeaders[value.split(',')[0]] = value.split(',', 1)[1] + auxHeaders[value.split(',')[0]] = value.split(',', 1)[-1] if conf.csrfToken: def _adjustParameter(paramString, parameter, newValue): @@ -982,7 +983,7 @@ class Connect(object): if not conf.csrfUrl: errMsg += ". You can try to rerun by providing " errMsg += "a valid value for option '--csrf-url'" - raise SqlmapTokenException, errMsg + raise SqlmapTokenException(errMsg) if token: token = token.strip("'\"") @@ -1040,7 +1041,7 @@ class Connect(object): name = safeVariableNaming(name) elif name in keywords: name = "%s%s" % (name, EVALCODE_KEYWORD_SUFFIX) - value = urldecode(value, convall=True, spaceplus=(item==post and kb.postSpaceToPlus)) + value = urldecode(value, convall=True, spaceplus=(item == post and kb.postSpaceToPlus)) variables[name] = value if cookie: @@ -1262,7 +1263,11 @@ class Connect(object): page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None - kb.permissionFlag = re.search(PERMISSION_DENIED_REGEX, page or "", re.I) is not None + + message = extractRegexResult(PERMISSION_DENIED_REGEX, page or "", re.I) + if message: + kb.permissionFlag = True + singleTimeWarnMessage("potential permission problems detected ('%s')" % message) if content or response: return page, headers, code @@ -1272,5 +1277,5 @@ class Connect(object): else: return comparison(page, headers, code, getRatioValue, pageLength) -def setHTTPHandlers(): # Cross-linked function +def setHTTPHandlers(): # Cross-referenced function raise NotImplementedError diff --git a/lib/request/httpshandler.py b/lib/request/httpshandler.py index bd8fe4b51..cb41f5af0 100644 --- a/lib/request/httpshandler.py +++ b/lib/request/httpshandler.py @@ -48,7 +48,7 @@ class HTTPSConnection(httplib.HTTPSConnection): # Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext # https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni - if re.search(r"\A[\d.]+\Z", self.host) is None and kb.tlsSNI.get(self.host) != False and hasattr(ssl, "SSLContext"): + if re.search(r"\A[\d.]+\Z", self.host) is None and kb.tlsSNI.get(self.host) is not False and hasattr(ssl, "SSLContext"): for protocol in filter(lambda _: _ >= ssl.PROTOCOL_TLSv1, _protocols): try: sock = create_sock() diff --git a/lib/request/inject.py b/lib/request/inject.py index 485b835c4..cfe69a6ba 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -33,6 +33,7 @@ from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries +from lib.core.decorators import stackedmethod from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS @@ -175,10 +176,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char # forge the SQL limiting the query output one entry at a time # NOTE: we assume that only queries that get data from a table # can return multiple entries - if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \ - not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not \ - expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \ - and not re.search(SQL_SCALAR_REGEX, expression, re.I): + if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and not re.search(SQL_SCALAR_REGEX, expression, re.I): expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression) if limitCond: @@ -336,6 +334,7 @@ def _goUnion(expression, unpack=True, dump=False): return output +@stackedmethod def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection diff --git a/lib/request/templates.py b/lib/request/templates.py index cad883bfd..ff8ac82fe 100644 --- a/lib/request/templates.py +++ b/lib/request/templates.py @@ -19,4 +19,3 @@ def getPageTemplate(payload, place): retVal = kb.pageTemplates[(payload, place)] return retVal - diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index 5a50ea986..490c8c298 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -27,7 +27,6 @@ from lib.takeover.udf import UDF from lib.takeover.web import Web from lib.takeover.xp_cmdshell import XP_cmdshell - class Abstraction(Web, UDF, XP_cmdshell): """ This class defines an abstraction layer for OS takeover functionalities @@ -172,9 +171,9 @@ class Abstraction(Web, UDF, XP_cmdshell): inject.goStacked(expression) # TODO: add support for PostgreSQL - #elif Backend.isDbms(DBMS.PGSQL): - # expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1") - # inject.goStacked(expression) + # elif Backend.isDbms(DBMS.PGSQL): + # expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1") + # inject.goStacked(expression) def initEnv(self, mandatory=True, detailed=False, web=False, forceInit=False): self._initRunAs() diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index 5813ca336..8a8c0b74d 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -81,6 +81,7 @@ class Metasploit: _ = normalizePath(os.path.join(_, "..")) if _ == old: break + self._msfCli = "%s & ruby %s" % (_, self._msfCli) self._msfConsole = "%s & ruby %s" % (_, self._msfConsole) self._msfEncode = "ruby %s" % self._msfEncode @@ -88,60 +89,60 @@ class Metasploit: self._msfVenom = "%s & ruby %s" % (_, self._msfVenom) self._msfPayloadsList = { - "windows": { - 1: ("Meterpreter (default)", "windows/meterpreter"), - 2: ("Shell", "windows/shell"), - 3: ("VNC", "windows/vncinject"), - }, - "linux": { - 1: ("Shell (default)", "linux/x86/shell"), - 2: ("Meterpreter (beta)", "linux/x86/meterpreter"), - } - } + "windows": { + 1: ("Meterpreter (default)", "windows/meterpreter"), + 2: ("Shell", "windows/shell"), + 3: ("VNC", "windows/vncinject"), + }, + "linux": { + 1: ("Shell (default)", "linux/x86/shell"), + 2: ("Meterpreter (beta)", "linux/x86/meterpreter"), + } + } self._msfConnectionsList = { - "windows": { - 1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"), - 2: ("Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports"), - 3: ("Reverse HTTP: Connect back from the database host to this machine tunnelling traffic over HTTP", "reverse_http"), - 4: ("Reverse HTTPS: Connect back from the database host to this machine tunnelling traffic over HTTPS", "reverse_https"), - 5: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"), - }, - "linux": { - 1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"), - 2: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"), - } - } + "windows": { + 1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"), + 2: ("Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports"), + 3: ("Reverse HTTP: Connect back from the database host to this machine tunnelling traffic over HTTP", "reverse_http"), + 4: ("Reverse HTTPS: Connect back from the database host to this machine tunnelling traffic over HTTPS", "reverse_https"), + 5: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"), + }, + "linux": { + 1: ("Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp"), + 2: ("Bind TCP: Listen on the database host for a connection", "bind_tcp"), + } + } self._msfEncodersList = { - "windows": { - 1: ("No Encoder", "generic/none"), - 2: ("Alpha2 Alphanumeric Mixedcase Encoder", "x86/alpha_mixed"), - 3: ("Alpha2 Alphanumeric Uppercase Encoder", "x86/alpha_upper"), - 4: ("Avoid UTF8/tolower", "x86/avoid_utf8_tolower"), - 5: ("Call+4 Dword XOR Encoder", "x86/call4_dword_xor"), - 6: ("Single-byte XOR Countdown Encoder", "x86/countdown"), - 7: ("Variable-length Fnstenv/mov Dword XOR Encoder", "x86/fnstenv_mov"), - 8: ("Polymorphic Jump/Call XOR Additive Feedback Encoder", "x86/jmp_call_additive"), - 9: ("Non-Alpha Encoder", "x86/nonalpha"), - 10: ("Non-Upper Encoder", "x86/nonupper"), - 11: ("Polymorphic XOR Additive Feedback Encoder (default)", "x86/shikata_ga_nai"), - 12: ("Alpha2 Alphanumeric Unicode Mixedcase Encoder", "x86/unicode_mixed"), - 13: ("Alpha2 Alphanumeric Unicode Uppercase Encoder", "x86/unicode_upper"), - } - } + "windows": { + 1: ("No Encoder", "generic/none"), + 2: ("Alpha2 Alphanumeric Mixedcase Encoder", "x86/alpha_mixed"), + 3: ("Alpha2 Alphanumeric Uppercase Encoder", "x86/alpha_upper"), + 4: ("Avoid UTF8/tolower", "x86/avoid_utf8_tolower"), + 5: ("Call+4 Dword XOR Encoder", "x86/call4_dword_xor"), + 6: ("Single-byte XOR Countdown Encoder", "x86/countdown"), + 7: ("Variable-length Fnstenv/mov Dword XOR Encoder", "x86/fnstenv_mov"), + 8: ("Polymorphic Jump/Call XOR Additive Feedback Encoder", "x86/jmp_call_additive"), + 9: ("Non-Alpha Encoder", "x86/nonalpha"), + 10: ("Non-Upper Encoder", "x86/nonupper"), + 11: ("Polymorphic XOR Additive Feedback Encoder (default)", "x86/shikata_ga_nai"), + 12: ("Alpha2 Alphanumeric Unicode Mixedcase Encoder", "x86/unicode_mixed"), + 13: ("Alpha2 Alphanumeric Unicode Uppercase Encoder", "x86/unicode_upper"), + } + } self._msfSMBPortsList = { - "windows": { - 1: ("139/TCP", "139"), - 2: ("445/TCP (default)", "445"), - } - } + "windows": { + 1: ("139/TCP", "139"), + 2: ("445/TCP (default)", "445"), + } + } self._portData = { - "bind": "remote port number", - "reverse": "local port number", - } + "bind": "remote port number", + "reverse": "local port number", + } def _skeletonSelection(self, msg, lst=None, maxValue=1, default=1): if Backend.isOs(OS.WINDOWS): @@ -484,10 +485,13 @@ class Metasploit: send_all(proc, "use espia\n") send_all(proc, "use incognito\n") - # This extension is loaded by default since Metasploit > 3.7 - #send_all(proc, "use priv\n") - # This extension freezes the connection on 64-bit systems - #send_all(proc, "use sniffer\n") + + # This extension is loaded by default since Metasploit > 3.7: + # send_all(proc, "use priv\n") + + # This extension freezes the connection on 64-bit systems: + # send_all(proc, "use sniffer\n") + send_all(proc, "sysinfo\n") send_all(proc, "getuid\n") @@ -671,13 +675,10 @@ class Metasploit: written = self.writeFile(self.shellcodeexecLocal, self.shellcodeexecRemote, "binary", forceCheck=True) if written is not True: - errMsg = "there has been a problem uploading shellcodeexec, it " + errMsg = "there has been a problem uploading shellcodeexec. It " errMsg += "looks like the binary file has not been written " errMsg += "on the database underlying file system or an AV has " - errMsg += "flagged it as malicious and removed it. In such a case " - errMsg += "it is recommended to recompile shellcodeexec with " - errMsg += "slight modification to the source code or pack it " - errMsg += "with an obfuscator software" + errMsg += "flagged it as malicious and removed it" logger.error(errMsg) return False diff --git a/lib/takeover/registry.py b/lib/takeover/registry.py index 043ed56bd..00b5183a7 100644 --- a/lib/takeover/registry.py +++ b/lib/takeover/registry.py @@ -33,19 +33,19 @@ class Registry: readParse = "REG QUERY \"" + self._regKey + "\" /v \"" + self._regValue + "\"" self._batRead = ( - "@ECHO OFF\r\n", - readParse, - ) + "@ECHO OFF\r\n", + readParse, + ) self._batAdd = ( - "@ECHO OFF\r\n", - "REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self._regKey, self._regValue, self._regType, self._regData), - ) + "@ECHO OFF\r\n", + "REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self._regKey, self._regValue, self._regType, self._regData), + ) self._batDel = ( - "@ECHO OFF\r\n", - "REG DELETE \"%s\" /v \"%s\" /f" % (self._regKey, self._regValue), - ) + "@ECHO OFF\r\n", + "REG DELETE \"%s\" /v \"%s\" /f" % (self._regKey, self._regValue), + ) def _createLocalBatchFile(self): self._batPathFp = open(self._batPathLocal, "w") diff --git a/lib/takeover/web.py b/lib/takeover/web.py index 617d67a5a..8f5b5616d 100644 --- a/lib/takeover/web.py +++ b/lib/takeover/web.py @@ -53,7 +53,6 @@ from lib.core.settings import VIEWSTATE_REGEX from lib.request.connect import Connect as Request from thirdparty.oset.pyoset import oset - class Web: """ This class defines web-oriented OS takeover functionalities for @@ -112,10 +111,10 @@ class Web: if self.webApi in getPublicTypeMembers(WEB_API, True): multipartParams = { - "upload": "1", - "file": stream, - "uploadDir": directory, - } + "upload": "1", + "file": stream, + "uploadDir": directory, + } if self.webApi == WEB_API.ASPX: multipartParams['__EVENTVALIDATION'] = kb.data.__EVENTVALIDATION diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index a9b17dd77..19b06d8e8 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -24,6 +24,7 @@ from lib.core.convert import hexencode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger +from lib.core.decorators import stackedmethod from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED @@ -96,6 +97,7 @@ class XP_cmdshell: return wasLastResponseDelayed() + @stackedmethod def _xpCmdshellTest(self): threadData = getCurrentThreadData() pushValue(threadData.disableStdOut) @@ -214,7 +216,7 @@ class XP_cmdshell: if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: output = inject.getValue(query, resumeValue=False, blind=False, time=False) - if (output is None) or len(output)==0 or output[0] is None: + if (output is None) or len(output) == 0 or output[0] is None: output = [] count = inject.getValue("SELECT COUNT(id) FROM %s" % self.cmdTblName, resumeValue=False, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 61f92b6ef..2783231f5 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -611,7 +611,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None # If we had no luck with commonValue and common charset, # use the returned other charset if not val: - val = getChar(index, otherCharset, otherCharset==asciiTbl) + val = getChar(index, otherCharset, otherCharset == asciiTbl) else: val = getChar(index, asciiTbl, not(charsetType is None and conf.charset)) diff --git a/lib/techniques/dns/test.py b/lib/techniques/dns/test.py index 3910e1302..7a580e6e5 100644 --- a/lib/techniques/dns/test.py +++ b/lib/techniques/dns/test.py @@ -14,7 +14,6 @@ from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.exception import SqlmapNotVulnerableException from lib.techniques.dns.use import dnsUse - def dnsTest(payload): logger.info("testing for data retrieval through DNS channel") diff --git a/lib/techniques/dns/use.py b/lib/techniques/dns/use.py index 42914f166..3cf607b54 100644 --- a/lib/techniques/dns/use.py +++ b/lib/techniques/dns/use.py @@ -33,7 +33,6 @@ from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request - def dnsUse(payload, expression): """ Retrieve the output of a SQL query taking advantage of the DNS diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index 769e0991a..cf84aa713 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -133,20 +133,23 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False): # Parse the returned page to get the exact error-based # SQL injection output - output = reduce(lambda x, y: x if x is not None else y, (\ - extractRegexResult(check, page), \ - extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None), \ - extractRegexResult(check, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)), \ - extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)), \ - None) + output = reduce(lambda x, y: x if x is not None else y, ( + extractRegexResult(check, page), + extractRegexResult(check, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None), + extractRegexResult(check, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)), + extractRegexResult(check, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None)), + None + ) if output is not None: output = getUnicode(output) else: - trimmed = extractRegexResult(trimcheck, page) \ - or extractRegexResult(trimcheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None) \ - or extractRegexResult(trimcheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)) \ - or extractRegexResult(trimcheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None) + trimmed = ( + extractRegexResult(trimcheck, page) or + extractRegexResult(trimcheck, threadData.lastHTTPError[2] if wasLastResponseHTTPError() else None) or + extractRegexResult(trimcheck, listToStrValue((headers[header] for header in headers if header.lower() != HTTP_HEADER.URI.lower()) if headers else None)) or + extractRegexResult(trimcheck, threadData.lastRedirectMsg[1] if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == threadData.lastRequestUID else None) + ) if trimmed: if not chunkTest: @@ -308,12 +311,7 @@ def errorUse(expression, dump=False): # entry at a time # NOTE: we assume that only queries that get data from a table can # return multiple entries - if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in \ - expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) \ - or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not \ - expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \ - and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \ - and not re.search(SQL_SCALAR_REGEX, expression, re.I): + if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) and not re.search(SQL_SCALAR_REGEX, expression, re.I): expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump) if limitCond: diff --git a/lib/techniques/union/test.py b/lib/techniques/union/test.py index 3d621e898..6d94cb875 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -27,6 +27,7 @@ from lib.core.common import wasLastResponseDBMSError from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger +from lib.core.decorators import stackedmethod from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import PAYLOAD from lib.core.settings import LIMITED_ROWS_TEST_NUMBER @@ -48,13 +49,14 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= """ retVal = None - def _orderByTechnique(lowerCount, upperCount): + @stackedmethod + def _orderByTechnique(lowerCount=None, upperCount=None): def _orderByTest(cols): query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix) query = agent.suffixQuery(query, suffix=suffix, comment=comment) payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where) page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False) - return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order by", "unknown column", "failed")) and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) + return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order by", "unknown column", "failed")) and not kb.heavilyDynamic and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) is not None if _orderByTest(1 if lowerCount is None else lowerCount) and not _orderByTest(randomInt() if upperCount is None else upperCount + 1): infoMsg = "'ORDER BY' technique appears to be usable. " @@ -89,7 +91,7 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= lowerCount, upperCount = conf.uColsStart, conf.uColsStop if lowerCount == 1 or conf.uCols: - found = kb.orderByColumns or _orderByTechnique(lowerCount, upperCount) + found = kb.orderByColumns or (_orderByTechnique(lowerCount, upperCount) if conf.uCols else _orderByTechnique()) if found: kb.orderByColumns = found infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "") @@ -142,14 +144,16 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= 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 deviation is not None: + lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation - if max_ > upper: - if retVal is None or abs(max_ - upper) > abs(min_ - lower): - retVal = maxItem[0] + if min_ < lower: + retVal = minItem[0] + + if max_ > upper: + if retVal is None or abs(max_ - upper) > abs(min_ - lower): + retVal = maxItem[0] finally: kb.errorIsNone = popValue() diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py index baa42ddd7..8d69f9c9b 100644 --- a/lib/techniques/union/use.py +++ b/lib/techniques/union/use.py @@ -44,6 +44,7 @@ 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 HTTP_HEADER from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapSyntaxException @@ -89,11 +90,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False): # Parse the returned page to get the exact UNION-based # SQL injection output def _(regex): - return reduce(lambda x, y: x if x is not None else y, (\ - extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), \ - extractRegexResult(regex, removeReflectiveValues(listToStrValue(headers.headers \ - if headers else None), payload, True), re.DOTALL | re.IGNORECASE)), \ - None) + return reduce(lambda x, y: x if x is not None else y, (extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE), extractRegexResult(regex, removeReflectiveValues(listToStrValue((_ for _ in headers.headers if not _.startswith(HTTP_HEADER.URI)) if headers else None), payload, True), re.DOTALL | re.IGNORECASE)), None) # Automatically patching last char trimming cases if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""): @@ -236,13 +233,7 @@ def unionUse(expression, unpack=True, dump=False): # SQL limiting the query output one entry at a time # NOTE: we assume that only queries that get data from a table can # return multiple entries - if value is None and (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or \ - kb.forcePartialUnion or \ - (dump and (conf.limitStart or conf.limitStop)) or "LIMIT " in expression.upper()) and \ - " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \ - not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE \ - and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \ - and not re.search(SQL_SCALAR_REGEX, expression, re.I): + if value is None and (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or kb.forcePartialUnion or (dump and (conf.limitStart or conf.limitStop)) or "LIMIT " in expression.upper()) and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) and not re.search(SQL_SCALAR_REGEX, expression, re.I): expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump) if limitCond: diff --git a/lib/utils/api.py b/lib/utils/api.py index 28f0a6c26..52ee0f442 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -94,7 +94,7 @@ class Database(object): else: self.cursor.execute(statement) except sqlite3.OperationalError, ex: - if not "locked" in getSafeExString(ex): + if "locked" not in getSafeExString(ex): raise else: break @@ -103,22 +103,9 @@ class Database(object): return self.cursor.fetchall() def init(self): - self.execute("CREATE TABLE logs(" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "taskid INTEGER, time TEXT, " - "level TEXT, message TEXT" - ")") - - self.execute("CREATE TABLE data(" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "taskid INTEGER, status INTEGER, " - "content_type INTEGER, value TEXT" - ")") - - self.execute("CREATE TABLE errors(" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "taskid INTEGER, error TEXT" - ")") + self.execute("CREATE TABLE logs(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, time TEXT, level TEXT, message TEXT)") + self.execute("CREATE TABLE data(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, status INTEGER, content_type INTEGER, value TEXT)") + self.execute("CREATE TABLE errors(id INTEGER PRIMARY KEY AUTOINCREMENT, taskid INTEGER, error TEXT)") class Task(object): def __init__(self, taskid, remote_addr): @@ -210,7 +197,6 @@ class Task(object): def engine_has_terminated(self): return isinstance(self.engine_get_returncode(), int) - # Wrapper functions for sqlmap engine class StdDbOut(object): def __init__(self, taskid, messagetype="stdout"): @@ -277,7 +263,7 @@ def setRestAPILog(): conf.databaseCursor = Database(conf.database) conf.databaseCursor.connect("client") except sqlite3.OperationalError, ex: - raise SqlmapConnectionException, "%s ('%s')" % (ex, conf.database) + raise SqlmapConnectionException("%s ('%s')" % (ex, conf.database)) # Set a logging handler that writes log messages to a IPC database logger.removeHandler(LOGGER_HANDLER) @@ -584,7 +570,6 @@ def scan_data(taskid): logger.debug("[%s] Retrieved scan data and error messages" % taskid) return jsonize({"success": True, "data": json_data_message, "error": json_errors_message}) - # Functions to handle scans' logs @get("/scan//log//") def scan_log_limited(taskid, start, end): @@ -612,7 +597,6 @@ def scan_log_limited(taskid, start, end): logger.debug("[%s] Retrieved scan log messages subset" % taskid) return jsonize({"success": True, "log": json_log_messages}) - @get("/scan//log") def scan_log(taskid): """ @@ -632,7 +616,6 @@ def scan_log(taskid): logger.debug("[%s] Retrieved scan log messages" % taskid) return jsonize({"success": True, "log": json_log_messages}) - # Function to handle files inside the output directory @get("/download///") def download(taskid, target, filename): @@ -659,7 +642,6 @@ def download(taskid, target, filename): logger.warning("[%s] File does not exist %s" % (taskid, target)) return jsonize({"success": False, "message": "File does not exist"}) - def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=RESTAPI_DEFAULT_ADAPTER, username=None, password=None): """ REST-JSON API server @@ -860,7 +842,7 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=Non return elif command in ("help", "?"): - msg = "help Show this help message\n" + msg = "help Show this help message\n" msg += "new ARGS Start a new scan task with provided arguments (e.g. 'new -u \"http://testphp.vulnweb.com/artists.php?artist=1\"')\n" msg += "use TASKID Switch current context to different task (e.g. 'use c04d8c5c7582efb4')\n" msg += "data Retrieve and show data for current task\n" diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index 6c8448594..bcd9495fc 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -167,7 +167,7 @@ def crawl(target): if not conf.bulkFile: logger.info("searching for links with depth %d" % (i + 1)) - runThreads(numThreads, crawlThread, threadChoice=(i>0)) + runThreads(numThreads, crawlThread, threadChoice=(i > 0)) clearConsoleLine(True) if threadData.shared.deeper: diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 835cb3568..e2ea0aa9b 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -108,4 +108,3 @@ def checkDependencies(): if len(missing_libraries) == 0: infoMsg = "all dependencies are installed" logger.info(infoMsg) - diff --git a/lib/utils/getch.py b/lib/utils/getch.py index 00de945bf..d2c204ac4 100644 --- a/lib/utils/getch.py +++ b/lib/utils/getch.py @@ -22,10 +22,9 @@ class _Getch(object): def __call__(self): return self.impl() - class _GetchUnix(object): def __init__(self): - import tty + __import__("tty") def __call__(self): import sys @@ -41,16 +40,14 @@ class _GetchUnix(object): termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch - class _GetchWindows(object): def __init__(self): - import msvcrt + __import__("msvcrt") def __call__(self): import msvcrt return msvcrt.getch() - class _GetchMacCarbon(object): """ A function which returns the current ASCII key that is down; @@ -79,6 +76,4 @@ class _GetchMacCarbon(object): (what, msg, when, where, mod) = Carbon.Evt.GetNextEvent(0x0008)[1] return chr(msg & 0x000000FF) - getch = _Getch() - diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 508d3a9ca..6487ba25a 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -135,7 +135,6 @@ def postgres_passwd(password, username, uppercase=False): 'md599e5ea7a6f7c3269995cba3927fd0093' """ - if isinstance(username, unicode): username = unicode.encode(username, UNICODE_ENCODING) @@ -380,7 +379,7 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs): ctx = password + magic + salt final = md5(password + salt + password).digest() - for pl in xrange(len(password),0,-16): + for pl in xrange(len(password), 0, -16): if pl > 16: ctx = ctx + final[:16] else: @@ -389,7 +388,7 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs): i = len(password) while i: if i & 1: - ctx = ctx + chr(0) #if ($i & 1) { $ctx->add(pack("C", 0)); } + ctx = ctx + chr(0) # if ($i & 1) { $ctx->add(pack("C", 0)); } else: ctx = ctx + password[0] i = i >> 1 @@ -417,7 +416,7 @@ def unix_md5_passwd(password, salt, magic="$1$", **kwargs): final = md5(ctx1).digest() - hash_ = _encode64((int(ord(final[0])) << 16) | (int(ord(final[6])) << 8) | (int(ord(final[12]))),4) + hash_ = _encode64((int(ord(final[0])) << 16) | (int(ord(final[6])) << 8) | (int(ord(final[12]))), 4) hash_ = hash_ + _encode64((int(ord(final[1])) << 16) | (int(ord(final[7])) << 8) | (int(ord(final[13]))), 4) hash_ = hash_ + _encode64((int(ord(final[2])) << 16) | (int(ord(final[8])) << 8) | (int(ord(final[14]))), 4) hash_ = hash_ + _encode64((int(ord(final[3])) << 16) | (int(ord(final[9])) << 8) | (int(ord(final[15]))), 4) @@ -522,38 +521,38 @@ def wordpress_passwd(password, salt, count, prefix, **kwargs): return "%s%s" % (prefix, _encode64(hash_, 16)) __functions__ = { - HASH.MYSQL: mysql_passwd, - HASH.MYSQL_OLD: mysql_old_passwd, - HASH.POSTGRES: postgres_passwd, - HASH.MSSQL: mssql_passwd, - HASH.MSSQL_OLD: mssql_old_passwd, - HASH.MSSQL_NEW: mssql_new_passwd, - HASH.ORACLE: oracle_passwd, - HASH.ORACLE_OLD: oracle_old_passwd, - HASH.MD5_GENERIC: md5_generic_passwd, - HASH.SHA1_GENERIC: sha1_generic_passwd, - HASH.SHA224_GENERIC: sha224_generic_passwd, - HASH.SHA256_GENERIC: sha256_generic_passwd, - HASH.SHA384_GENERIC: sha384_generic_passwd, - HASH.SHA512_GENERIC: sha512_generic_passwd, - HASH.CRYPT_GENERIC: crypt_generic_passwd, - HASH.JOOMLA: joomla_passwd, - HASH.DJANGO_MD5: django_md5_passwd, - HASH.DJANGO_SHA1: django_sha1_passwd, - HASH.WORDPRESS: wordpress_passwd, - HASH.APACHE_MD5_CRYPT: unix_md5_passwd, - HASH.UNIX_MD5_CRYPT: unix_md5_passwd, - HASH.APACHE_SHA1: apache_sha1_passwd, - HASH.VBULLETIN: vbulletin_passwd, - HASH.VBULLETIN_OLD: vbulletin_passwd, - HASH.SSHA: ssha_passwd, - HASH.SSHA256: ssha256_passwd, - HASH.SSHA512: ssha512_passwd, - HASH.MD5_BASE64: md5_generic_passwd, - HASH.SHA1_BASE64: sha1_generic_passwd, - HASH.SHA256_BASE64: sha256_generic_passwd, - HASH.SHA512_BASE64: sha512_generic_passwd, - } + HASH.MYSQL: mysql_passwd, + HASH.MYSQL_OLD: mysql_old_passwd, + HASH.POSTGRES: postgres_passwd, + HASH.MSSQL: mssql_passwd, + HASH.MSSQL_OLD: mssql_old_passwd, + HASH.MSSQL_NEW: mssql_new_passwd, + HASH.ORACLE: oracle_passwd, + HASH.ORACLE_OLD: oracle_old_passwd, + HASH.MD5_GENERIC: md5_generic_passwd, + HASH.SHA1_GENERIC: sha1_generic_passwd, + HASH.SHA224_GENERIC: sha224_generic_passwd, + HASH.SHA256_GENERIC: sha256_generic_passwd, + HASH.SHA384_GENERIC: sha384_generic_passwd, + HASH.SHA512_GENERIC: sha512_generic_passwd, + HASH.CRYPT_GENERIC: crypt_generic_passwd, + HASH.JOOMLA: joomla_passwd, + HASH.DJANGO_MD5: django_md5_passwd, + HASH.DJANGO_SHA1: django_sha1_passwd, + HASH.WORDPRESS: wordpress_passwd, + HASH.APACHE_MD5_CRYPT: unix_md5_passwd, + HASH.UNIX_MD5_CRYPT: unix_md5_passwd, + HASH.APACHE_SHA1: apache_sha1_passwd, + HASH.VBULLETIN: vbulletin_passwd, + HASH.VBULLETIN_OLD: vbulletin_passwd, + HASH.SSHA: ssha_passwd, + HASH.SSHA256: ssha256_passwd, + HASH.SSHA512: ssha512_passwd, + HASH.MD5_BASE64: md5_generic_passwd, + HASH.SHA1_BASE64: sha1_generic_passwd, + HASH.SHA256_BASE64: sha256_generic_passwd, + HASH.SHA512_BASE64: sha512_generic_passwd, +} def storeHashesToFile(attack_dict): if not attack_dict: diff --git a/lib/utils/hashdb.py b/lib/utils/hashdb.py index 8f3c91e35..95ce6bbce 100644 --- a/lib/utils/hashdb.py +++ b/lib/utils/hashdb.py @@ -92,7 +92,7 @@ class HashDB(object): except sqlite3.DatabaseError, ex: errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, getSafeExString(ex)) errMsg += "If the problem persists please rerun with `--flush-session`" - raise SqlmapConnectionException, errMsg + raise SqlmapConnectionException(errMsg) else: break diff --git a/lib/utils/htmlentities.py b/lib/utils/htmlentities.py index 361acf549..399e3580c 100644 --- a/lib/utils/htmlentities.py +++ b/lib/utils/htmlentities.py @@ -8,256 +8,256 @@ See the file 'LICENSE' for copying permission # Reference: http://www.w3.org/TR/1999/REC-html401-19991224/sgml/entities.html htmlEntities = { - 'quot': 34, - 'amp': 38, - 'lt': 60, - 'gt': 62, - 'nbsp': 160, - 'iexcl': 161, - 'cent': 162, - 'pound': 163, - 'curren': 164, - 'yen': 165, - 'brvbar': 166, - 'sect': 167, - 'uml': 168, - 'copy': 169, - 'ordf': 170, - 'laquo': 171, - 'not': 172, - 'shy': 173, - 'reg': 174, - 'macr': 175, - 'deg': 176, - 'plusmn': 177, - 'sup2': 178, - 'sup3': 179, - 'acute': 180, - 'micro': 181, - 'para': 182, - 'middot': 183, - 'cedil': 184, - 'sup1': 185, - 'ordm': 186, - 'raquo': 187, - 'frac14': 188, - 'frac12': 189, - 'frac34': 190, - 'iquest': 191, - 'Agrave': 192, - 'Aacute': 193, - 'Acirc': 194, - 'Atilde': 195, - 'Auml': 196, - 'Aring': 197, - 'AElig': 198, - 'Ccedil': 199, - 'Egrave': 200, - 'Eacute': 201, - 'Ecirc': 202, - 'Euml': 203, - 'Igrave': 204, - 'Iacute': 205, - 'Icirc': 206, - 'Iuml': 207, - 'ETH': 208, - 'Ntilde': 209, - 'Ograve': 210, - 'Oacute': 211, - 'Ocirc': 212, - 'Otilde': 213, - 'Ouml': 214, - 'times': 215, - 'Oslash': 216, - 'Ugrave': 217, - 'Uacute': 218, - 'Ucirc': 219, - 'Uuml': 220, - 'Yacute': 221, - 'THORN': 222, - 'szlig': 223, - 'agrave': 224, - 'aacute': 225, - 'acirc': 226, - 'atilde': 227, - 'auml': 228, - 'aring': 229, - 'aelig': 230, - 'ccedil': 231, - 'egrave': 232, - 'eacute': 233, - 'ecirc': 234, - 'euml': 235, - 'igrave': 236, - 'iacute': 237, - 'icirc': 238, - 'iuml': 239, - 'eth': 240, - 'ntilde': 241, - 'ograve': 242, - 'oacute': 243, - 'ocirc': 244, - 'otilde': 245, - 'ouml': 246, - 'divide': 247, - 'oslash': 248, - 'ugrave': 249, - 'uacute': 250, - 'ucirc': 251, - 'uuml': 252, - 'yacute': 253, - 'thorn': 254, - 'yuml': 255, - 'OElig': 338, - 'oelig': 339, - 'Scaron': 352, - 'fnof': 402, - 'scaron': 353, - 'Yuml': 376, - 'circ': 710, - 'tilde': 732, - 'Alpha': 913, - 'Beta': 914, - 'Gamma': 915, - 'Delta': 916, - 'Epsilon': 917, - 'Zeta': 918, - 'Eta': 919, - 'Theta': 920, - 'Iota': 921, - 'Kappa': 922, - 'Lambda': 923, - 'Mu': 924, - 'Nu': 925, - 'Xi': 926, - 'Omicron': 927, - 'Pi': 928, - 'Rho': 929, - 'Sigma': 931, - 'Tau': 932, - 'Upsilon': 933, - 'Phi': 934, - 'Chi': 935, - 'Psi': 936, - 'Omega': 937, - 'alpha': 945, - 'beta': 946, - 'gamma': 947, - 'delta': 948, - 'epsilon': 949, - 'zeta': 950, - 'eta': 951, - 'theta': 952, - 'iota': 953, - 'kappa': 954, - 'lambda': 955, - 'mu': 956, - 'nu': 957, - 'xi': 958, - 'omicron': 959, - 'pi': 960, - 'rho': 961, - 'sigmaf': 962, - 'sigma': 963, - 'tau': 964, - 'upsilon': 965, - 'phi': 966, - 'chi': 967, - 'psi': 968, - 'omega': 969, - 'thetasym': 977, - 'upsih': 978, - 'piv': 982, - 'bull': 8226, - 'hellip': 8230, - 'prime': 8242, - 'Prime': 8243, - 'oline': 8254, - 'frasl': 8260, - 'ensp': 8194, - 'emsp': 8195, - 'thinsp': 8201, - 'zwnj': 8204, - 'zwj': 8205, - 'lrm': 8206, - 'rlm': 8207, - 'ndash': 8211, - 'mdash': 8212, - 'lsquo': 8216, - 'rsquo': 8217, - 'sbquo': 8218, - 'ldquo': 8220, - 'rdquo': 8221, - 'bdquo': 8222, - 'dagger': 8224, - 'Dagger': 8225, - 'permil': 8240, - 'lsaquo': 8249, - 'rsaquo': 8250, - 'euro': 8364, - 'weierp': 8472, - 'image': 8465, - 'real': 8476, - 'trade': 8482, - 'alefsym': 8501, - 'larr': 8592, - 'uarr': 8593, - 'rarr': 8594, - 'darr': 8595, - 'harr': 8596, - 'crarr': 8629, - 'lArr': 8656, - 'uArr': 8657, - 'rArr': 8658, - 'dArr': 8659, - 'hArr': 8660, - 'forall': 8704, - 'part': 8706, - 'exist': 8707, - 'empty': 8709, - 'nabla': 8711, - 'isin': 8712, - 'notin': 8713, - 'ni': 8715, - 'prod': 8719, - 'sum': 8721, - 'minus': 8722, - 'lowast': 8727, - 'radic': 8730, - 'prop': 8733, - 'infin': 8734, - 'ang': 8736, - 'and': 8743, - 'or': 8744, - 'cap': 8745, - 'cup': 8746, - 'int': 8747, - 'there4': 8756, - 'sim': 8764, - 'cong': 8773, - 'asymp': 8776, - 'ne': 8800, - 'equiv': 8801, - 'le': 8804, - 'ge': 8805, - 'sub': 8834, - 'sup': 8835, - 'nsub': 8836, - 'sube': 8838, - 'supe': 8839, - 'oplus': 8853, - 'otimes': 8855, - 'perp': 8869, - 'sdot': 8901, - 'lceil': 8968, - 'rceil': 8969, - 'lfloor': 8970, - 'rfloor': 8971, - 'lang': 9001, - 'rang': 9002, - 'loz': 9674, - 'spades': 9824, - 'clubs': 9827, - 'hearts': 9829, - 'diams': 9830, + "quot": 34, + "amp": 38, + "lt": 60, + "gt": 62, + "nbsp": 160, + "iexcl": 161, + "cent": 162, + "pound": 163, + "curren": 164, + "yen": 165, + "brvbar": 166, + "sect": 167, + "uml": 168, + "copy": 169, + "ordf": 170, + "laquo": 171, + "not": 172, + "shy": 173, + "reg": 174, + "macr": 175, + "deg": 176, + "plusmn": 177, + "sup2": 178, + "sup3": 179, + "acute": 180, + "micro": 181, + "para": 182, + "middot": 183, + "cedil": 184, + "sup1": 185, + "ordm": 186, + "raquo": 187, + "frac14": 188, + "frac12": 189, + "frac34": 190, + "iquest": 191, + "Agrave": 192, + "Aacute": 193, + "Acirc": 194, + "Atilde": 195, + "Auml": 196, + "Aring": 197, + "AElig": 198, + "Ccedil": 199, + "Egrave": 200, + "Eacute": 201, + "Ecirc": 202, + "Euml": 203, + "Igrave": 204, + "Iacute": 205, + "Icirc": 206, + "Iuml": 207, + "ETH": 208, + "Ntilde": 209, + "Ograve": 210, + "Oacute": 211, + "Ocirc": 212, + "Otilde": 213, + "Ouml": 214, + "times": 215, + "Oslash": 216, + "Ugrave": 217, + "Uacute": 218, + "Ucirc": 219, + "Uuml": 220, + "Yacute": 221, + "THORN": 222, + "szlig": 223, + "agrave": 224, + "aacute": 225, + "acirc": 226, + "atilde": 227, + "auml": 228, + "aring": 229, + "aelig": 230, + "ccedil": 231, + "egrave": 232, + "eacute": 233, + "ecirc": 234, + "euml": 235, + "igrave": 236, + "iacute": 237, + "icirc": 238, + "iuml": 239, + "eth": 240, + "ntilde": 241, + "ograve": 242, + "oacute": 243, + "ocirc": 244, + "otilde": 245, + "ouml": 246, + "divide": 247, + "oslash": 248, + "ugrave": 249, + "uacute": 250, + "ucirc": 251, + "uuml": 252, + "yacute": 253, + "thorn": 254, + "yuml": 255, + "OElig": 338, + "oelig": 339, + "Scaron": 352, + "fnof": 402, + "scaron": 353, + "Yuml": 376, + "circ": 710, + "tilde": 732, + "Alpha": 913, + "Beta": 914, + "Gamma": 915, + "Delta": 916, + "Epsilon": 917, + "Zeta": 918, + "Eta": 919, + "Theta": 920, + "Iota": 921, + "Kappa": 922, + "Lambda": 923, + "Mu": 924, + "Nu": 925, + "Xi": 926, + "Omicron": 927, + "Pi": 928, + "Rho": 929, + "Sigma": 931, + "Tau": 932, + "Upsilon": 933, + "Phi": 934, + "Chi": 935, + "Psi": 936, + "Omega": 937, + "alpha": 945, + "beta": 946, + "gamma": 947, + "delta": 948, + "epsilon": 949, + "zeta": 950, + "eta": 951, + "theta": 952, + "iota": 953, + "kappa": 954, + "lambda": 955, + "mu": 956, + "nu": 957, + "xi": 958, + "omicron": 959, + "pi": 960, + "rho": 961, + "sigmaf": 962, + "sigma": 963, + "tau": 964, + "upsilon": 965, + "phi": 966, + "chi": 967, + "psi": 968, + "omega": 969, + "thetasym": 977, + "upsih": 978, + "piv": 982, + "bull": 8226, + "hellip": 8230, + "prime": 8242, + "Prime": 8243, + "oline": 8254, + "frasl": 8260, + "ensp": 8194, + "emsp": 8195, + "thinsp": 8201, + "zwnj": 8204, + "zwj": 8205, + "lrm": 8206, + "rlm": 8207, + "ndash": 8211, + "mdash": 8212, + "lsquo": 8216, + "rsquo": 8217, + "sbquo": 8218, + "ldquo": 8220, + "rdquo": 8221, + "bdquo": 8222, + "dagger": 8224, + "Dagger": 8225, + "permil": 8240, + "lsaquo": 8249, + "rsaquo": 8250, + "euro": 8364, + "weierp": 8472, + "image": 8465, + "real": 8476, + "trade": 8482, + "alefsym": 8501, + "larr": 8592, + "uarr": 8593, + "rarr": 8594, + "darr": 8595, + "harr": 8596, + "crarr": 8629, + "lArr": 8656, + "uArr": 8657, + "rArr": 8658, + "dArr": 8659, + "hArr": 8660, + "forall": 8704, + "part": 8706, + "exist": 8707, + "empty": 8709, + "nabla": 8711, + "isin": 8712, + "notin": 8713, + "ni": 8715, + "prod": 8719, + "sum": 8721, + "minus": 8722, + "lowast": 8727, + "radic": 8730, + "prop": 8733, + "infin": 8734, + "ang": 8736, + "and": 8743, + "or": 8744, + "cap": 8745, + "cup": 8746, + "int": 8747, + "there4": 8756, + "sim": 8764, + "cong": 8773, + "asymp": 8776, + "ne": 8800, + "equiv": 8801, + "le": 8804, + "ge": 8805, + "sub": 8834, + "sup": 8835, + "nsub": 8836, + "sube": 8838, + "supe": 8839, + "oplus": 8853, + "otimes": 8855, + "perp": 8869, + "sdot": 8901, + "lceil": 8968, + "rceil": 8969, + "lfloor": 8970, + "rfloor": 8971, + "lang": 9001, + "rang": 9002, + "loz": 9674, + "spades": 9824, + "clubs": 9827, + "hearts": 9829, + "diams": 9830, } diff --git a/lib/utils/progress.py b/lib/utils/progress.py index 4d7c023a4..e1cb4ca66 100644 --- a/lib/utils/progress.py +++ b/lib/utils/progress.py @@ -62,8 +62,7 @@ class ProgressBar(object): elif numHashes == allFull: self._progBar = "[%s]" % ("=" * allFull) else: - self._progBar = "[%s>%s]" % ("=" * (numHashes - 1), - " " * (allFull - numHashes)) + self._progBar = "[%s>%s]" % ("=" * (numHashes - 1), " " * (allFull - numHashes)) # Add the percentage at the beginning of the progress bar percentString = getUnicode(percentDone) + "%" diff --git a/lib/utils/search.py b/lib/utils/search.py index c660d4aee..e2cca24b9 100644 --- a/lib/utils/search.py +++ b/lib/utils/search.py @@ -20,6 +20,7 @@ from lib.core.common import urlencode from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger +from lib.core.decorators import stackedmethod from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import HTTP_HEADER from lib.core.enums import REDIRECTION @@ -35,7 +36,6 @@ from lib.core.settings import UNICODE_ENCODING from lib.request.basic import decodePage from thirdparty.socks import socks - def _search(dork): """ This method performs the effective search on Google providing @@ -165,6 +165,7 @@ def _search(dork): return retVal +@stackedmethod def search(dork): pushValue(kb.redirectChoice) kb.redirectChoice = REDIRECTION.YES @@ -187,5 +188,5 @@ def search(dork): finally: kb.redirectChoice = popValue() -def setHTTPHandlers(): # Cross-linked function +def setHTTPHandlers(): # Cross-referenced function raise NotImplementedError diff --git a/lib/utils/sqlalchemy.py b/lib/utils/sqlalchemy.py index 3644a6d24..7dfc59309 100644 --- a/lib/utils/sqlalchemy.py +++ b/lib/utils/sqlalchemy.py @@ -46,7 +46,7 @@ class SQLAlchemy(GenericConnector): try: if not self.port and self.db: if not os.path.exists(self.db): - raise SqlmapFilePathException, "the provided database file '%s' does not exist" % self.db + raise SqlmapFilePathException("the provided database file '%s' does not exist" % self.db) _ = conf.direct.split("//", 1) conf.direct = "%s////%s" % (_[0], os.path.abspath(self.db)) diff --git a/lib/utils/versioncheck.py b/lib/utils/versioncheck.py index 21249997b..e9f413c6c 100644 --- a/lib/utils/versioncheck.py +++ b/lib/utils/versioncheck.py @@ -20,4 +20,4 @@ except ImportError: errMsg = "missing one or more core extensions (%s) " % (", ".join("'%s'" % _ for _ in extensions)) errMsg += "most likely because current version of Python has been " errMsg += "built without appropriate dev packages (e.g. 'libsqlite3-dev')" - exit(errMsg) \ No newline at end of file + exit(errMsg) diff --git a/lib/utils/xrange.py b/lib/utils/xrange.py index 34076c7ec..98338863b 100644 --- a/lib/utils/xrange.py +++ b/lib/utils/xrange.py @@ -69,7 +69,7 @@ class xrange(object): if isinstance(index, slice): start, stop, step = index.indices(self._len()) return xrange(self._index(start), - self._index(stop), step*self.step) + self._index(stop), step * self.step) elif isinstance(index, (int, long)): if index < 0: fixed_index = index + self._len() diff --git a/plugins/dbms/access/fingerprint.py b/plugins/dbms/access/fingerprint.py index 4b01d076d..5c6896dc5 100644 --- a/plugins/dbms/access/fingerprint.py +++ b/plugins/dbms/access/fingerprint.py @@ -48,11 +48,12 @@ class Fingerprint(GenericFingerprint): # Microsoft Access table reference updated on 01/2010 sysTables = { - "97": ("MSysModules2", "MSysAccessObjects"), - "2000" : ("!MSysModules2", "MSysAccessObjects"), - "2002-2003" : ("MSysAccessStorage", "!MSysNavPaneObjectIDs"), - "2007" : ("MSysAccessStorage", "MSysNavPaneObjectIDs"), - } + "97": ("MSysModules2", "MSysAccessObjects"), + "2000": ("!MSysModules2", "MSysAccessObjects"), + "2002-2003": ("MSysAccessStorage", "!MSysNavPaneObjectIDs"), + "2007": ("MSysAccessStorage", "MSysNavPaneObjectIDs"), + } + # MSysAccessXML is not a reliable system table because it doesn't always exist # ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty") diff --git a/plugins/dbms/db2/connector.py b/plugins/dbms/db2/connector.py index d3dfef306..7bd4b86d4 100644 --- a/plugins/dbms/db2/connector.py +++ b/plugins/dbms/db2/connector.py @@ -37,7 +37,6 @@ class Connector(GenericConnector): except ibm_db_dbi.OperationalError, msg: raise SqlmapConnectionException(msg) - self.initCursor() self.printConnected() diff --git a/plugins/dbms/db2/enumeration.py b/plugins/dbms/db2/enumeration.py index b6b64ac0b..e79d281a8 100644 --- a/plugins/dbms/db2/enumeration.py +++ b/plugins/dbms/db2/enumeration.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ - from lib.core.data import logger from plugins.generic.enumeration import Enumeration as GenericEnumeration diff --git a/plugins/dbms/db2/fingerprint.py b/plugins/dbms/db2/fingerprint.py index deb2c22bd..6a584b8a9 100644 --- a/plugins/dbms/db2/fingerprint.py +++ b/plugins/dbms/db2/fingerprint.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ - from lib.core.common import Backend from lib.core.common import Format from lib.core.data import conf @@ -64,9 +63,9 @@ class Fingerprint(GenericFingerprint): value += DBMS.DB2 return value - actVer = Format.getDbms() - blank = " " * 15 - value += "active fingerprint: %s" % actVer + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer if kb.bannerFp: banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None @@ -127,12 +126,14 @@ class Fingerprint(GenericFingerprint): infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() if result: - versions = { "2003": ("5.2", (2, 1)), + versions = { + "2003": ("5.2", (2, 1)), "2008": ("7.0", (1,)), "2000": ("5.0", (4, 3, 2, 1)), "7": ("6.1", (1, 0)), "XP": ("5.1", (2, 1)), - "NT": ("4.0", (6, 5, 4, 3, 2, 1)) } + "NT": ("4.0", (6, 5, 4, 3, 2, 1)) + } # Get back-end DBMS underlying operating system version for version, data in versions.items(): diff --git a/plugins/dbms/firebird/connector.py b/plugins/dbms/firebird/connector.py index df874f9c0..f6b88cb00 100644 --- a/plugins/dbms/firebird/connector.py +++ b/plugins/dbms/firebird/connector.py @@ -39,8 +39,8 @@ class Connector(GenericConnector): self.checkFileDb() try: - self.connector = kinterbasdb.connect(host=self.hostname.encode(UNICODE_ENCODING), database=self.db.encode(UNICODE_ENCODING), \ - user=self.user.encode(UNICODE_ENCODING), password=self.password.encode(UNICODE_ENCODING), charset="UTF8") # Reference: http://www.daniweb.com/forums/thread248499.html + # Reference: http://www.daniweb.com/forums/thread248499.html + self.connector = kinterbasdb.connect(host=self.hostname.encode(UNICODE_ENCODING), database=self.db.encode(UNICODE_ENCODING), user=self.user.encode(UNICODE_ENCODING), password=self.password.encode(UNICODE_ENCODING), charset="UTF8") except kinterbasdb.OperationalError, msg: raise SqlmapConnectionException(msg[1]) diff --git a/plugins/dbms/firebird/fingerprint.py b/plugins/dbms/firebird/fingerprint.py index ba350205e..f63a57f49 100644 --- a/plugins/dbms/firebird/fingerprint.py +++ b/plugins/dbms/firebird/fingerprint.py @@ -68,12 +68,12 @@ class Fingerprint(GenericFingerprint): def _sysTablesCheck(self): retVal = None table = ( - ("1.0", ("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)",)), - ("1.5", ("NULLIF(%d,%d) IS NULL", "EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)")), - ("2.0", ("EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", "BIT_LENGTH(%d)>0", "CHAR_LENGTH(%d)>0")), - ("2.1", ("BIN_XOR(%d,%d)=0", "PI()>0.%d", "RAND()<1.%d", "FLOOR(1.%d)>=0")), - # TODO: add test for Firebird 2.5 - ) + ("1.0", ("EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)",)), + ("1.5", ("NULLIF(%d,%d) IS NULL", "EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)")), + ("2.0", ("EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", "BIT_LENGTH(%d)>0", "CHAR_LENGTH(%d)>0")), + ("2.1", ("BIN_XOR(%d,%d)=0", "PI()>0.%d", "RAND()<1.%d", "FLOOR(1.%d)>=0")), + # TODO: add test for Firebird 2.5 + ) for i in xrange(len(table)): version, checks = table[i] diff --git a/plugins/dbms/hsqldb/connector.py b/plugins/dbms/hsqldb/connector.py index 77e041e0c..ee605409f 100644 --- a/plugins/dbms/hsqldb/connector.py +++ b/plugins/dbms/hsqldb/connector.py @@ -46,11 +46,8 @@ class Connector(GenericConnector): try: driver = 'org.hsqldb.jdbc.JDBCDriver' - connection_string = 'jdbc:hsqldb:mem:.' #'jdbc:hsqldb:hsql://%s/%s' % (self.hostname, self.db) - self.connector = jaydebeapi.connect(driver, - connection_string, - str(self.user), - str(self.password)) + connection_string = 'jdbc:hsqldb:mem:.' # 'jdbc:hsqldb:hsql://%s/%s' % (self.hostname, self.db) + self.connector = jaydebeapi.connect(driver, connection_string, str(self.user), str(self.password)) except Exception, msg: raise SqlmapConnectionException(msg[0]) @@ -70,7 +67,7 @@ class Connector(GenericConnector): try: self.cursor.execute(query) retVal = True - except Exception, msg: #todo fix with specific error + except Exception, msg: # TODO: fix with specific error logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % msg[1]) self.connector.commit() diff --git a/plugins/dbms/hsqldb/fingerprint.py b/plugins/dbms/hsqldb/fingerprint.py index cab68f15e..f6a9aa659 100644 --- a/plugins/dbms/hsqldb/fingerprint.py +++ b/plugins/dbms/hsqldb/fingerprint.py @@ -125,9 +125,12 @@ class Fingerprint(GenericFingerprint): return True else: - warnMsg = "the back-end DBMS is not %s or version is < 1.7.2" % DBMS.HSQLDB + warnMsg = "the back-end DBMS is not %s" % DBMS.HSQLDB logger.warn(warnMsg) + dbgMsg = "...or version is < 1.7.2" + logger.debug(dbgMsg) + return False def getHostname(self): diff --git a/plugins/dbms/informix/connector.py b/plugins/dbms/informix/connector.py index 022e04e39..d4c5354ea 100644 --- a/plugins/dbms/informix/connector.py +++ b/plugins/dbms/informix/connector.py @@ -37,7 +37,6 @@ class Connector(GenericConnector): except ibm_db_dbi.OperationalError, msg: raise SqlmapConnectionException(msg) - self.initCursor() self.printConnected() diff --git a/plugins/dbms/informix/syntax.py b/plugins/dbms/informix/syntax.py index 62b06283a..e3cbf0d69 100644 --- a/plugins/dbms/informix/syntax.py +++ b/plugins/dbms/informix/syntax.py @@ -41,4 +41,4 @@ class Syntax(GenericSyntax): for _ in excluded.items(): retVal = retVal.replace(_[1], _[0]) - return retVal \ No newline at end of file + return retVal diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py index 79a2c9587..c0442f7be 100644 --- a/plugins/dbms/maxdb/enumeration.py +++ b/plugins/dbms/maxdb/enumeration.py @@ -108,7 +108,7 @@ class Enumeration(GenericEnumeration): conf.db = self.getCurrentDb() elif conf.db is not None: - if ',' in conf.db: + if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) @@ -184,9 +184,7 @@ class Enumeration(GenericEnumeration): rootQuery = queries[DBMS.MAXDB].columns for tbl in tblList: - if conf.db is not None and len(kb.data.cachedColumns) > 0 \ - and conf.db in kb.data.cachedColumns and tbl in \ - kb.data.cachedColumns[conf.db]: + if conf.db is not None and len(kb.data.cachedColumns) > 0 and conf.db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) diff --git a/plugins/dbms/mssqlserver/__init__.py b/plugins/dbms/mssqlserver/__init__.py index 202d6193c..02a23e967 100644 --- a/plugins/dbms/mssqlserver/__init__.py +++ b/plugins/dbms/mssqlserver/__init__.py @@ -15,7 +15,6 @@ from plugins.dbms.mssqlserver.syntax import Syntax from plugins.dbms.mssqlserver.takeover import Takeover from plugins.generic.misc import Miscellaneous - class MSSQLServerMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Microsoft SQL Server methods diff --git a/plugins/dbms/mssqlserver/connector.py b/plugins/dbms/mssqlserver/connector.py index fe1cec52f..36f69ef32 100644 --- a/plugins/dbms/mssqlserver/connector.py +++ b/plugins/dbms/mssqlserver/connector.py @@ -43,6 +43,8 @@ class Connector(GenericConnector): self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout) except (pymssql.Error, _mssql.MssqlDatabaseException), msg: raise SqlmapConnectionException(msg) + except ValueError: + raise SqlmapConnectionException self.initCursor() self.printConnected() diff --git a/plugins/dbms/mssqlserver/enumeration.py b/plugins/dbms/mssqlserver/enumeration.py index c0eec311b..7b89d60b4 100644 --- a/plugins/dbms/mssqlserver/enumeration.py +++ b/plugins/dbms/mssqlserver/enumeration.py @@ -368,16 +368,16 @@ class Enumeration(GenericEnumeration): if foundTbl not in dbs[db]: dbs[db][foundTbl] = {} - if colConsider == "1": + if colConsider == '1': conf.db = db conf.tbl = foundTbl conf.col = column self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False) - if db in kb.data.cachedColumns and foundTbl in kb.data.cachedColumns[db]\ - and not isNoneValue(kb.data.cachedColumns[db][foundTbl]): + if db in kb.data.cachedColumns and foundTbl in kb.data.cachedColumns[db] and not isNoneValue(kb.data.cachedColumns[db][foundTbl]): dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl]) + kb.data.cachedColumns = {} else: dbs[db][foundTbl][column] = None diff --git a/plugins/dbms/mssqlserver/filesystem.py b/plugins/dbms/mssqlserver/filesystem.py index b8aeaaee0..c94f70f4f 100644 --- a/plugins/dbms/mssqlserver/filesystem.py +++ b/plugins/dbms/mssqlserver/filesystem.py @@ -73,10 +73,13 @@ class Filesystem(GenericFilesystem): logger.debug("generating chunk file %s\%s from debug script %s" % (tmpPath, chunkName, randScr)) - commands = ("cd \"%s\"" % tmpPath, "debug < %s" % randScr, "del /F /Q %s" % randScr) - complComm = " & ".join(command for command in commands) + commands = ( + "cd \"%s\"" % tmpPath, + "debug < %s" % randScr, + "del /F /Q %s" % randScr + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) return chunkName @@ -195,12 +198,13 @@ class Filesystem(GenericFilesystem): logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % dFile) - commands = ("powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath, - "del /F /Q \"%s\"" % encodedBase64FilePath, - "del /F /Q \"%s\"" % randPSScriptPath) - complComm = " & ".join(command for command in commands) + commands = ( + "powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath, + "del /F /Q \"%s\"" % encodedBase64FilePath, + "del /F /Q \"%s\"" % randPSScriptPath + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) def _stackedWriteFileDebugExe(self, tmpPath, wFile, wFileContent, dFile, fileType): infoMsg = "using debug.exe to write the %s " % fileType @@ -219,10 +223,13 @@ class Filesystem(GenericFilesystem): debugMsg += "file %s\%s and moving it to %s" % (tmpPath, dFileName, dFile) logger.debug(debugMsg) - commands = ("cd \"%s\"" % tmpPath, "ren %s %s" % (chunkName, dFileName), "move /Y %s %s" % (dFileName, dFile)) - complComm = " & ".join(command for command in commands) + commands = ( + "cd \"%s\"" % tmpPath, + "ren %s %s" % (chunkName, dFileName), + "move /Y %s %s" % (dFileName, dFile) + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) else: debugMsg = "the file is larger than %d bytes. " % debugSize debugMsg += "sqlmap will split it into chunks locally, upload " @@ -244,17 +251,22 @@ class Filesystem(GenericFilesystem): debugMsg += "%s\%s to %s file %s\%s" % (tmpPath, chunkName, fileType, tmpPath, dFileName) logger.debug(debugMsg) - commands = ("cd \"%s\"" % tmpPath, copyCmd, "del /F /Q %s" % chunkName) - complComm = " & ".join(command for command in commands) + commands = ( + "cd \"%s\"" % tmpPath, + copyCmd, + "del /F /Q %s" % chunkName + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) logger.debug("moving %s file %s to %s" % (fileType, sFile, dFile)) - commands = ("cd \"%s\"" % tmpPath, "move /Y %s %s" % (dFileName, dFile)) - complComm = " & ".join(command for command in commands) + commands = ( + "cd \"%s\"" % tmpPath, + "move /Y %s %s" % (dFileName, dFile) + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) def _stackedWriteFileVbs(self, tmpPath, wFileContent, dFile, fileType): infoMsg = "using a custom visual basic script to write the " @@ -330,12 +342,14 @@ class Filesystem(GenericFilesystem): self.xpCmdshellWriteFile(vbs, tmpPath, randVbs) - commands = ("cd \"%s\"" % tmpPath, "cscript //nologo %s" % randVbs, - "del /F /Q %s" % randVbs, - "del /F /Q %s" % randFile) - complComm = " & ".join(command for command in commands) + commands = ( + "cd \"%s\"" % tmpPath, + "cscript //nologo %s" % randVbs, + "del /F /Q %s" % randVbs, + "del /F /Q %s" % randFile + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) def _stackedWriteFileCertutilExe(self, tmpPath, wFile, wFileContent, dFile, fileType): infoMsg = "using certutil.exe to write the %s " % fileType @@ -349,7 +363,7 @@ class Filesystem(GenericFilesystem): encodedFileContent = base64encode(wFileContent) - splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i+chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)]) + splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)]) logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath) @@ -357,11 +371,13 @@ class Filesystem(GenericFilesystem): logger.debug("decoding the file to %s.." % dFile) - commands = ("cd \"%s\"" % tmpPath, "certutil -f -decode %s %s" % (randFile, dFile), - "del /F /Q %s" % randFile) - complComm = " & ".join(command for command in commands) + commands = ( + "cd \"%s\"" % tmpPath, + "certutil -f -decode %s %s" % (randFile, dFile), + "del /F /Q %s" % randFile + ) - self.execCmd(complComm) + self.execCmd(" & ".join(command for command in commands)) def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False): # NOTE: this is needed here because we use xp_cmdshell extended diff --git a/plugins/dbms/mssqlserver/fingerprint.py b/plugins/dbms/mssqlserver/fingerprint.py index 67992416c..354b05b48 100644 --- a/plugins/dbms/mssqlserver/fingerprint.py +++ b/plugins/dbms/mssqlserver/fingerprint.py @@ -88,12 +88,14 @@ class Fingerprint(GenericFingerprint): infoMsg = "confirming %s" % DBMS.MSSQL logger.info(infoMsg) - for version, check in (("2000", "HOST_NAME()=HOST_NAME()"), \ - ("2005", "XACT_STATE()=XACT_STATE()"), \ - ("2008", "SYSDATETIME()=SYSDATETIME()"), \ - ("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), \ - ("2014", "CHARINDEX('12.0.2000',@@version)>0"), \ - ("2016", "ISJSON(NULL) IS NULL")): + for version, check in ( + ("2000", "HOST_NAME()=HOST_NAME()"), + ("2005", "XACT_STATE()=XACT_STATE()"), + ("2008", "SYSDATETIME()=SYSDATETIME()"), + ("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), + ("2014", "CHARINDEX('12.0.2000',@@version)>0"), + ("2016", "ISJSON(NULL) IS NULL") + ): result = inject.checkBooleanExpression(check) if result: @@ -136,14 +138,16 @@ class Fingerprint(GenericFingerprint): # Reference: http://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions # http://en.wikipedia.org/wiki/Windows_NT#Releases - versions = { "NT": ("4.0", (6, 5, 4, 3, 2, 1)), - "2000": ("5.0", (4, 3, 2, 1)), - "XP": ("5.1", (3, 2, 1)), - "2003": ("5.2", (2, 1)), - "Vista or 2008": ("6.0", (2, 1)), - "7 or 2008 R2": ("6.1", (1, 0)), - "8 or 2012": ("6.2", (0,)), - "8.1 or 2012 R2": ("6.3", (0,)) } + versions = { + "NT": ("4.0", (6, 5, 4, 3, 2, 1)), + "2000": ("5.0", (4, 3, 2, 1)), + "XP": ("5.1", (3, 2, 1)), + "2003": ("5.2", (2, 1)), + "Vista or 2008": ("6.0", (2, 1)), + "7 or 2008 R2": ("6.1", (1, 0)), + "8 or 2012": ("6.2", (0,)), + "8.1 or 2012 R2": ("6.3", (0,)) + } # Get back-end DBMS underlying operating system version for version, data in versions.items(): diff --git a/plugins/dbms/mssqlserver/takeover.py b/plugins/dbms/mssqlserver/takeover.py index c3a3381e2..a728a74da 100644 --- a/plugins/dbms/mssqlserver/takeover.py +++ b/plugins/dbms/mssqlserver/takeover.py @@ -20,7 +20,7 @@ class Takeover(GenericTakeover): GenericTakeover.__init__(self) def uncPathRequest(self): - #inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True) + # inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True) inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath) def spHeapOverflow(self): @@ -31,21 +31,22 @@ class Takeover(GenericTakeover): """ returns = { - # 2003 Service Pack 0 - "2003-0": (""), + # 2003 Service Pack 0 + "2003-0": (""), - # 2003 Service Pack 1 - "2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)" ), + # 2003 Service Pack 1 + "2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)"), - # 2003 Service Pack 2 updated at 12/2008 - #"2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)" ), + # 2003 Service Pack 2 updated at 12/2008 + # "2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)"), - # 2003 Service Pack 2 updated at 05/2009 - "2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)"), + # 2003 Service Pack 2 updated at 05/2009 + "2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)"), + + # 2003 Service Pack 2 updated at 09/2009 + # "2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"), + } - # 2003 Service Pack 2 updated at 09/2009 - #"2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"), - } addrs = None for versionSp, data in returns.items(): diff --git a/plugins/dbms/mysql/__init__.py b/plugins/dbms/mysql/__init__.py index 276c67663..b91bbefca 100644 --- a/plugins/dbms/mysql/__init__.py +++ b/plugins/dbms/mysql/__init__.py @@ -23,11 +23,11 @@ class MySQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Take def __init__(self): self.excludeDbsList = MYSQL_SYSTEM_DBS self.sysUdfs = { - # UDF name: UDF return data-type - "sys_exec": { "return": "int" }, - "sys_eval": { "return": "string" }, - "sys_bineval": { "return": "int" } - } + # UDF name: UDF return data-type + "sys_exec": {"return": "int"}, + "sys_eval": {"return": "string"}, + "sys_bineval": {"return": "int"} + } Syntax.__init__(self) Fingerprint.__init__(self) diff --git a/plugins/dbms/mysql/filesystem.py b/plugins/dbms/mysql/filesystem.py index d28d12312..1181d3a86 100644 --- a/plugins/dbms/mysql/filesystem.py +++ b/plugins/dbms/mysql/filesystem.py @@ -14,6 +14,7 @@ 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.decorators import stackedmethod from lib.core.enums import CHARSET_TYPE from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD @@ -81,6 +82,7 @@ class Filesystem(GenericFilesystem): return result + @stackedmethod def unionWriteFile(self, wFile, dFile, fileType, forceCheck=False): logger.debug("encoding file to its hexadecimal string value") diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index 9a0ec75e6..2e039532e 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -41,18 +41,19 @@ class Fingerprint(GenericFingerprint): # Reference: https://downloads.mysql.com/archives/community/ versions = ( - (32200, 32235), # MySQL 3.22 - (32300, 32359), # MySQL 3.23 - (40000, 40032), # MySQL 4.0 - (40100, 40131), # MySQL 4.1 - (50000, 50096), # MySQL 5.0 - (50100, 50172), # MySQL 5.1 - (50400, 50404), # MySQL 5.4 - (50500, 50554), # MySQL 5.5 - (50600, 50635), # MySQL 5.6 - (50700, 50717), # MySQL 5.7 - (60000, 60014), # MySQL 6.0 - ) + (32200, 32235), # MySQL 3.22 + (32300, 32359), # MySQL 3.23 + (40000, 40032), # MySQL 4.0 + (40100, 40131), # MySQL 4.1 + (50000, 50096), # MySQL 5.0 + (50100, 50172), # MySQL 5.1 + (50400, 50404), # MySQL 5.4 + (50500, 50558), # MySQL 5.5 + (50600, 50638), # MySQL 5.6 + (50700, 50720), # MySQL 5.7 + (60000, 60014), # MySQL 6.0 + (80000, 80003), # MySQL 8.0 + ) index = -1 for i in xrange(len(versions)): diff --git a/plugins/dbms/mysql/takeover.py b/plugins/dbms/mysql/takeover.py index 4a5173b52..19207ba3e 100644 --- a/plugins/dbms/mysql/takeover.py +++ b/plugins/dbms/mysql/takeover.py @@ -67,10 +67,10 @@ class Takeover(GenericTakeover): # On MySQL 4.1 < 4.1.25 and on MySQL 4.1 >= 4.1.25 with NO plugin_dir set in my.ini configuration file # On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file else: - #logger.debug("retrieving MySQL data directory absolute path") + # logger.debug("retrieving MySQL data directory absolute path") # Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir - #self.__datadir = inject.getValue("SELECT @@datadir") + # self.__datadir = inject.getValue("SELECT @@datadir") # NOTE: specifying the relative path as './udf.dll' # saves in @@datadir on both MySQL 4.1 and MySQL 5.0 diff --git a/plugins/dbms/postgresql/__init__.py b/plugins/dbms/postgresql/__init__.py index bc24a57c2..41683881f 100644 --- a/plugins/dbms/postgresql/__init__.py +++ b/plugins/dbms/postgresql/__init__.py @@ -23,12 +23,12 @@ class PostgreSQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, def __init__(self): self.excludeDbsList = PGSQL_SYSTEM_DBS self.sysUdfs = { - # UDF name: UDF parameters' input data-type and return data-type - "sys_exec": { "input": ["text"], "return": "int4" }, - "sys_eval": { "input": ["text"], "return": "text" }, - "sys_bineval": { "input": ["text"], "return": "int4" }, - "sys_fileread": { "input": ["text"], "return": "text" } - } + # UDF name: UDF parameters' input data-type and return data-type + "sys_exec": {"input": ["text"], "return": "int4"}, + "sys_eval": {"input": ["text"], "return": "text"}, + "sys_bineval": {"input": ["text"], "return": "int4"}, + "sys_fileread": {"input": ["text"], "return": "text"} + } Syntax.__init__(self) Fingerprint.__init__(self) diff --git a/plugins/dbms/postgresql/syntax.py b/plugins/dbms/postgresql/syntax.py index 13129c9e2..3ba144511 100644 --- a/plugins/dbms/postgresql/syntax.py +++ b/plugins/dbms/postgresql/syntax.py @@ -22,6 +22,6 @@ class Syntax(GenericSyntax): """ def escaper(value): - return "(%s)" % "||".join("CHR(%d)" % ord(_) for _ in value) # Postgres CHR() function already accepts Unicode code point of character(s) + return "(%s)" % "||".join("CHR(%d)" % ord(_) for _ in value) # Postgres CHR() function already accepts Unicode code point of character(s) return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/sqlite/connector.py b/plugins/dbms/sqlite/connector.py index ae2722a9a..f214b39a3 100644 --- a/plugins/dbms/sqlite/connector.py +++ b/plugins/dbms/sqlite/connector.py @@ -19,7 +19,6 @@ from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapMissingDependence from plugins.generic.connector import Connector as GenericConnector - class Connector(GenericConnector): """ Homepage: http://pysqlite.googlecode.com/ and http://packages.ubuntu.com/quantal/python-sqlite diff --git a/plugins/dbms/sybase/connector.py b/plugins/dbms/sybase/connector.py index fe1cec52f..36f69ef32 100644 --- a/plugins/dbms/sybase/connector.py +++ b/plugins/dbms/sybase/connector.py @@ -43,6 +43,8 @@ class Connector(GenericConnector): self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout) except (pymssql.Error, _mssql.MssqlDatabaseException), msg: raise SqlmapConnectionException(msg) + except ValueError: + raise SqlmapConnectionException self.initCursor() self.printConnected() diff --git a/plugins/dbms/sybase/enumeration.py b/plugins/dbms/sybase/enumeration.py index 2b5f2d6f3..2432598b7 100644 --- a/plugins/dbms/sybase/enumeration.py +++ b/plugins/dbms/sybase/enumeration.py @@ -176,7 +176,7 @@ class Enumeration(GenericEnumeration): conf.db = self.getCurrentDb() elif conf.db is not None: - if ',' in conf.db: + if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 02fce6b7a..b17ff722a 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -32,6 +32,7 @@ from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries +from lib.core.decorators import stackedmethod from lib.core.dicts import FIREBIRD_TYPES from lib.core.dicts import INFORMIX_TYPES from lib.core.enums import CHARSET_TYPE @@ -400,7 +401,7 @@ class Databases: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.db = conf.db.upper() - if ',' in conf.db: + if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) @@ -663,8 +664,7 @@ class Databases: query += condQuery elif Backend.isDbms(DBMS.MSSQL): - query = rootQuery.blind.count % (conf.db, conf.db, \ - unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) + query = rootQuery.blind.count % (conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): @@ -763,8 +763,7 @@ class Databases: elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): - query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, - conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) + query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column) elif Backend.isDbms(DBMS.INFORMIX): @@ -808,6 +807,7 @@ class Databases: return kb.data.cachedColumns + @stackedmethod def getSchema(self): infoMsg = "enumerating database management system schema" logger.info(infoMsg) @@ -823,10 +823,7 @@ class Databases: 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()]) + infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) else '.', unsafeSQLIdentificatorNaming(_)) for _ in tbl) for db, tbl in kb.data.cachedTables.items()]) logger.info(infoMsg) for db, tables in kb.data.cachedTables.items(): diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 0fab15af1..abf2003bb 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -23,6 +23,7 @@ from lib.core.common import prioritySortColumns from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import singleTimeLogMessage +from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue from lib.core.common import unsafeSQLIdentificatorNaming from lib.core.data import conf @@ -105,6 +106,9 @@ class Entries: tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True) for tbl in tblList: + if kb.dumpKeyboardInterrupt: + break + if conf.exclude and tbl in conf.exclude.split(','): infoMsg = "skipping table '%s'" % unsafeSQLIdentificatorNaming(tbl) singleTimeLogMessage(infoMsg) @@ -181,7 +185,11 @@ class Entries: if not (isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL): table = "%s.%s" % (conf.db, tbl) - if Backend.isDbms(DBMS.MSSQL): + if Backend.isDbms(DBMS.MSSQL) and not conf.forcePivoting: + warnMsg = "in case of table dumping problems (e.g. column entry order) " + warnMsg += "you are advised to rerun with '--force-pivoting'" + singleTimeWarnMessage(warnMsg) + query = rootQuery.blind.count % table query = agent.whereQuery(query) @@ -324,7 +332,11 @@ class Entries: elif Backend.isDbms(DBMS.INFORMIX): table = "%s:%s" % (conf.db, tbl) - if Backend.isDbms(DBMS.MSSQL): + if Backend.isDbms(DBMS.MSSQL) and not conf.forcePivoting: + warnMsg = "in case of table dumping problems (e.g. column entry order) " + warnMsg += "you are advised to rerun with '--force-pivoting'" + singleTimeWarnMessage(warnMsg) + try: indexRange = getLimitRange(count, plusOne=True) @@ -470,7 +482,7 @@ class Entries: if kb.data.cachedTables: if isinstance(kb.data.cachedTables, list): - kb.data.cachedTables = { None: kb.data.cachedTables } + kb.data.cachedTables = {None: kb.data.cachedTables} for db, tables in kb.data.cachedTables.items(): conf.db = db diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index a57548c79..59ca3284e 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -49,7 +49,7 @@ class Filesystem: elif Backend.isDbms(DBMS.MSSQL): self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)") - inject.goStacked("INSERT INTO %s(%s) SELECT %s FROM OPENROWSET(BULK '%s', SINGLE_BLOB) AS %s(%s)" % (self.fileTblName, self.tblField, self.tblField, remoteFile, self.fileTblName, self.tblField)); + inject.goStacked("INSERT INTO %s(%s) SELECT %s FROM OPENROWSET(BULK '%s', SINGLE_BLOB) AS %s(%s)" % (self.fileTblName, self.tblField, self.tblField, remoteFile, self.fileTblName, self.tblField)) lengthQuery = "SELECT DATALENGTH(%s) FROM %s" % (self.tblField, self.fileTblName) diff --git a/sqlmap.py b/sqlmap.py index d8c236da1..4593e715b 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -108,7 +108,6 @@ def checkEnvironment(): for _ in ("SqlmapBaseException", "SqlmapShellQuitException", "SqlmapSilentQuitException", "SqlmapUserQuitException"): globals()[_] = getattr(sys.modules["lib.core.exception"], _) - def main(): """ Main function of sqlmap when running from command line. @@ -265,11 +264,18 @@ def main(): raise SystemExit elif all(_ in excMsg for _ in ("twophase", "sqlalchemy")): - errMsg = "please update the 'sqlalchemy' package" + errMsg = "please update the 'sqlalchemy' package " errMsg += "(Reference: https://github.com/apache/incubator-superset/issues/3447)" logger.error(errMsg) raise SystemExit + elif "must be pinned buffer, not bytearray" in excMsg: + errMsg = "error occurred at Python interpreter which " + errMsg += "is fixed in 2.7.x. Please update accordingly " + errMsg += "(Reference: https://bugs.python.org/issue8104)" + logger.error(errMsg) + raise SystemExit + elif "can't start new thread" in excMsg: errMsg = "there has been a problem while creating new thread instance. " errMsg += "Please make sure that you are not running too many processes" @@ -305,7 +311,7 @@ def main(): logger.error(errMsg) raise SystemExit - elif "valueStack.pop" in excMsg and kb.get("dumpKeyboardInterrupt"): + elif kb.get("dumpKeyboardInterrupt"): raise SystemExit elif any(_ in excMsg for _ in ("Broken pipe",)): diff --git a/tamper/between.py b/tamper/between.py index 57edd5151..e64628f12 100644 --- a/tamper/between.py +++ b/tamper/between.py @@ -55,5 +55,4 @@ def tamper(payload, **kwargs): _ = "%s %s BETWEEN %s AND %s" % (match.group(2), match.group(4), match.group(5), match.group(5)) retVal = retVal.replace(match.group(0), _) - return retVal diff --git a/tamper/ifnull2casewhenisnull.py b/tamper/ifnull2casewhenisnull.py index 5ac14a559..b049d8582 100644 --- a/tamper/ifnull2casewhenisnull.py +++ b/tamper/ifnull2casewhenisnull.py @@ -61,5 +61,3 @@ def tamper(payload, **kwargs): break return payload - - diff --git a/thirdparty/colorama/winterm.py b/thirdparty/colorama/winterm.py index 60309d3c0..b7c2404b7 100644 --- a/thirdparty/colorama/winterm.py +++ b/thirdparty/colorama/winterm.py @@ -128,6 +128,8 @@ class WinTerm(object): elif mode == 2: from_coord = win32.COORD(0, 0) cells_to_erase = cells_in_screen + else: + return # fill the entire screen with blanks win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) # now set the buffer's attributes accordingly @@ -153,6 +155,8 @@ class WinTerm(object): elif mode == 2: from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) cells_to_erase = csbi.dwSize.X + else: + return # fill the entire screen with blanks win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) # now set the buffer's attributes accordingly diff --git a/txt/checksum.md5 b/txt/checksum.md5 index f0ce097f4..791ab9c5a 100644 --- a/txt/checksum.md5 +++ b/txt/checksum.md5 @@ -5,7 +5,7 @@ b0eb597c613afeff9d62898cf4c67a56 extra/cloak/cloak.py e0911386106b95d2ba4b12d651b2eb16 extra/dbgtool/dbgtool.py 1e5532ede194ac9c083891c2f02bca93 extra/dbgtool/__init__.py acba8b5dc93db0fe6b2b04ff0138c33c extra/icmpsh/icmpsh.exe_ -2176d964f2d5ba2d871383d6a1868b8f extra/icmpsh/icmpsh_m.py +fe39e5c315d63afff5cb99ec42fc883f extra/icmpsh/icmpsh_m.py 2d020d2bdcee1170805f48839fdb89df extra/icmpsh/__init__.py 1e5532ede194ac9c083891c2f02bca93 extra/__init__.py 27629e01ba722271c990ad4b27151917 extra/mssqlsig/update.py @@ -16,163 +16,164 @@ d229479d02d21b29f209143cb0547780 extra/shellcodeexec/linux/shellcodeexec.x32_ 2fe2f94eebc62f7614f0391a8a90104f extra/shellcodeexec/linux/shellcodeexec.x64_ c55b400b72acc43e0e59c87dd8bb8d75 extra/shellcodeexec/windows/shellcodeexec.x32.exe_ 220745c50d375dad7aefebf8ca3611ef extra/shutils/duplicates.py +1f33abe1a67493909d29a35ca72ecedb extra/shutils/newlines.py 71b9d4357c31db013ecda27433830090 extra/shutils/pylint.py c88d66597f4aab719bde4542b0a1a6e0 extra/shutils/regressiontest.py 1e5532ede194ac9c083891c2f02bca93 extra/sqlharvest/__init__.py b3e60ea4e18a65c48515d04aab28ff68 extra/sqlharvest/sqlharvest.py 0f581182871148b0456a691ae85b04c0 lib/controller/action.py -a4605691d340fd05d4bfe7dde922da92 lib/controller/checks.py -9fbd66da9b5cf58bbb8474ccf9252bb7 lib/controller/controller.py -a7b0c8e5a18a3abe8803999dcfc4664f lib/controller/handler.py +a0ae21cc46b8f5fd0afe0a173ceaab70 lib/controller/checks.py +c414cecdb0472c92cf50ed5b01e4438c lib/controller/controller.py +c7443613a0a2505b1faec931cee2a6ef lib/controller/handler.py 1e5532ede194ac9c083891c2f02bca93 lib/controller/__init__.py -e3a3f5218b2e52dd0afafdfc9fed2002 lib/core/agent.py -86a4703d5474badd8462146510b2c460 lib/core/bigarray.py -863d9c00a7684db29005705d6dcc36b9 lib/core/common.py -2a40d5b5997265daa890545d4a4a59b9 lib/core/convert.py +b1990c7805943f0c973a853bba981d96 lib/core/agent.py +fd8f239e259afaf5f24bcf34a0ad187f lib/core/bigarray.py +f42e346d33199b4f663cff6efe2be775 lib/core/common.py +0d082da16c388b3445e656e0760fb582 lib/core/convert.py 9f87391b6a3395f7f50830b391264f27 lib/core/data.py 72016ea5c994a711a262fd64572a0fcd lib/core/datatype.py -12e80071013606f01822c3823fb51054 lib/core/decorators.py -9458679feb9184f3fb1611daf1ebef63 lib/core/defaults.py -a8bea09096a42a9a7feeb9d4d118ae66 lib/core/dicts.py -0d742fbf72bca25a3e82640616c30c9a lib/core/dump.py -c8551f7696a76450e6d139409e4f06cd lib/core/enums.py +93567739d591829c1fb9ff77a50bcc87 lib/core/decorators.py +fbb55cc6100318ff922957b6577dc58f lib/core/defaults.py +da98f5288aad57855c6d287ba3b397a1 lib/core/dicts.py +9ea8a043030796e6faef7f7e957729d5 lib/core/dump.py +bfffdc74a93ff647c49b79c215d96d8a lib/core/enums.py cada93357a7321655927fc9625b3bfec lib/core/exception.py 1e5532ede194ac9c083891c2f02bca93 lib/core/__init__.py 458a194764805cd8312c14ecd4be4d1e lib/core/log.py -63ac6631d75e4f7c20b946a0c06bad33 lib/core/optiondict.py -a377168b153725d3677924040b7861f4 lib/core/option.py -7dadbb9a301d40cc8cd9c7491e99b43d lib/core/profiling.py -ffa5f01f39b17c8d73423acca6cfe86a lib/core/readlineng.py +c9a56e58984420a5abb7a3f7aadc196d lib/core/optiondict.py +83345a6b0b7e187d2cbcc280a509f03e lib/core/option.py +7cfd04e583cca782b843f6f6d973981a lib/core/profiling.py +6f654e1715571eff68a0f8af3d62dcf8 lib/core/readlineng.py 0c3eef46bdbf87e29a3f95f90240d192 lib/core/replication.py a7db43859b61569b601b97f187dd31c5 lib/core/revision.py fcb74fcc9577523524659ec49e2e964b lib/core/session.py -9fde692b6fa94718d5fbe8f804e4edde lib/core/settings.py -d0adc28a38e43a787df4471f7f027413 lib/core/shell.py -63491be462c515a1a3880c27c2acc4a2 lib/core/subprocessng.py -505aaa61e1bba3c3d4567c3e667699e3 lib/core/target.py +8a8b9515cd98eb1e1b0701baf84e9d35 lib/core/settings.py +0dfc2ed40adf72e302291f6ecd4406f6 lib/core/shell.py +a7edc9250d13af36ac0108f259859c19 lib/core/subprocessng.py +6306284edcccc185b2df085438572b0d lib/core/target.py 72d499ca8d792e90a1ebfb2ad2341a51 lib/core/testing.py de9922a29c71a235cb95a916ff925db2 lib/core/threads.py c40758411bb0bd68764d78e0bb72bd0f lib/core/unescaper.py -063c10fb8261994fe1f8c8ace715aa76 lib/core/update.py -fc624104ddb36d41794b7a943fde5f21 lib/core/wordlist.py +af2d1810b6a7ebc61689a53c253ddbaa lib/core/update.py +e772deb63270375e685fa5a7b775c382 lib/core/wordlist.py 1e5532ede194ac9c083891c2f02bca93 lib/__init__.py 7620f1f4b8791e13c7184c06b5421754 lib/parse/banner.py -27c4d3e568d199e01d1cffd37b370516 lib/parse/cmdline.py +5e46fac7f824ba8ab8003a1cd47d8af3 lib/parse/cmdline.py fb2e2f05dde98caeac6ccf3e67192177 lib/parse/configfile.py 3794ff139869f5ae8e81cfdbe5714f56 lib/parse/handler.py -263ee1cec41facd2a06d0dc887b207ad lib/parse/headers.py +6bab53ea9d75bc9bb8169d3e8f3f149f lib/parse/headers.py 33f21b11b7963062df8fa2292229df80 lib/parse/html.py 1e5532ede194ac9c083891c2f02bca93 lib/parse/__init__.py -307d4001682f38dd574548d98c0f1c3e lib/parse/payloads.py -38563853a32dd677ce6c65a0945d7227 lib/parse/sitemap.py -4e60fe7c94bbfa631087ed3426df8ef0 lib/request/basicauthhandler.py -eb39d5cbd69a2238e2f4ea2fde183cdb lib/request/basic.py +ec4e56bbb1349176b2a22e0b99ba6a55 lib/parse/payloads.py +492654567e72b6a14584651fcd9f16e6 lib/parse/sitemap.py +30eed3a92a04ed2c29770e1b10d39dc0 lib/request/basicauthhandler.py +596988f14408cde1a2d3b5c9f231873a lib/request/basic.py c0cabedead14b8a23353b606672cff42 lib/request/comparison.py -6b70d287ed2508ffc66b37994d5ffca5 lib/request/connect.py +e9bbba4a133effeae86d146286f9116b lib/request/connect.py dd4598675027fae99f2e2475b05986da lib/request/direct.py 2044fce3f4ffa268fcfaaf63241b1e64 lib/request/dns.py -a1436e4e4f9b636cb8332f00b686bfd5 lib/request/httpshandler.py +eee965d781546d05f36cfd14af050913 lib/request/httpshandler.py 1e5532ede194ac9c083891c2f02bca93 lib/request/__init__.py -bee0a8bec4968406e93281d2b8ad62c8 lib/request/inject.py +b188a11542a996276abbbc48913501c3 lib/request/inject.py aaf956c1e9855836c3f372e29d481393 lib/request/methodrequest.py 51eeaa8abf5ba62aaaade66d46ff8b00 lib/request/pkihandler.py aa7cb67139bbc57d67a728fd2abf80ed lib/request/rangehandler.py aa809d825b33bea76a63ecd97cf7792c lib/request/redirecthandler.py -bbfe91128ab3ad65343ed449936a890b lib/request/templates.py -edfd88ee82c2b2a0a762dad1f4eb5253 lib/takeover/abstraction.py +7f12d8f3b6665ed7053954bba70ff718 lib/request/templates.py +747f9941a68361bd779ec760f71568e9 lib/takeover/abstraction.py acc1db3667bf910b809eb279b60595eb lib/takeover/icmpsh.py 1e5532ede194ac9c083891c2f02bca93 lib/takeover/__init__.py -703e15714316a8cc4bbe54cdd0a8cb87 lib/takeover/metasploit.py -0fc9b00596df21c8878ef92f513ecad7 lib/takeover/registry.py +46ff5840b29531412bcaa05dac190413 lib/takeover/metasploit.py +fb9e34d558293b5d6b9727f440712886 lib/takeover/registry.py 48575dde7bb867b7937769f569a98309 lib/takeover/udf.py -746f400dfa6dc1139f14c44574d6b948 lib/takeover/web.py -d8c10f278e5943b137a222f4cedca59d lib/takeover/xp_cmdshell.py -b84d45fc7349caa714f9769b13d70cab lib/techniques/blind/inference.py +2665fa7eedb19a1b10ffe949999b75f1 lib/takeover/web.py +f1decf0a987bd3a4bc757212cbe6a6c8 lib/takeover/xp_cmdshell.py +2543e14cc7f6e239b49dd40f41bc34fa lib/techniques/blind/inference.py 1e5532ede194ac9c083891c2f02bca93 lib/techniques/blind/__init__.py 1e5532ede194ac9c083891c2f02bca93 lib/techniques/dns/__init__.py -855355a1a216f6b267a5f089028f1cd8 lib/techniques/dns/test.py -733f3419ff2ea23f75bc24e36f4746d9 lib/techniques/dns/use.py +799faf9008527d2e9da9d923e50f685a lib/techniques/dns/test.py +bad83c6386adf345fbc982bdafbe3b93 lib/techniques/dns/use.py 1e5532ede194ac9c083891c2f02bca93 lib/techniques/error/__init__.py -627ddc86a5a969e5509c7531c5c27a6c lib/techniques/error/use.py +f999f2e88dea9ac8831eb2f468478b5f lib/techniques/error/use.py 1e5532ede194ac9c083891c2f02bca93 lib/techniques/__init__.py 1e5532ede194ac9c083891c2f02bca93 lib/techniques/union/__init__.py -e58ab8029ffb2cc37e42d68747c4da39 lib/techniques/union/test.py -6c3c4c7d43ad75e61a73184323a81eac lib/techniques/union/use.py -e4146464cf968d4015a52cb8c10e3da5 lib/utils/api.py +a36be917cf86a5ee407c83d74567f324 lib/techniques/union/test.py +11ecf2effbe9f40b361843d546c3c521 lib/techniques/union/use.py +8d99c07416df40350ff8836d9d79ebb5 lib/utils/api.py 37dfb641358669f62c2acedff241348b lib/utils/brute.py -a34c4fd2e7d78c5dfdd9eeccb079fb1c lib/utils/crawler.py -69c25da85a3a71a9798804075cdfd62b lib/utils/deps.py -a6d6888e14a7c11f0884c8cc18489caa lib/utils/getch.py +31b1e7eb489eac837db6a2bc1dcb7da7 lib/utils/crawler.py +de9620f03231d8329ee8434884b6bacd lib/utils/deps.py +f7af65aa47329d021e2b2cc8521b42a4 lib/utils/getch.py 7af29f61302c8693cd6436d4b69e22d3 lib/utils/har.py -9bd8fbfb9c25ee685c97b260331e7165 lib/utils/hashdb.py -55c552e754b54cd25a47efb84d3e6892 lib/utils/hash.py -145120b21fcfca843d5e2c8b0562e4db lib/utils/htmlentities.py +062e4e8fc43ac54305a75ddd0d482f81 lib/utils/hashdb.py +cc1cfe36057f1d9bbdcba1bcc03359f9 lib/utils/hash.py +011d2dbf589e0faa0deca61a651239cc lib/utils/htmlentities.py 1e5532ede194ac9c083891c2f02bca93 lib/utils/__init__.py 010d8327239d33af4ce9f25683cfc012 lib/utils/pivotdumptable.py -5d6d73d27833eef1b10b9215629533ff lib/utils/progress.py +5cb78b0e60fd7fd84502d62cf85d2064 lib/utils/progress.py 0ec5cec9d93d5ffd1eaeda6e942ecadf lib/utils/purge.py -4a6886d3a0c7bf768df97738fa257de9 lib/utils/search.py -4b17311256f0081904a67831252e3fb9 lib/utils/sqlalchemy.py +2c5a655c8e94cbe2664ee497752ac1f2 lib/utils/search.py +236a8d9e596602b53f8e0aa09c30c0ef lib/utils/sqlalchemy.py dcc25183c6bd85b172c87cfcbc305ab6 lib/utils/timeout.py -ce5ec6300bc0a185827a21d8a8f09de3 lib/utils/versioncheck.py -1e9cf437451ff8147a372a002641b963 lib/utils/xrange.py +3d230e342a6c8d60ac7c68c556fbba9b lib/utils/versioncheck.py +7348ee704485651737ddbe3538271be9 lib/utils/xrange.py b9d2761f47fec3d98b88311a263fd5db plugins/dbms/access/connector.py 3f1c50a1507d1c2f69c20c706230e2e2 plugins/dbms/access/enumeration.py fcc66fc377db3681f7890ec55675564b plugins/dbms/access/filesystem.py -47a9c7a39ad179b73a9d6f0e1f269f74 plugins/dbms/access/fingerprint.py +c2428c5c73d049abf4442ec1b9404a25 plugins/dbms/access/fingerprint.py e657b1b7a295a38ac9ce515158164f00 plugins/dbms/access/__init__.py 77686d7c7e287d5db0a9a87f2c7d4902 plugins/dbms/access/syntax.py 2f1d8706b51497623b2b59c07b552bdc plugins/dbms/access/takeover.py -0cf941076f4685ec8ac63f57b31a46a6 plugins/dbms/db2/connector.py -0884e475c98701f8e698150aa122fb76 plugins/dbms/db2/enumeration.py +ead470b613e52e718a3062b63b518272 plugins/dbms/db2/connector.py +4deeda463003ab71e7d2f34a263b5bbf plugins/dbms/db2/enumeration.py da9dccd1f9ec2cf1e53295125dd983a0 plugins/dbms/db2/filesystem.py -a660e74854f3c70606f1cc3bc450fbcc plugins/dbms/db2/fingerprint.py +b54dbf44590a5cbefb2b4f8e9a01a383 plugins/dbms/db2/fingerprint.py 95b35cbd859bbced44e7f8fd84486d75 plugins/dbms/db2/__init__.py 82d96d8fcfd565129580260040555623 plugins/dbms/db2/syntax.py 25f0fb28e9defcab48a2e946fbb7550a plugins/dbms/db2/takeover.py -4a941e7f39dc098ee489eeacc720a8cc plugins/dbms/firebird/connector.py +53bd7de27d37958f543f5329362ac298 plugins/dbms/firebird/connector.py bc4d71116d7296d63894484f2e60ade2 plugins/dbms/firebird/enumeration.py c3ca81000200e5ab4210e9bf2e04ce93 plugins/dbms/firebird/filesystem.py -94a86678fd2bf6bff6c3439934f59277 plugins/dbms/firebird/fingerprint.py +bd2159afbe83c70059f57712b4ae0189 plugins/dbms/firebird/fingerprint.py d4ea3036492b8ae15340548b2936021f plugins/dbms/firebird/__init__.py c56f2dabe88fd761a1a9a51e4d104088 plugins/dbms/firebird/syntax.py 1522a29bd4b54ea78bb2855fc32b6c72 plugins/dbms/firebird/takeover.py -61225f674e64bc6eafea140c4cf93deb plugins/dbms/hsqldb/connector.py +271a7f16e781d56a0a31a3d5515a1945 plugins/dbms/hsqldb/connector.py 95919592e5bb83df00b99bb9e8a70977 plugins/dbms/hsqldb/enumeration.py 616595e74ecb644271cbbd31815d92e0 plugins/dbms/hsqldb/filesystem.py -b207e728934f768732852c1928c38483 plugins/dbms/hsqldb/fingerprint.py +b7d693a6f5f39fee0a65f2d7b0830c5e plugins/dbms/hsqldb/fingerprint.py fd369161778d6b48d7f1f7fc14dcdb5c plugins/dbms/hsqldb/__init__.py 4673ebfdce9859718c19e8a7765da8d3 plugins/dbms/hsqldb/syntax.py 7c0535736215ca612756cf589adb249b plugins/dbms/hsqldb/takeover.py -5fca2136204e0ea432cc7a2572244a20 plugins/dbms/informix/connector.py +9ceb9430031a26ecebe13ea49cb2a5fa plugins/dbms/informix/connector.py c54d70e4847c6327bd3110c4d8723b04 plugins/dbms/informix/enumeration.py da9dccd1f9ec2cf1e53295125dd983a0 plugins/dbms/informix/filesystem.py 35eac2f3837a72940eb50753dc4566e5 plugins/dbms/informix/fingerprint.py 9dac94c8f76acf0be65b6c57ecdb5c34 plugins/dbms/informix/__init__.py -39dc5c088b4d37742290acc76c47fe94 plugins/dbms/informix/syntax.py +aa77fec4fe6b2d7ca4a91aebd9ff4e21 plugins/dbms/informix/syntax.py 25f0fb28e9defcab48a2e946fbb7550a plugins/dbms/informix/takeover.py 1e5532ede194ac9c083891c2f02bca93 plugins/dbms/__init__.py 6917f9b045f6188b89e816dea9b46a3f plugins/dbms/maxdb/connector.py -615be11d750530211af244b6ca6aef14 plugins/dbms/maxdb/enumeration.py +f33efaab1695dc9885ebae3f6072fffa plugins/dbms/maxdb/enumeration.py ffd26f64142226d0b1ed1d70f7f294c0 plugins/dbms/maxdb/filesystem.py 9f9f1c4c4c3150545c4b61d1cffc76a8 plugins/dbms/maxdb/fingerprint.py 4321d7018f5121343460ebfd83bb69be plugins/dbms/maxdb/__init__.py e7d44671ae26c0bcd5fe8448be070bbd plugins/dbms/maxdb/syntax.py bf7842bb291e2297c3c8d1023eb3e550 plugins/dbms/maxdb/takeover.py -6439d15c1e8cdb069056c4fa725326df plugins/dbms/mssqlserver/connector.py -a833fbc30ab1133bc6ba293d97d0ef7c plugins/dbms/mssqlserver/enumeration.py -7e495d786fa8e1da96e73e2905bbd7dd plugins/dbms/mssqlserver/filesystem.py -03d463c15ebbfa4e49155b261b59db31 plugins/dbms/mssqlserver/fingerprint.py -affef90b1442285da7e89e46603c502e plugins/dbms/mssqlserver/__init__.py +9e64e67291a4c369bad8b8cf2cfa722a plugins/dbms/mssqlserver/connector.py +f1f1541a54faf67440179fa521f99849 plugins/dbms/mssqlserver/enumeration.py +177e1d55d28ed3190bc0079b8126c6be plugins/dbms/mssqlserver/filesystem.py +51eb413ac62408965be20a812f2412c8 plugins/dbms/mssqlserver/fingerprint.py +f25c50a95e5390ecd32be5a011637349 plugins/dbms/mssqlserver/__init__.py 612be1929108e7b4512a49a4a3837bbc plugins/dbms/mssqlserver/syntax.py -b9e62a80bd3ead133a511f9769e5e6c3 plugins/dbms/mssqlserver/takeover.py +08fe8ac7acdfc0e3168b5b069a7c73bf plugins/dbms/mssqlserver/takeover.py f6e1f3f09f32b9cb2ca11c016d373423 plugins/dbms/mysql/connector.py 445164daf59b890aeacc968af58fcb53 plugins/dbms/mysql/enumeration.py -f36e09edc3eafedd989fbe44ec048e71 plugins/dbms/mysql/filesystem.py -2bfd2369aebe2999f7333cca0895507c plugins/dbms/mysql/fingerprint.py -88b876f085fec2569a0697f4b69f41da plugins/dbms/mysql/__init__.py +4578fa29f04d0a75499f9668466ded07 plugins/dbms/mysql/filesystem.py +fcbf7ff279c527b4aca0dac94c28d20c plugins/dbms/mysql/fingerprint.py +30065993f8300994e4658634121609e9 plugins/dbms/mysql/__init__.py 0e2adbee217f5b94dcc124d24b8dde99 plugins/dbms/mysql/syntax.py -f30009816db6a0b41342301f0d657a01 plugins/dbms/mysql/takeover.py +403591e638b6bfdb840d52bd3138ee56 plugins/dbms/mysql/takeover.py 999cb8d0d52820d30bdd4b3d658a765d plugins/dbms/oracle/connector.py e1ffee36fd18f33f34bb4bac4ae43f14 plugins/dbms/oracle/enumeration.py c326b0d8bed92be67888b0242f565ac8 plugins/dbms/oracle/filesystem.py @@ -184,18 +185,18 @@ f99c23db4ee6a6b8c0edbf684d360ad3 plugins/dbms/postgresql/connector.py 7cdb821884e5f15084d1bea7f8a50574 plugins/dbms/postgresql/enumeration.py c8bb829d45752b98e6a03817b92e0fe5 plugins/dbms/postgresql/filesystem.py 603d533d924498378eccba4f0f196be6 plugins/dbms/postgresql/fingerprint.py -4fe6dcf2b43b6dac46f31d75e9de260d plugins/dbms/postgresql/__init__.py -c8c2d660977e3e07182e7cdf31aa786a plugins/dbms/postgresql/syntax.py +470860d3e85d11a67f2220bffaa415e7 plugins/dbms/postgresql/__init__.py +20e6f48f496348be45f3402ebc265dbb plugins/dbms/postgresql/syntax.py 1287acf330da86a93c8e64aff46e3b65 plugins/dbms/postgresql/takeover.py -3009438ba259ca159c5ce9799f27dec1 plugins/dbms/sqlite/connector.py +80a2083a4fb7809d310c3d5ecc94e3c5 plugins/dbms/sqlite/connector.py 5194556e6b1575b1349f8ccfd773952b plugins/dbms/sqlite/enumeration.py 90fa97b84998a01dba7cc8c3329a1223 plugins/dbms/sqlite/filesystem.py ed52c198f3346ceabdef676e9f5d3c0f plugins/dbms/sqlite/fingerprint.py f639120d42b33b6ca67930bddbf2ac1f plugins/dbms/sqlite/__init__.py 964e59d2eba619b068b0a15cea28efe0 plugins/dbms/sqlite/syntax.py 3364b2938d7040c507cd622c323557dc plugins/dbms/sqlite/takeover.py -6439d15c1e8cdb069056c4fa725326df plugins/dbms/sybase/connector.py -31462dc5a1cd2a1b4eba6762d18fb48c plugins/dbms/sybase/enumeration.py +9e64e67291a4c369bad8b8cf2cfa722a plugins/dbms/sybase/connector.py +426698152f63504061e5875e64957691 plugins/dbms/sybase/enumeration.py 74de450dd6d6d006aa9c7eed56e6b09a plugins/dbms/sybase/filesystem.py c8ee0deaa2309e96d9a409ff1524f3ad plugins/dbms/sybase/fingerprint.py a3db8618eed5bb2807b6f77605cba9cc plugins/dbms/sybase/__init__.py @@ -203,10 +204,10 @@ a3db8618eed5bb2807b6f77605cba9cc plugins/dbms/sybase/__init__.py 79f6c7017db4ded8f74a0117188836ff plugins/dbms/sybase/takeover.py 34d181a7086d6dfc7e72ae5f8a4cfe0f plugins/generic/connector.py e6cd1c5a5244d83396b401f7db43d323 plugins/generic/custom.py -554f925e0a66f62b8ba39dd6c95d1e7f plugins/generic/databases.py -764a8fd5a99224910885c6b94a592170 plugins/generic/entries.py +79c6dbcb7e6ad5e993a44aa52fdc36ed plugins/generic/databases.py +4e2b366bb9cfdaaed719b219913357c6 plugins/generic/entries.py d82f2c78c1d4d7c6487e94fd3a68a908 plugins/generic/enumeration.py -ea0f3b9085061b272bfd98c13ad2d977 plugins/generic/filesystem.py +0c8abe66a78edca0660bfb8049d109e2 plugins/generic/filesystem.py f5d5419efddfe04648ea5e953c650793 plugins/generic/fingerprint.py 1e5532ede194ac9c083891c2f02bca93 plugins/generic/__init__.py f7874230e5661910d5fd21544c7d1022 plugins/generic/misc.py @@ -224,12 +225,12 @@ ec2ba8c757ac96425dcd2b97970edd3a shell/stagers/stager.asp_ 0c48ddb1feb7e38a951ef05a0d48e032 shell/stagers/stager.jsp_ 2f9e459a4cf6a58680978cdce5ff7971 shell/stagers/stager.php_ 4eaeef94314956e4517e5310a28d579a sqlmapapi.py -082aa29ab77c647a0d3830c07279d437 sqlmap.py +e585626909b2de432f1fb71e0944b130 sqlmap.py 4c3b8a7daa4bff52e01d4168be0eedbe tamper/apostrophemask.py 4115a55b8aba464723d645b7d3156b6e tamper/apostrophenullencode.py d7e9a979eff4d7315d804a181e66fc93 tamper/appendnullbyte.py 0298d81e9dfac7ff18a5236c0f1d84b6 tamper/base64encode.py -55e9fbe57967e57a05a8ca77c312dc70 tamper/between.py +4d44f868c6c97ced29e306347ce5d650 tamper/between.py e1d2329adc6ca89828a2eaec2951806c tamper/bluecoat.py e3cdf13caedb4682bee3ff8fac103606 tamper/chardoubleencode.py 3b2f68476fbcf8223199e8dd4ec14b64 tamper/charencode.py @@ -244,7 +245,7 @@ dcdc433fe946f1b9005bcd427a951dd6 tamper/equaltolike.py 4393cc5220d2e39c5c9c5a9af4e2635d tamper/greatest.py 25ec62158d3e289bda8a04c8b65686ba tamper/halfversionedmorekeywords.py 9d8c350cbb90d4b21ec9c9db184a213a tamper/htmlencode.py -838212f289632526777b7224bf8aacf9 tamper/ifnull2casewhenisnull.py +3f79551baf811ff70b2ba8795a2064be tamper/ifnull2casewhenisnull.py e2c2b6a67546b36983a72f129a817ec0 tamper/ifnull2ifisnull.py 91c92ee203e7e619cb547643883924ca tamper/informationschemacomment.py 1e5532ede194ac9c083891c2f02bca93 tamper/__init__.py @@ -333,7 +334,7 @@ bcae4c645a737d3f0e7c96a66528ca4a thirdparty/chardet/universaldetector.py ed4d76c08741d34ac79f6488663345f7 thirdparty/colorama/initialise.py c0707ca77ccb4a2c0f12b4085057193c thirdparty/colorama/__init__.py ad3d022d4591aee80f7391248d722413 thirdparty/colorama/win32.py -c690e140157d0caac5824c73688231b3 thirdparty/colorama/winterm.py +cdd682cbf77137ef4253b77a95ed9bd8 thirdparty/colorama/winterm.py be7eac2e6cfb45c5e297ec5eee66e747 thirdparty/fcrypt/fcrypt.py e00542d22ffa8d8ac894c210f38454be thirdparty/fcrypt/__init__.py 2f94ddd6ada38e4091e819568e7c4b7c thirdparty/gprof2dot/gprof2dot.py @@ -364,8 +365,8 @@ a44e7cf30f2189b2fbdb635b310cdc0c thirdparty/wininetpton/win_inet_pton.py 593473084228b63a12318d812e50f1e2 thirdparty/xdot/xdot.py 08c706478fad0acba049d0e32cbb6411 udf/mysql/linux/32/lib_mysqludf_sys.so_ 1501fa7150239b18acc0f4a9db2ebc0d udf/mysql/linux/64/lib_mysqludf_sys.so_ -7824059e8fc87c4a565e774676e2f1eb udf/mysql/windows/32/lib_mysqludf_sys.dll_ -7fed5b8e99e36ce255c64527ec61a995 udf/mysql/windows/64/lib_mysqludf_sys.dll_ +70d83edb90c4a20bd95eb62f71c99bd0 udf/mysql/windows/32/lib_mysqludf_sys.dll_ +15aaa93872ca87366065568375ad8eb1 udf/mysql/windows/64/lib_mysqludf_sys.dll_ 0ee1310d4e2a4cc5a7295df01a3a78bf udf/postgresql/linux/32/8.2/lib_postgresqludf_sys.so_ c7d9e1fcac5f047edf17d79a825fb64b udf/postgresql/linux/32/8.3/lib_postgresqludf_sys.so_ ec41a080f4570c3866b9a7219f7623c4 udf/postgresql/linux/32/8.4/lib_postgresqludf_sys.so_ @@ -427,7 +428,7 @@ ad7fe23004f8e0d02534c7baa877add3 waf/paloalto.py 166eb53544536e3e86223d513b8b688d waf/proventia.py 78a40eca7ddd14c4eaf911de7748b487 waf/radware.py f5d53758d2008195609557112ce8e895 waf/requestvalidationmode.py -022956799ff08db1a39fe1484d949e54 waf/safe3.py +acb82b21f4032ceb510a58142add02ab waf/safe3.py 67cdf508e7b1f69ddf622a87e0e5e4e8 waf/safedog.py d1b67820442199181815ec3fce27e582 waf/secureiis.py 34f0ec775835744bed601ef7c7a21c9d waf/senginx.py @@ -450,14 +451,14 @@ a687449cd4e45f69e33b13d41e021480 waf/uspses.py 68e332530fab216d017ede506c3fec2f waf/yundun.py bea35ba732ccc9548e6c4023cea6832b waf/yunsuo.py 705ac8663513c12150cb5623ef4a04fb waf/zenedge.py -e87d59af23b7b18cd56c9883e5f02d5c xml/banner/generic.xml +dc394c5b90ada0a5d5853b5ad1f7d56d xml/banner/generic.xml d8925c034263bf1b83e7d8e1c78eec57 xml/banner/mssql.xml -b8b56f4aa34bf65365808919b97119a7 xml/banner/mysql.xml +7b21aeb3ad66d7686eacd23a6346292c xml/banner/mysql.xml 9b262a617b06af56b1267987d694bf6f xml/banner/oracle.xml -d90fe5a47b95dff3eb1797764c9db6c5 xml/banner/postgresql.xml -b07b5c47c751787e136650ded060197f xml/banner/server.xml +c26cd4fa986ddc9f6d92dd87c8fc61cb xml/banner/postgresql.xml +4970709ca31bcaea5eb79547a132606a xml/banner/server.xml d48c971769c6131e35bd52d2315a8d58 xml/banner/servlet-engine.xml -2d53fdaca0d7b42edad5192661248d76 xml/banner/set-cookie.xml +58be20a3b29a9108d043786907700469 xml/banner/set-cookie.xml d989813ee377252bca2103cea524c06b xml/banner/sharepoint.xml 350605448f049cd982554123a75f11e1 xml/banner/x-aspnet-version.xml 817078783e1edaa492773d3b34d8eef0 xml/banner/x-powered-by.xml @@ -470,4 +471,4 @@ b5b8b0aebce810e6cdda1b7106c96427 xml/payloads/error_based.xml 3194e2688a7576e1f877d5b137f7c260 xml/payloads/stacked_queries.xml c2d8dd03db5a663e79eabb4495dd0723 xml/payloads/time_blind.xml ac649aff0e7db413e4937e446e398736 xml/payloads/union_query.xml -775ed5c7e1340f76f17f6186abbd8c92 xml/queries.xml +186808373a45316a45ad5f6ca8d90ff3 xml/queries.xml diff --git a/udf/mysql/windows/32/lib_mysqludf_sys.dll_ b/udf/mysql/windows/32/lib_mysqludf_sys.dll_ index ae438d636..22a114220 100644 Binary files a/udf/mysql/windows/32/lib_mysqludf_sys.dll_ and b/udf/mysql/windows/32/lib_mysqludf_sys.dll_ differ diff --git a/udf/mysql/windows/64/lib_mysqludf_sys.dll_ b/udf/mysql/windows/64/lib_mysqludf_sys.dll_ index c06f77f22..3641746f1 100644 Binary files a/udf/mysql/windows/64/lib_mysqludf_sys.dll_ and b/udf/mysql/windows/64/lib_mysqludf_sys.dll_ differ diff --git a/waf/safe3.py b/waf/safe3.py index 2aa468099..2d4a294c0 100644 --- a/waf/safe3.py +++ b/waf/safe3.py @@ -23,4 +23,3 @@ def detect(get_page): break return retval - diff --git a/xml/banner/generic.xml b/xml/banner/generic.xml index eb97b1d88..27e8bdd86 100644 --- a/xml/banner/generic.xml +++ b/xml/banner/generic.xml @@ -27,6 +27,10 @@ + + + + diff --git a/xml/banner/mysql.xml b/xml/banner/mysql.xml index 5ac157302..b637ebb92 100644 --- a/xml/banner/mysql.xml +++ b/xml/banner/mysql.xml @@ -35,6 +35,22 @@ + + + + + + + + + + + + + + + + diff --git a/xml/banner/postgresql.xml b/xml/banner/postgresql.xml index 4c64844d7..7f03e8e8c 100644 --- a/xml/banner/postgresql.xml +++ b/xml/banner/postgresql.xml @@ -13,13 +13,4 @@ - - - - - - - - - diff --git a/xml/banner/server.xml b/xml/banner/server.xml index 48f0ab158..737a13f14 100644 --- a/xml/banner/server.xml +++ b/xml/banner/server.xml @@ -89,6 +89,10 @@ + + + + @@ -155,8 +159,8 @@ - - + + @@ -273,6 +277,22 @@ + + + + + + + + + + + + + + + + @@ -379,6 +399,14 @@ + + + + + + + + @@ -678,6 +706,14 @@ + + + + + + + + @@ -753,7 +789,15 @@ - + + + + + + + + + @@ -761,4 +805,10 @@ + + + + + + diff --git a/xml/banner/set-cookie.xml b/xml/banner/set-cookie.xml index c9e34d2ce..4e85296b8 100644 --- a/xml/banner/set-cookie.xml +++ b/xml/banner/set-cookie.xml @@ -11,7 +11,7 @@ - + diff --git a/xml/queries.xml b/xml/queries.xml index 1610a19a8..cbd407d47 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -14,7 +14,7 @@ - +