diff --git a/data/txt/sha256sums.txt b/data/txt/sha256sums.txt index c54b511edf..59534c9a0a 100644 --- a/data/txt/sha256sums.txt +++ b/data/txt/sha256sums.txt @@ -85,7 +85,7 @@ b0f434f64105bd61ab0f6867b3f681b97fa02b4fb809ac538db382d031f0e609 data/xml/paylo 0648264166455010921df1ec431e4c973809f37ef12cbfea75f95029222eb689 data/xml/payloads/stacked_queries.xml 997556b6170964a64474a2e053abe33cf2cf029fb1acec660d4651cc67a3c7e1 data/xml/payloads/time_blind.xml 40a4878669f318568097719d07dc906a19b8520bc742be3583321fc1e8176089 data/xml/payloads/union_query.xml -eeaec8f6590db3315a740b04f21fed8ae229d9d0ef8b85af5ad83a905e9bfd6e data/xml/queries.xml +12078af6bdd45397fc855f30738fba5ecaf9948e526d819d226b229d87db2b43 data/xml/queries.xml abb6261b1c531ad2ee3ada8184c76bcdc38732558d11a8e519f36fcc95325f7e doc/AUTHORS ce20a4b452f24a97fde7ec9ed816feee12ac148e1fde5f1722772cc866b12740 doc/CHANGELOG.md 7af515e3ad13fb7e9cfa4debc8ec879758c0cfbe67642b760172178cda9cf5cb doc/THANKS.md @@ -164,7 +164,7 @@ df768bcb9838dc6c46dab9b4a877056cb4742bd6cfaaf438c4a3712c5cc0d264 extra/shutils/ b8411d1035bb49b073476404e61e1be7f4c61e205057730e2f7880beadcd5f60 lib/controller/action.py e376093d4f6e42ee38b050af329179df9c1c136b7667b2f1cb559f5d4b69ebd9 lib/controller/checks.py 430475857a37fd997e73a47d7485c5dd4aa0985ef32c5a46b5e7bff01749ba66 lib/controller/controller.py -ccec2373f6393f3d644db3de2910e17ef705817063c03e7ca4417f9d7f622527 lib/controller/handler.py +1ecbca13afdc7c2bc8dc215c5d7fca453bf836dbe3ca377609750bfbc4874a85 lib/controller/handler.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py 6da126b359e67f73cea7848d3f35dd0890aece16374d04b60490b85e26bf7224 lib/core/agent.py 1da4ec9cd9b67c8b54e4a3d314f8237d58778d8f3a00bc26a1e0540294dca30f lib/core/bigarray.py @@ -175,9 +175,9 @@ c03dc585f89642cfd81b087ac2723e3e1bb3bfa8c60e6f5fe58ef3b0113ebfe6 lib/core/data. e396b7971d38896e0e20b973a3a6a3fbc3171d080a21bc6e66a65bee452fd69c lib/core/datatype.py e18c0c2c5a57924a623792a48bfd36e98d9bc085f6db61a95fc0dc8a3bcedc0c lib/core/decorators.py 147823c37596bd6a56d677697781f34b8d1d1671d5a2518fbc9468d623c6d07d lib/core/defaults.py -86fa0ffa7a3e7a7141eab730e3981faf6f0249125ea9a29a57aaa8b65b7503f9 lib/core/dicts.py +76e2c68051c2c1d811d09eec1ca63bc146f4d047708d6296be1460d047743074 lib/core/dicts.py 186f0331d66e861a942817a3321156a93a6f66c34a19ce90ec1d10aac8bc1cac lib/core/dump.py -f5272cda54f7cdd07fb6154d5a1ed1f1141a2a4f39b6a85d3f325fd60ac8dc9a lib/core/enums.py +1abf1edeacb85eaf5cffd35fcbde4eee2da6f5fc722a8dc1f9287fb55d138418 lib/core/enums.py 5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py 914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py @@ -189,7 +189,7 @@ f5272cda54f7cdd07fb6154d5a1ed1f1141a2a4f39b6a85d3f325fd60ac8dc9a lib/core/enums 48797d6c34dd9bb8a53f7f3794c85f4288d82a9a1d6be7fcf317d388cb20d4b3 lib/core/replication.py 3574639db4942d16a2dc0a2f04bb7c0913c40c3862b54d34c44075a760e0c194 lib/core/revision.py 888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py -3b6399d22ede02c937ac211fdddfdfd36c67b797d05ef550244dd0f0d72ccce0 lib/core/settings.py +306d40d69dddc0bbd8168e40df4002bb6d666e323f8211780b5c9619cd70c068 lib/core/settings.py cd5a66deee8963ba8e7e9af3dd36eb5e8127d4d68698811c29e789655f507f82 lib/core/shell.py bcb5d8090d5e3e0ef2a586ba09ba80eef0c6d51feb0f611ed25299fbb254f725 lib/core/subprocessng.py d35650179816193164a5f177102f18379dfbe6bb6d40fbb67b78d907b41c8038 lib/core/target.py @@ -434,6 +434,13 @@ b76606fe4dee18467bc0d19af1e6ab38c0b5593c6c0f2068a8d4c664d4bd71d8 plugins/dbms/r 3b49758a10ce88c5d8db081cdb4924168c726d1e060e6d09601796fba2a3fbee plugins/dbms/raima/__init__.py 1df5c5d522b381ef48174cfc5c9e1149194e15c80b9d517e3ed61d60b1a46740 plugins/dbms/raima/syntax.py 5b9572279051ab345f45c1db02b02279a070aafdc651aedd7f163d8a6477390b plugins/dbms/raima/takeover.py +5744531487abfb0368e55187a66cb615277754a14c2e7facea2778378e67d5c9 plugins/dbms/snowflake/connector.py +bca8e2de881b59314e84f361682e810333b63f8211e6aa5f5a4d0efe1d9bcd31 plugins/dbms/snowflake/enumeration.py +3b52302bc41ab185d190bbef58312a4d6f1ee63caa8757309cda58eb91628bc5 plugins/dbms/snowflake/filesystem.py +f51afa612135dbc870bd48085baa867f94fe1809ec8123fea8f62bc3720ac619 plugins/dbms/snowflake/fingerprint.py +1de7c93b445deb0766c314066cb122535e9982408614b0ff952a97cbae9b813a plugins/dbms/snowflake/__init__.py +859cc5b9be496fe35f2782743f8e573ff9d823de7e99b0d32dbc250c361c653e plugins/dbms/snowflake/syntax.py +da43fed8bfa4a94aaceb63e760c69e9927c1640e45e457b8f03189be6604693f plugins/dbms/snowflake/takeover.py cae01d387617e3986b9cfb23519b7c6a444e2d116f2dc774163abec0217f6ed6 plugins/dbms/sqlite/connector.py fbcff0468fcccd9f86277d205b33f14578b7550b33d31716fd10003f16122752 plugins/dbms/sqlite/enumeration.py 013f6cf4d04edce3ee0ede73b6415a2774e58452a5365ab5f7a49c77650ba355 plugins/dbms/sqlite/filesystem.py @@ -464,8 +471,8 @@ e2e20e4707abe9ed8b6208837332d2daa4eaca282f847412063f2484dcca8fbd plugins/dbms/v 2b2dad6ba1d344215cad11b629546eb9f259d7c996c202edf3de5ab22418787e plugins/dbms/virtuoso/takeover.py 51c44048e4b335b306f8ed1323fd78ad6935a8c0d6e9d6efe195a9a5a24e46dc plugins/generic/connector.py a967f4ebd101c68a5dcc10ff18c882a8f44a5c3bf06613d951a739ecc3abb9b3 plugins/generic/custom.py -ba5d7cdebd0619454ab23b474e36231085f35a70961bfe4e93d5753736799b82 plugins/generic/databases.py -c46904df889742d2c781749e153663cde29a7c77eb8cbaad6d1db3148e9a58bd plugins/generic/entries.py +f4b803320e9681250b90b7d46cd599ec27fd9f2c0f8ccc707f195707551d0bc0 plugins/generic/databases.py +6a62dbe3feddb12b48c4077478668576e62663ebd8d8aa795820199d9588f919 plugins/generic/entries.py d2de7fc135cf0db3eb4ac4a509c23ebec5250a5d8043face7f8c546a09f301b5 plugins/generic/enumeration.py a02ac4ebc1cc488a2aa5ae07e6d0c3d5064e99ded7fd529dfa073735692f11df plugins/generic/filesystem.py efd7177218288f32881b69a7ba3d667dc9178f1009c06a3e1dd4f4a4ee6980db plugins/generic/fingerprint.py diff --git a/data/xml/queries.xml b/data/xml/queries.xml index d497f3d8cf..0091a66f3f 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1786,4 +1786,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 3360a458b8..e6736680ba 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -41,6 +41,7 @@ from lib.core.settings import SYBASE_ALIASES from lib.core.settings import VERTICA_ALIASES from lib.core.settings import VIRTUOSO_ALIASES +from lib.core.settings import SNOWFLAKE_ALIASES from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.access.connector import Connector as AccessConn @@ -99,6 +100,8 @@ from plugins.dbms.vertica import VerticaMap from plugins.dbms.virtuoso.connector import Connector as VirtuosoConn from plugins.dbms.virtuoso import VirtuosoMap +from plugins.dbms.snowflake.connector import Connector as SnowflakeConn +from plugins.dbms.snowflake import SnowflakeMap def setHandler(): """ @@ -107,6 +110,7 @@ def setHandler(): """ items = [ + (DBMS.SNOWFLAKE, SNOWFLAKE_ALIASES, SnowflakeMap, SnowflakeConn), (DBMS.MYSQL, MYSQL_ALIASES, MySQLMap, MySQLConn), (DBMS.ORACLE, ORACLE_ALIASES, OracleMap, OracleConn), (DBMS.PGSQL, PGSQL_ALIASES, PostgreSQLMap, PostgreSQLConn), @@ -135,6 +139,7 @@ def setHandler(): (DBMS.FRONTBASE, FRONTBASE_ALIASES, FrontBaseMap, FrontBaseConn), (DBMS.RAIMA, RAIMA_ALIASES, RaimaMap, RaimaConn), (DBMS.VIRTUOSO, VIRTUOSO_ALIASES, VirtuosoMap, VirtuosoConn), + # TODO: put snowflake stuff on this line ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 4ab9728d6e..29b249a1a8 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -39,6 +39,7 @@ from lib.core.settings import VERTICA_ALIASES from lib.core.settings import VIRTUOSO_ALIASES from lib.core.settings import CLICKHOUSE_ALIASES +from lib.core.settings import SNOWFLAKE_ALIASES FIREBIRD_TYPES = { 261: "BLOB", @@ -250,6 +251,7 @@ DBMS.FRONTBASE: (FRONTBASE_ALIASES, None, None, None), DBMS.RAIMA: (RAIMA_ALIASES, None, None, None), DBMS.VIRTUOSO: (VIRTUOSO_ALIASES, None, None, None), + DBMS.SNOWFLAKE: (SNOWFLAKE_ALIASES, None, None, "snowflake"), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ diff --git a/lib/core/enums.py b/lib/core/enums.py index 7c362aaaea..689055a3c2 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -60,6 +60,7 @@ class DBMS(object): FRONTBASE = "FrontBase" RAIMA = "Raima Database Manager" VIRTUOSO = "Virtuoso" + SNOWFLAKE = "Snowflake" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -90,6 +91,7 @@ class DBMS_DIRECTORY_NAME(object): FRONTBASE = "frontbase" RAIMA = "raima" VIRTUOSO = "virtuoso" + SNOWFLAKE = "snowflake" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 29b464ae5a..200bd4d500 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.1.22" +VERSION = "1.10.1.24" 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) @@ -292,6 +292,7 @@ FRONTBASE_SYSTEM_DBS = ("DEFINITION_SCHEMA", "INFORMATION_SCHEMA") RAIMA_SYSTEM_DBS = ("",) VIRTUOSO_SYSTEM_DBS = ("",) +SNOWFLAKE_SYSTEM_DBS = ("INFORMATION_SCHEMA",) # Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") @@ -322,10 +323,11 @@ FRONTBASE_ALIASES = ("frontbase",) RAIMA_ALIASES = ("raima database manager", "raima", "raimadb", "raimadm", "rdm", "rds", "velocis") VIRTUOSO_ALIASES = ("virtuoso", "openlink virtuoso") +SNOWFLAKE_ALIASES = ("snowflake",) DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_")) -SUPPORTED_DBMS = set(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 + ALTIBASE_ALIASES + MIMERSQL_ALIASES + CLICKHOUSE_ALIASES + CRATEDB_ALIASES + CUBRID_ALIASES + CACHE_ALIASES + EXTREMEDB_ALIASES + RAIMA_ALIASES + VIRTUOSO_ALIASES) +SUPPORTED_DBMS = set(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 + ALTIBASE_ALIASES + MIMERSQL_ALIASES + CLICKHOUSE_ALIASES + CRATEDB_ALIASES + CUBRID_ALIASES + CACHE_ALIASES + EXTREMEDB_ALIASES + RAIMA_ALIASES + VIRTUOSO_ALIASES + SNOWFLAKE_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.PRESTO, PRESTO_ALIASES), (DBMS.ALTIBASE, ALTIBASE_ALIASES), (DBMS.MIMERSQL, MIMERSQL_ALIASES), (DBMS.CLICKHOUSE, CLICKHOUSE_ALIASES), (DBMS.CRATEDB, CRATEDB_ALIASES), (DBMS.CUBRID, CUBRID_ALIASES), (DBMS.CACHE, CACHE_ALIASES), (DBMS.EXTREMEDB, EXTREMEDB_ALIASES), (DBMS.FRONTBASE, FRONTBASE_ALIASES), (DBMS.RAIMA, RAIMA_ALIASES), (DBMS.VIRTUOSO, VIRTUOSO_ALIASES)) diff --git a/plugins/dbms/snowflake/__init__.py b/plugins/dbms/snowflake/__init__.py new file mode 100644 index 0000000000..c331859644 --- /dev/null +++ b/plugins/dbms/snowflake/__init__.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import SNOWFLAKE_SYSTEM_DBS +from lib.core.unescaper import unescaper +from plugins.dbms.snowflake.enumeration import Enumeration +from plugins.dbms.snowflake.filesystem import Filesystem +from plugins.dbms.snowflake.fingerprint import Fingerprint +from plugins.dbms.snowflake.syntax import Syntax +from plugins.dbms.snowflake.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class SnowflakeMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Snowflake methods + """ + + def __init__(self): + self.excludeDbsList = SNOWFLAKE_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.SNOWFLAKE] = Syntax.escape diff --git a/plugins/dbms/snowflake/connector.py b/plugins/dbms/snowflake/connector.py new file mode 100644 index 0000000000..c24f3ab17b --- /dev/null +++ b/plugins/dbms/snowflake/connector.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) +See the file 'LICENSE' for copying permission +""" + +try: + import snowflake.connector +except: + pass + +import logging + +from lib.core.common import getSafeExString +from lib.core.convert import getText +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://www.snowflake.com/ + User guide: https://docs.snowflake.com/en/developer-guide/python-connector/python-connector + API: https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api + """ + + def __init__(self): + GenericConnector.__init__(self) + + def connect(self): + self.initConnection() + + try: + self.connector = snowflake.connector.connect( + user=self.user, + password=self.password, + account=self.account, + warehouse=self.warehouse, + database=self.db, + schema=self.schema + ) + cursor = self.connector.cursor() + cursor.execute("SELECT CURRENT_VERSION()") + cursor.close() + + except Exception as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except Exception as ex: + logger.log(logging.WARNING if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(getText(query)) + except Exception as ex: + logger.log(logging.WARNING if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex)) + return None + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/snowflake/enumeration.py b/plugins/dbms/snowflake/enumeration.py new file mode 100644 index 0000000000..f95e448839 --- /dev/null +++ b/plugins/dbms/snowflake/enumeration.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getPasswordHashes(self): + warnMsg = "on Snowflake it is not possible to enumerate the user password hashes" + logger.warning(warnMsg) + return {} + + def getHostname(self): + warnMsg = "on Snowflake it is not possible to enumerate the hostname" + logger.warning(warnMsg) + + def searchDb(self): + warnMsg = "on Snowflake it is not possible to search databases" + logger.warning(warnMsg) + return [] + + def searchColumn(self): + errMsg = "on Snowflake it is not possible to search columns" + raise SqlmapUnsupportedFeatureException(errMsg) + + def getPrivileges(self, *args, **kwargs): + warnMsg = "on SQLite it is not possible to enumerate the user privileges" + logger.warning(warnMsg) + return {} + + def getStatements(self): + warnMsg = "on Snowflake it is not possible to enumerate the SQL statements" + logger.warning(warnMsg) + return [] diff --git a/plugins/dbms/snowflake/filesystem.py b/plugins/dbms/snowflake/filesystem.py new file mode 100644 index 0000000000..23ba254b08 --- /dev/null +++ b/plugins/dbms/snowflake/filesystem.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://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 Snowflake it is not possible to read files" + raise SqlmapUnsupportedFeatureException(errMsg) + + def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): + errMsg = "on Snowflake it is not possible to write files" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/snowflake/fingerprint.py b/plugins/dbms/snowflake/fingerprint.py new file mode 100644 index 0000000000..51215ec7df --- /dev/null +++ b/plugins/dbms/snowflake/fingerprint.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://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 METADB_SUFFIX +from lib.core.settings import SNOWFLAKE_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.SNOWFLAKE) + + 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.SNOWFLAKE + 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): + """ + References for fingerprint: + + * https://docs.snowflake.com/en/sql-reference/functions/current_warehouse + * https://docs.snowflake.com/en/sql-reference/functions/md5_number_upper64 + """ + + if not conf.extensiveFp and Backend.isDbmsWithin(SNOWFLAKE_ALIASES): + setDbms("%s %s" % (DBMS.SNOWFLAKE, Backend.getVersion())) + self.getBanner() + return True + + infoMsg = "testing %s" % DBMS.SNOWFLAKE + logger.info(infoMsg) + + result = inject.checkBooleanExpression("CURRENT_WAREHOUSE()=CURRENT_WAREHOUSE()") + if result: + infoMsg = "confirming %s" % DBMS.SNOWFLAKE + logger.info(infoMsg) + + result = inject.checkBooleanExpression("MD5_NUMBER_UPPER64('z')=MD5_NUMBER_UPPER64('z')") + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.SNOWFLAKE + logger.warning(warnMsg) + return False + + setDbms(DBMS.SNOWFLAKE) + self.getBanner() + return True + + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.SNOWFLAKE + logger.warning(warnMsg) + + return False diff --git a/plugins/dbms/snowflake/syntax.py b/plugins/dbms/snowflake/syntax.py new file mode 100644 index 0000000000..7ba5c8b9f3 --- /dev/null +++ b/plugins/dbms/snowflake/syntax.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://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/snowflake/takeover.py b/plugins/dbms/snowflake/takeover.py new file mode 100644 index 0000000000..0acd82169f --- /dev/null +++ b/plugins/dbms/snowflake/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://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 Snowflake it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on Snowflake it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Snowflake it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Snowflake 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 226f7293cd..0347815d14 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -621,7 +621,7 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod 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, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -757,7 +757,7 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod 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, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 9498efab13..b310dc4412 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -187,7 +187,7 @@ def dumpTable(self, foundData=None): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.inband.query % (colString, tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) - elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA): + elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA, DBMS.SNOWFLAKE): query = rootQuery.inband.query % (colString, tbl) elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): # Partial inband and error