Adding support for DuckDB

This commit is contained in:
Miroslav Štampar 2026-07-12 16:59:41 +02:00
parent 16cd9425ae
commit 9331ac0f2c
4 changed files with 63 additions and 3 deletions

View file

@ -117,6 +117,7 @@ class FORK(object):
DORIS = "Doris"
STARROCKS = "StarRocks"
TRINO = "Trino"
DUCKDB = "DuckDB"
class CUSTOM_LOGGING(object):
PAYLOAD = 9

View file

@ -20,7 +20,7 @@ from lib.core.enums import OS
from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.7.93"
VERSION = "1.10.7.94"
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)
@ -368,7 +368,7 @@ HANA_SYSTEM_DBS = ("SYS", "SYSTEM", "_SYS_BI", "_SYS_BIC", "_SYS_REPO", "_SYS_ST
# Note: (<regular>) + (<forks>)
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb", "percona", "drizzle", "doris", "starrocks")
PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb", "amazon redshift", "redshift", "greenplum", "yellowbrick", "enterprisedb", "yugabyte", "yugabytedb", "opengauss")
PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb", "amazon redshift", "redshift", "greenplum", "yellowbrick", "enterprisedb", "yugabyte", "yugabytedb", "opengauss", "duckdb")
ORACLE_ALIASES = ("oracle", "orcl", "ora", "or", "dm8")
SQLITE_ALIASES = ("sqlite", "sqlite3")
ACCESS_ALIASES = ("microsoft access", "msaccess", "access", "jet")

View file

@ -5,7 +5,11 @@ 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.data import logger
from lib.core.data import queries
from lib.core.enums import DBMS
from lib.core.enums import FORK
from plugins.generic.enumeration import Enumeration as GenericEnumeration
@ -13,3 +17,55 @@ class Enumeration(GenericEnumeration):
def getHostname(self):
warnMsg = "on PostgreSQL it is not possible to enumerate the hostname"
logger.warning(warnMsg)
def getColumns(self, *args, **kwargs):
if not Backend.isFork(FORK.DUCKDB):
return GenericEnumeration.getColumns(self, *args, **kwargs)
# DuckDB (PostgreSQL fork) exposes column metadata through information_schema instead of the
# pg_catalog tables (pg_attribute yields no rows), so swap those queries in for the generic routine
columns = queries[DBMS.PGSQL].columns
backup = (columns.inband.query, columns.inband.condition, columns.blind.query, columns.blind.query2, columns.blind.count, columns.blind.condition)
columns.inband.query = "SELECT column_name,data_type FROM information_schema.columns WHERE table_name='%s' AND table_schema='%s' ORDER BY column_name"
columns.blind.query = "SELECT column_name FROM information_schema.columns WHERE table_name='%s' AND table_schema='%s' ORDER BY column_name"
columns.blind.query2 = "SELECT data_type FROM information_schema.columns WHERE table_name='%s' AND column_name='%s' AND table_schema='%s'"
columns.blind.count = "SELECT COUNT(column_name) FROM information_schema.columns WHERE table_name='%s' AND table_schema='%s'"
columns.inband.condition = columns.blind.condition = "column_name"
try:
return GenericEnumeration.getColumns(self, *args, **kwargs)
finally:
columns.inband.query, columns.inband.condition, columns.blind.query, columns.blind.query2, columns.blind.count, columns.blind.condition = backup
def getUsers(self):
if Backend.isFork(FORK.DUCKDB):
warnMsg = "on DuckDB it is not possible to enumerate the users"
logger.warning(warnMsg)
return []
return GenericEnumeration.getUsers(self)
def getPasswordHashes(self):
if Backend.isFork(FORK.DUCKDB):
warnMsg = "on DuckDB it is not possible to enumerate the user password hashes"
logger.warning(warnMsg)
return {}
return GenericEnumeration.getPasswordHashes(self)
def getPrivileges(self, query2=False):
if Backend.isFork(FORK.DUCKDB):
warnMsg = "on DuckDB it is not possible to enumerate the user privileges"
logger.warning(warnMsg)
return {}
return GenericEnumeration.getPrivileges(self, query2)
def getRoles(self, query2=False):
if Backend.isFork(FORK.DUCKDB):
warnMsg = "on DuckDB it is not possible to enumerate the user roles"
logger.warning(warnMsg)
return {}
return GenericEnumeration.getRoles(self, query2)

View file

@ -45,6 +45,8 @@ class Fingerprint(GenericFingerprint):
fork = FORK.OPENGAUSS
elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/
fork = FORK.AURORA
elif inject.checkBooleanExpression("[1,2,3][2]=2"): # NOTE: bare list literal with 1-based indexing is DuckDB-only (invalid syntax on PostgreSQL)
fork = FORK.DUCKDB
else:
fork = ""
@ -109,7 +111,8 @@ class Fingerprint(GenericFingerprint):
logger.info(infoMsg)
# NOTE: Vertica works too without the CONVERT_TO()
result = inject.checkBooleanExpression("CONVERT_TO('[RANDSTR]', QUOTE_IDENT(NULL)) IS NULL")
# NOTE: DuckDB (PostgreSQL dialect fork) lacks CONVERT_TO()/QUOTE_IDENT(), so it is accepted via its list-literal instead
result = inject.checkBooleanExpression("CONVERT_TO('[RANDSTR]', QUOTE_IDENT(NULL)) IS NULL") or inject.checkBooleanExpression("[1,2,3][2]=2")
if result:
infoMsg = "confirming %s" % DBMS.PGSQL