From d739d5062d52ab1c529829ee730e248397db73e2 Mon Sep 17 00:00:00 2001 From: Meatballs Date: Mon, 24 Jun 2013 14:34:25 +0100 Subject: [PATCH] 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)