Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions data/xml/queries.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1785,4 +1785,66 @@
<search_table/>
<search_column/>
</dbms>
<dbms value="Snowflake">
<cast query="CAST(%s AS VARCHAR)"/>
<length query="LENGTH(%s)"/>
<isnull query="NVL(%s, ' ')"/>
<delimiter query="||"/>
<limit query="LIMIT %d OFFSET %d"/>
<limitregexp query="\s+LIMIT\s+([\d]+)\s+OFFSET\s+([\d]+)"/>
<limitgroupstart query="1"/>
<limitgroupstop query="2"/>
<limitstring query=" LIMIT "/>
<order query="ORDER BY %s ASC"/>
<count query="COUNT(%s)"/>
<comment query="--"/>
<concatenate query="%s||%s"/>
<case query="SELECT CASE WHEN (%s) THEN 1 ELSE 0 END"/>
<inference query="ASCII(SUBSTR((%s),%d,1))>%d"/>
<banner query="SELECT CURRENT_VERSION()"/>
<current_user query="SELECT CURRENT_USER()"/>
<current_db query="SELECT CURRENT_DATABASE()"/>
<hostname/>
<table_comment/>
<column_comment/>
<is_dba query="CURRENT_ROLE()='ACCOUNTADMIN'"/>

<dbs>
<inband query="SELECT DATABASE_NAME FROM SNOWFLAKE.INFORMATION_SCHEMA.DATABASES"/>
<blind query="SELECT DATABASE_NAME FROM SNOWFLAKE.INFORMATION_SCHEMA.DATABASES ORDER BY DATABASE_NAME LIMIT 1 OFFSET %d" count="SELECT COUNT(*) FROM SNOWFLAKE.INFORMATION_SCHEMA.DATABASES"/>
</dbs>

<tables>
<inband query="SELECT TABLE_CATALOG, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES" condition="TABLE_TYPE='BASE TABLE' AND TABLE_CATALOG"/>

<blind query="SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG='%s' ORDER BY TABLE_NAME LIMIT 1 OFFSET %d" count="SELECT COUNT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG='%s'"
/>
</tables>

<columns>
<inband query="SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='%s' AND TABLE_CATALOG='%s'"/>
<blind query="SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='%s' AND TABLE_CATALOG='%s' LIMIT 1 OFFSET %d" query2="SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='%s' AND COLUMN_NAME='%s' AND TABLE_CATALOG='%s'" count="SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='%s' AND TABLE_CATALOG='%s'"/>
</columns>

<dump_table>
<inband query="SELECT %s FROM TABLE('%s')"/>
<blind query="SELECT %s FROM %s.%s LIMIT 1 OFFSET %d" count="SELECT COUNT(*) FROM %s.%s"/>
</dump_table>

<users>
<inband query="SELECT NAME FROM SNOWFLAKE.ACCOUNT_USAGE.USERS"/>
<blind query="SELECT NAME FROM SNOWFLAKE.ACCOUNT_USAGE.USERS LIMIT 1 OFFSET %d" count="SELECT COUNT(*) FROM SNOWFLAKE.ACCOUNT_USAGE.USERS"/>
</users>

<roles>
<inband query="SELECT NAME FROM SNOWFLAKE.ACCOUNT_USAGE.ROLES"/>
<blind query="SELECT NAME FROM SNOWFLAKE.ACCOUNT_USAGE.ROLES LIMIT 1 OFFSET %d" count="SELECT COUNT(*) FROM SNOWFLAKE.ACCOUNT_USAGE.ROLES"/>
</roles>

<privileges/>
<statements/>
<search_db/>
<search_table/>
<search_column/>
</dbms>
</root>
5 changes: 5 additions & 0 deletions lib/controller/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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():
"""
Expand All @@ -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),
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions lib/core/dicts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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/
Expand Down
2 changes: 2 additions & 0 deletions lib/core/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class DBMS(object):
FRONTBASE = "FrontBase"
RAIMA = "Raima Database Manager"
VIRTUOSO = "Virtuoso"
SNOWFLAKE = "Snowflake"

class DBMS_DIRECTORY_NAME(object):
ACCESS = "access"
Expand Down Expand Up @@ -90,6 +91,7 @@ class DBMS_DIRECTORY_NAME(object):
FRONTBASE = "frontbase"
RAIMA = "raima"
VIRTUOSO = "virtuoso"
SNOWFLAKE = "snowflake"

class FORK(object):
MARIADB = "MariaDB"
Expand Down
4 changes: 3 additions & 1 deletion lib/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@
FRONTBASE_SYSTEM_DBS = ("DEFINITION_SCHEMA", "INFORMATION_SCHEMA")
RAIMA_SYSTEM_DBS = ("",)
VIRTUOSO_SYSTEM_DBS = ("",)
SNOWFLAKE_SYSTEM_DBS = ("INFORMATION_SCHEMA",)

# Note: (<regular>) + (<forks>)
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
Expand Down Expand Up @@ -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))
Expand Down
29 changes: 29 additions & 0 deletions plugins/dbms/snowflake/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python

"""
Copyright (c) 2006-2025 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
70 changes: 70 additions & 0 deletions plugins/dbms/snowflake/connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python

"""
Copyright (c) 2006-2025 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()
39 changes: 39 additions & 0 deletions plugins/dbms/snowflake/enumeration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python

"""
Copyright (c) 2006-2025 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 []
18 changes: 18 additions & 0 deletions plugins/dbms/snowflake/filesystem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env python

"""
Copyright (c) 2006-2025 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)
Loading