From d5fab1907dd691f9e88ac45963b6bef85453e28f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 16:59:02 +0100 Subject: [PATCH] Adding support for Presto --- data/xml/errors.xml | 8 ++ data/xml/queries.xml | 62 +++++++++++++ lib/controller/handler.py | 82 +++++++++-------- lib/core/agent.py | 4 +- lib/core/common.py | 6 +- lib/core/dicts.py | 2 + lib/core/enums.py | 2 + lib/core/settings.py | 8 +- lib/utils/deps.py | 2 + plugins/dbms/presto/__init__.py | 30 +++++++ plugins/dbms/presto/connector.py | 70 +++++++++++++++ plugins/dbms/presto/enumeration.py | 58 ++++++++++++ plugins/dbms/presto/filesystem.py | 18 ++++ plugins/dbms/presto/fingerprint.py | 137 +++++++++++++++++++++++++++++ plugins/dbms/presto/syntax.py | 22 +++++ plugins/dbms/presto/takeover.py | 28 ++++++ plugins/generic/databases.py | 12 +-- plugins/generic/entries.py | 4 +- 18 files changed, 500 insertions(+), 55 deletions(-) create mode 100644 plugins/dbms/presto/__init__.py create mode 100644 plugins/dbms/presto/connector.py create mode 100644 plugins/dbms/presto/enumeration.py create mode 100644 plugins/dbms/presto/filesystem.py create mode 100644 plugins/dbms/presto/fingerprint.py create mode 100644 plugins/dbms/presto/syntax.py create mode 100644 plugins/dbms/presto/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 3afdbc91c..77c46bde3 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -202,4 +202,12 @@ + + + + + + + + diff --git a/data/xml/queries.xml b/data/xml/queries.xml index c606cbce7..ea2de83a5 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1130,4 +1130,66 @@ + + + + + + + + + + + + + + + + + + + + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 5fca7156a..86ee67f21 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -11,59 +11,62 @@ from lib.core.data import kb from lib.core.dicts import DBMS_DICT from lib.core.enums import DBMS from lib.core.exception import SqlmapConnectionException +from lib.core.settings import ACCESS_ALIASES +from lib.core.settings import DB2_ALIASES +from lib.core.settings import DERBY_ALIASES +from lib.core.settings import FIREBIRD_ALIASES +from lib.core.settings import H2_ALIASES +from lib.core.settings import HSQLDB_ALIASES +from lib.core.settings import INFORMIX_ALIASES +from lib.core.settings import MAXDB_ALIASES from lib.core.settings import MCKOI_ALIASES +from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PGSQL_ALIASES +from lib.core.settings import PRESTO_ALIASES from lib.core.settings import SQLITE_ALIASES -from lib.core.settings import ACCESS_ALIASES -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 HSQLDB_ALIASES -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.mckoi import MckoiMap -from plugins.dbms.mckoi.connector import Connector as MckoiConn -from plugins.dbms.mssqlserver import MSSQLServerMap -from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn -from plugins.dbms.mysql import MySQLMap -from plugins.dbms.mysql.connector import Connector as MySQLConn -from plugins.dbms.oracle import OracleMap -from plugins.dbms.oracle.connector import Connector as OracleConn -from plugins.dbms.postgresql import PostgreSQLMap -from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn -from plugins.dbms.sqlite import SQLiteMap -from plugins.dbms.sqlite.connector import Connector as SQLiteConn -from plugins.dbms.access import AccessMap from plugins.dbms.access.connector import Connector as AccessConn -from plugins.dbms.firebird import FirebirdMap -from plugins.dbms.firebird.connector import Connector as FirebirdConn -from plugins.dbms.maxdb import MaxDBMap -from plugins.dbms.maxdb.connector import Connector as MaxDBConn -from plugins.dbms.sybase import SybaseMap -from plugins.dbms.sybase.connector import Connector as SybaseConn -from plugins.dbms.db2 import DB2Map +from plugins.dbms.access import AccessMap from plugins.dbms.db2.connector import Connector as DB2Conn -from plugins.dbms.hsqldb import HSQLDBMap -from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn -from plugins.dbms.h2 import H2Map -from plugins.dbms.h2.connector import Connector as H2Conn -from plugins.dbms.informix import InformixMap -from plugins.dbms.informix.connector import Connector as InformixConn -from plugins.dbms.monetdb import MonetDBMap -from plugins.dbms.monetdb.connector import Connector as MonetDBConn -from plugins.dbms.derby import DerbyMap +from plugins.dbms.db2 import DB2Map from plugins.dbms.derby.connector import Connector as DerbyConn -from plugins.dbms.vertica import VerticaMap +from plugins.dbms.derby import DerbyMap +from plugins.dbms.firebird.connector import Connector as FirebirdConn +from plugins.dbms.firebird import FirebirdMap +from plugins.dbms.h2.connector import Connector as H2Conn +from plugins.dbms.h2 import H2Map +from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn +from plugins.dbms.hsqldb import HSQLDBMap +from plugins.dbms.informix.connector import Connector as InformixConn +from plugins.dbms.informix import InformixMap +from plugins.dbms.maxdb.connector import Connector as MaxDBConn +from plugins.dbms.maxdb import MaxDBMap +from plugins.dbms.mckoi.connector import Connector as MckoiConn +from plugins.dbms.mckoi import MckoiMap +from plugins.dbms.monetdb.connector import Connector as MonetDBConn +from plugins.dbms.monetdb import MonetDBMap +from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn +from plugins.dbms.mssqlserver import MSSQLServerMap +from plugins.dbms.mysql.connector import Connector as MySQLConn +from plugins.dbms.mysql import MySQLMap +from plugins.dbms.oracle.connector import Connector as OracleConn +from plugins.dbms.oracle import OracleMap +from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn +from plugins.dbms.postgresql import PostgreSQLMap +from plugins.dbms.presto.connector import Connector as PrestoConn +from plugins.dbms.presto import PrestoMap +from plugins.dbms.sqlite.connector import Connector as SQLiteConn +from plugins.dbms.sqlite import SQLiteMap +from plugins.dbms.sybase.connector import Connector as SybaseConn +from plugins.dbms.sybase import SybaseMap from plugins.dbms.vertica.connector import Connector as VerticaConn +from plugins.dbms.vertica import VerticaMap def setHandler(): """ @@ -89,6 +92,7 @@ def setHandler(): (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn), (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn), (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn), + (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn), ] _ = 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 dd6cc5dae..301118201 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -657,7 +657,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, DBMS.VERTICA, DBMS.MCKOI): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -946,7 +946,7 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index b35e1074b..2dbaaa2ae 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1461,7 +1461,7 @@ def parseTargetDirect(): remote = False for dbms in SUPPORTED_DBMS: - details = re.search(r"^(?P%s)://(?P(?P.+?)\:(?P.*)\@)?(?P(?P[\w.-]+?)\:(?P[\d]+)\/)?(?P[\w\d\ \:\.\_\-\/\\]+?)$" % dbms, conf.direct, re.I) + details = re.search(r"^(?P%s)://(?P(?P.*?)\:(?P.*)\@)?(?P(?P[\w.-]+?)\:(?P[\d]+)\/)?(?P[\w\d\ \:\.\_\-\/\\]+?)$" % dbms, conf.direct, re.I) if details: conf.dbms = details.group("dbms") @@ -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, DBMS.VERTICA, DBMS.MCKOI): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): 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, DBMS.VERTICA, DBMS.MCKOI): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): 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 c1aa9278f..561502372 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -25,6 +25,7 @@ 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 PGSQL_ALIASES +from lib.core.settings import PRESTO_ALIASES from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SYBASE_ALIASES from lib.core.settings import VERTICA_ALIASES @@ -206,6 +207,7 @@ DBMS_DICT = { 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"), DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), + DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ diff --git a/lib/core/enums.py b/lib/core/enums.py index 2d51dd080..76d0760af 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -49,6 +49,7 @@ class DBMS(object): DERBY = "Apache Derby" VERTICA = "Vertica" MCKOI = "Mckoi" + PRESTO = "Presto" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -68,6 +69,7 @@ class DBMS_DIRECTORY_NAME(object): DERBY = "derby" VERTICA = "vertica" MCKOI = "mckoi" + PRESTO = "presto" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 7a1f6205f..3ea1fef5f 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.42" +VERSION = "1.4.1.43" 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) @@ -263,6 +263,7 @@ 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",) MCKOI_SYSTEM_DBS = ("",) +PRESTO_SYSTEM_DBS = ("information_schema",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") @@ -281,15 +282,16 @@ MONETDB_ALIASES = ("monet", "monetdb",) DERBY_ALIASES = ("derby", "apache derby",) VERTICA_ALIASES = ("vertica",) MCKOI_ALIASES = ("mckoi",) +PRESTO_ALIASES = ("presto",) UPPER_CASE_IDENTIFIERS = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY)) 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 + VERTICA_ALIASES + MCKOI_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 + MCKOI_ALIASES + PRESTO_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.VERTICA, VERTICA_ALIASES), (DBMS.MCKOI, MCKOI_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), (DBMS.MCKOI, MCKOI_ALIASES), (DBMS.PRESTO, PRESTO_ALIASES)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 006bc2e5e..19fab922f 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -52,6 +52,8 @@ def checkDependencies(): __import__("drda") elif dbmsName == DBMS.VERTICA: __import__("vertica_python") + elif dbmsName == DBMS.PRESTO: + __import__("prestodb") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/presto/__init__.py b/plugins/dbms/presto/__init__.py new file mode 100644 index 000000000..05f883134 --- /dev/null +++ b/plugins/dbms/presto/__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 PRESTO_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.presto.enumeration import Enumeration +from plugins.dbms.presto.filesystem import Filesystem +from plugins.dbms.presto.fingerprint import Fingerprint +from plugins.dbms.presto.syntax import Syntax +from plugins.dbms.presto.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class PrestoMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Presto methods + """ + + def __init__(self): + self.excludeDbsList = PRESTO_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.PRESTO] = Syntax.escape diff --git a/plugins/dbms/presto/connector.py b/plugins/dbms/presto/connector.py new file mode 100644 index 000000000..86b18d1e2 --- /dev/null +++ b/plugins/dbms/presto/connector.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import prestodb +except: + pass + +import logging +import struct + +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/prestodb/presto-python-client + User guide: https://github.com/prestodb/presto-python-client/blob/master/README.md + API: https://www.python.org/dev/peps/pep-0249/ + PyPI package: presto-python-client + License: Apache License 2.0 + """ + + def connect(self): + self.initConnection() + + try: + self.connector = prestodb.dbapi.connect(host=self.hostname, user=self.user, catalog=self.db, port=self.port, request_timeout=conf.timeout) + except (prestodb.exceptions.OperationalError, prestodb.exceptions.InternalError, prestodb.exceptions.ProgrammingError, struct.error) as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except prestodb.exceptions.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + retVal = False + + try: + self.cursor.execute(query) + retVal = True + except (prestodb.exceptions.OperationalError, prestodb.exceptions.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except prestodb.exceptions.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + return retVal + + def select(self, query): + retVal = None + + if self.execute(query): + retVal = self.fetchall() + + return retVal diff --git a/plugins/dbms/presto/enumeration.py b/plugins/dbms/presto/enumeration.py new file mode 100644 index 000000000..e36ed2ab9 --- /dev/null +++ b/plugins/dbms/presto/enumeration.py @@ -0,0 +1,58 @@ +#!/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 getBanner(self): + warnMsg = "on Presto it is not possible to get a banner" + logger.warn(warnMsg) + + return None + + def getCurrentDb(self): + warnMsg = "on Presto it is not possible to get name of the current database (schema)" + logger.warn(warnMsg) + + def isDba(self, user=None): + warnMsg = "on Presto it is not possible to test if current user is DBA" + logger.warn(warnMsg) + + def getUsers(self): + warnMsg = "on Presto it is not possible to enumerate the users" + logger.warn(warnMsg) + + return [] + + def getPasswordHashes(self): + warnMsg = "on Presto it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} + + def getPrivileges(self, *args, **kwargs): + warnMsg = "on Presto it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getRoles(self, *args, **kwargs): + warnMsg = "on Presto it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} + + def getHostname(self): + warnMsg = "on Presto it is not possible to enumerate the hostname" + logger.warn(warnMsg) + + def getStatements(self): + warnMsg = "on Presto it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] diff --git a/plugins/dbms/presto/filesystem.py b/plugins/dbms/presto/filesystem.py new file mode 100644 index 000000000..68a6bf093 --- /dev/null +++ b/plugins/dbms/presto/filesystem.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def readFile(self, remoteFile): + errMsg = "on Presto it is not possible to read files" + raise SqlmapUnsupportedFeatureException(errMsg) + + def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): + errMsg = "on Presto it is not possible to write files" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/presto/fingerprint.py b/plugins/dbms/presto/fingerprint.py new file mode 100644 index 000000000..aa0dc14fd --- /dev/null +++ b/plugins/dbms/presto/fingerprint.py @@ -0,0 +1,137 @@ +#!/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.session import setDbms +from lib.core.settings import PRESTO_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.PRESTO) + + 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.PRESTO + 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(PRESTO_ALIASES): + setDbms(DBMS.PRESTO) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.PRESTO + logger.info(infoMsg) + + result = inject.checkBooleanExpression("TO_BASE64URL(NULL) IS NULL") + + if result: + infoMsg = "confirming %s" % DBMS.PRESTO + logger.info(infoMsg) + + result = inject.checkBooleanExpression("TO_HEX(FROM_HEX(NULL)) IS NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.PRESTO + logger.warn(warnMsg) + + return False + + setDbms(DBMS.PRESTO) + + if not conf.extensiveFp: + return True + + infoMsg = "actively fingerprinting %s" % DBMS.PRESTO + logger.info(infoMsg) + + # Reference: https://prestodb.io/docs/current/release/release-0.200.html + if inject.checkBooleanExpression("FROM_IEEE754_32(NULL) IS NULL"): + Backend.setVersion(">= 0.200") + # Reference: https://prestodb.io/docs/current/release/release-0.193.html + elif inject.checkBooleanExpression("NORMAL_CDF(NULL,NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.193") + # Reference: https://prestodb.io/docs/current/release/release-0.183.html + elif inject.checkBooleanExpression("MAP_ENTRIES(NULL) IS NULL"): + Backend.setVersion(">= 0.183") + # Reference: https://prestodb.io/docs/current/release/release-0.171.html + elif inject.checkBooleanExpression("CODEPOINT(NULL) IS NULL"): + Backend.setVersion(">= 0.171") + # Reference: https://prestodb.io/docs/current/release/release-0.162.html + elif inject.checkBooleanExpression("XXHASH64(NULL) IS NULL"): + Backend.setVersion(">= 0.162") + # Reference: https://prestodb.io/docs/current/release/release-0.151.html + elif inject.checkBooleanExpression("COSINE_SIMILARITY(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.151") + # Reference: https://prestodb.io/docs/current/release/release-0.143.html + elif inject.checkBooleanExpression("TRUNCATE(NULL) IS NULL"): + Backend.setVersion(">= 0.143") + # Reference: https://prestodb.io/docs/current/release/release-0.137.html + elif inject.checkBooleanExpression("BIT_COUNT(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.137") + # Reference: https://prestodb.io/docs/current/release/release-0.130.html + elif inject.checkBooleanExpression("MAP_CONCAT(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.130") + # Reference: https://prestodb.io/docs/current/release/release-0.115.html + elif inject.checkBooleanExpression("SHA1(NULL) IS NULL"): + Backend.setVersion(">= 0.115") + # Reference: https://prestodb.io/docs/current/release/release-0.100.html + elif inject.checkBooleanExpression("SPLIT(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.100") + # Reference: https://prestodb.io/docs/current/release/release-0.70.html + elif inject.checkBooleanExpression("GREATEST(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.70") + else: + Backend.setVersion("< 0.100") + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.PRESTO + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/presto/syntax.py b/plugins/dbms/presto/syntax.py new file mode 100644 index 000000000..f9355c077 --- /dev/null +++ b/plugins/dbms/presto/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 "||".join("CHR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/presto/takeover.py b/plugins/dbms/presto/takeover.py new file mode 100644 index 000000000..e27563c47 --- /dev/null +++ b/plugins/dbms/presto/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on Presto it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on Presto it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Presto it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Presto it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 5eb713b59..b8389d089 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -82,7 +82,7 @@ class Databases(object): 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): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO): 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" @@ -102,7 +102,7 @@ class Databases(object): warnMsg += "names will be fetched from 'mysql' database" logger.warn(warnMsg) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO): warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -589,7 +589,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, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -731,7 +731,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, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -798,7 +798,7 @@ class Databases(object): continue for index in getLimitRange(count): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None @@ -848,7 +848,7 @@ class Databases(object): singleTimeWarnMessage(warnMsg) if not onlyColNames: - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): 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 74d664564..99fd9d646 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, DBMS.VERTICA): + elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): 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, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): 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)