mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-06-29 13:01:02 +00:00
Update of tests
This commit is contained in:
parent
cb20a446ae
commit
2297c81309
32 changed files with 7177 additions and 7304 deletions
|
|
@ -6,11 +6,19 @@ See the file 'LICENSE' for copying permission
|
|||
|
||||
DBMS-specific enumeration overrides (plugins/dbms/<dbms>/enumeration.py),
|
||||
driven through each full DBMS handler with the injection layer mocked, so the
|
||||
dialect-specific table/column discovery paths run without a live target. The
|
||||
in-band (UNION/error/direct) branch is taken via conf.direct=True and
|
||||
inject.getValue is stubbed with canned result rows.
|
||||
dialect-specific table/column/user/privilege discovery paths run without a live
|
||||
target, network, or DBMS. The in-band (UNION/error/direct) branch is taken via
|
||||
conf.direct=True and inject.getValue is stubbed with canned result rows;
|
||||
conf.batch=True avoids interactive prompts.
|
||||
|
||||
Consolidated from former tests/test_dbms_enum.py (Microsoft SQL Server),
|
||||
tests/test_dbms_enum_a.py (Oracle/PostgreSQL/MySQL/SQLite) and
|
||||
tests/test_dbms_enum_b.py (Sybase/MaxDB/MSSQL extra/DB2/Informix/Firebird/HSQLDB).
|
||||
|
||||
stdlib unittest only (no pytest / no pip); works on Python 2.7 and 3.x.
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
|
@ -19,11 +27,18 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|||
from _testutils import bootstrap, set_dbms
|
||||
bootstrap()
|
||||
|
||||
from lib.core.common import Backend
|
||||
from lib.core.data import conf, kb
|
||||
from lib.core.enums import EXPECTED
|
||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from lib.request import inject
|
||||
|
||||
|
||||
class _EnumBase(unittest.TestCase):
|
||||
# ---------------------------------------------------------------------------
|
||||
# Base for Microsoft SQL Server getTables (former test_dbms_enum.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class _EnumBaseMSSQL(unittest.TestCase):
|
||||
"""Snapshot/restore the global state these enumerators mutate."""
|
||||
module = None # the enumeration module whose inject.getValue we patch
|
||||
|
||||
|
|
@ -45,7 +60,7 @@ class _EnumBase(unittest.TestCase):
|
|||
kb.data.cachedColumns = self._cachedColumns
|
||||
|
||||
|
||||
class TestMSSQLServerEnum(_EnumBase):
|
||||
class TestMSSQLServerEnum(_EnumBaseMSSQL):
|
||||
import plugins.dbms.mssqlserver.enumeration as module
|
||||
|
||||
def _handler(self):
|
||||
|
|
@ -94,5 +109,614 @@ class TestMSSQLServerEnum(_EnumBase):
|
|||
self.assertEqual(tables["salesdb"], ["dbo.invoices", "dbo.orders"])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Base for Oracle/PostgreSQL/MySQL/SQLite (former test_dbms_enum_a.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class _EnumBaseA(unittest.TestCase):
|
||||
"""Snapshot/restore the global state these enumerators mutate.
|
||||
|
||||
Other tests in the suite depend on clean globals (a leaked kb.hintValue
|
||||
breaks test_inference_engine; a leaked forced DBMS breaks others), so every
|
||||
knob touched here is captured in setUp and put back in tearDown.
|
||||
"""
|
||||
|
||||
# the enumeration module whose inject.getValue we patch (overridden per DBMS)
|
||||
module = None
|
||||
|
||||
def setUp(self):
|
||||
# conf knobs
|
||||
self._direct = conf.direct
|
||||
self._batch = conf.batch
|
||||
self._user = conf.user
|
||||
self._db = conf.get("db")
|
||||
self._tbl = conf.get("tbl")
|
||||
self._exclude = conf.get("exclude")
|
||||
|
||||
# injection layer (some override modules - e.g. SQLite/PostgreSQL - do not
|
||||
# import inject because their overrides return constants without querying)
|
||||
self._has_inject = hasattr(self.module, "inject")
|
||||
if self._has_inject:
|
||||
self._gv = self.module.inject.getValue
|
||||
|
||||
# kb.data cached* containers
|
||||
self._cachedTables = kb.data.get("cachedTables")
|
||||
self._cachedColumns = kb.data.get("cachedColumns")
|
||||
self._cachedDbs = kb.data.get("cachedDbs")
|
||||
self._cachedUsers = kb.data.get("cachedUsers")
|
||||
self._cachedUsersRoles = kb.data.get("cachedUsersRoles")
|
||||
self._cachedUsersPrivileges = kb.data.get("cachedUsersPrivileges")
|
||||
self._has_information_schema = kb.data.get("has_information_schema")
|
||||
|
||||
# state other tests are sensitive to
|
||||
self._hintValue = kb.hintValue
|
||||
self._injectionData = kb.injection.data
|
||||
self._forcedDbms = Backend.getForcedDbms()
|
||||
self._stickyDBMS = kb.stickyDBMS
|
||||
|
||||
# avoid readInput EOFError flakiness and interactive prompts
|
||||
conf.direct = True
|
||||
conf.batch = True
|
||||
|
||||
def tearDown(self):
|
||||
conf.direct = self._direct
|
||||
conf.batch = self._batch
|
||||
conf.user = self._user
|
||||
conf.db = self._db
|
||||
conf.tbl = self._tbl
|
||||
conf.exclude = self._exclude
|
||||
|
||||
if self._has_inject:
|
||||
self.module.inject.getValue = self._gv
|
||||
|
||||
kb.data.cachedTables = self._cachedTables
|
||||
kb.data.cachedColumns = self._cachedColumns
|
||||
kb.data.cachedDbs = self._cachedDbs
|
||||
kb.data.cachedUsers = self._cachedUsers
|
||||
kb.data.cachedUsersRoles = self._cachedUsersRoles
|
||||
kb.data.cachedUsersPrivileges = self._cachedUsersPrivileges
|
||||
kb.data.has_information_schema = self._has_information_schema
|
||||
|
||||
kb.hintValue = self._hintValue
|
||||
kb.injection.data = self._injectionData
|
||||
kb.stickyDBMS = self._stickyDBMS
|
||||
if self._forcedDbms is not None:
|
||||
Backend.forceDbms(self._forcedDbms)
|
||||
else:
|
||||
kb.forcedDbms = None
|
||||
|
||||
|
||||
class TestOracleEnum(_EnumBaseA):
|
||||
module = importlib.import_module("plugins.dbms.oracle.enumeration")
|
||||
|
||||
def _handler(self):
|
||||
from plugins.dbms.oracle import OracleMap
|
||||
set_dbms("Oracle")
|
||||
return OracleMap()
|
||||
|
||||
def test_get_roles(self):
|
||||
# rows are [GRANTEE, GRANTED_ROLE]; first column is the user, the rest roles
|
||||
conf.user = None
|
||||
kb.data.cachedUsersRoles = {}
|
||||
self.module.inject.getValue = lambda q, *a, **k: [
|
||||
["SYS", "DBA"], ["SYS", "CONNECT"], ["SCOTT", "RESOURCE"]
|
||||
]
|
||||
roles, areAdmins = self._handler().getRoles()
|
||||
self.assertIn("SYS", roles)
|
||||
self.assertIn("SCOTT", roles)
|
||||
self.assertEqual(set(roles["SYS"]), {"DBA", "CONNECT"})
|
||||
# DBA implies administrator
|
||||
self.assertIn("SYS", areAdmins)
|
||||
|
||||
def test_get_roles_filtered_by_user(self):
|
||||
# conf.user populates a WHERE clause; canned rows still drive the parse
|
||||
conf.user = "SCOTT"
|
||||
kb.data.cachedUsersRoles = {}
|
||||
self.module.inject.getValue = lambda q, *a, **k: [["SCOTT", "RESOURCE"]]
|
||||
roles, _ = self._handler().getRoles()
|
||||
self.assertEqual(list(roles.keys()), ["SCOTT"])
|
||||
self.assertEqual(roles["SCOTT"], ["RESOURCE"])
|
||||
|
||||
def test_get_roles_multiple_roles_per_user(self):
|
||||
# a user appearing across several rows accumulates all granted roles
|
||||
conf.user = None
|
||||
kb.data.cachedUsersRoles = {}
|
||||
self.module.inject.getValue = lambda q, *a, **k: [
|
||||
["APP", "CONNECT"], ["APP", "RESOURCE"], ["APP", "CREATE SESSION"]
|
||||
]
|
||||
roles, _ = self._handler().getRoles()
|
||||
self.assertEqual(
|
||||
set(roles["APP"]), {"CONNECT", "RESOURCE", "CREATE SESSION"}
|
||||
)
|
||||
|
||||
|
||||
class TestPostgreSQLEnum(_EnumBaseA):
|
||||
module = importlib.import_module("plugins.dbms.postgresql.enumeration")
|
||||
|
||||
def _handler(self):
|
||||
from plugins.dbms.postgresql import PostgreSQLMap
|
||||
set_dbms("PostgreSQL")
|
||||
return PostgreSQLMap()
|
||||
|
||||
def test_get_hostname_unsupported(self):
|
||||
# PostgreSQL overrides getHostname purely to warn; it returns None
|
||||
self.assertIsNone(self._handler().getHostname())
|
||||
|
||||
|
||||
class TestMySQLEnum(_EnumBaseA):
|
||||
# MySQL's enumeration.py adds no overrides (it is a bare `pass`); cover the
|
||||
# generic discovery path through the full MySQL handler instead.
|
||||
module = importlib.import_module("plugins.generic.enumeration")
|
||||
|
||||
def _handler(self):
|
||||
from plugins.dbms.mysql import MySQLMap
|
||||
set_dbms("MySQL")
|
||||
return MySQLMap()
|
||||
|
||||
def test_get_dbs(self):
|
||||
conf.db = None
|
||||
kb.data.cachedDbs = []
|
||||
kb.data.has_information_schema = True
|
||||
self.module.inject.getValue = lambda q, *a, **k: (
|
||||
3 if k.get("expected") == EXPECTED.INT
|
||||
else [["information_schema"], ["testdb"], ["mysql"]]
|
||||
)
|
||||
dbs = self._handler().getDbs()
|
||||
self.assertIn("testdb", dbs)
|
||||
self.assertEqual(set(kb.data.cachedDbs), set(dbs))
|
||||
|
||||
|
||||
class TestSQLiteEnum(_EnumBaseA):
|
||||
module = importlib.import_module("plugins.dbms.sqlite.enumeration")
|
||||
|
||||
def _handler(self):
|
||||
from plugins.dbms.sqlite import SQLiteMap
|
||||
set_dbms("SQLite")
|
||||
return SQLiteMap()
|
||||
|
||||
def test_unsupported_simple_overrides(self):
|
||||
# SQLite overrides these to a warning + an empty/neutral return value
|
||||
h = self._handler()
|
||||
self.assertIsNone(h.getCurrentUser())
|
||||
self.assertIsNone(h.getCurrentDb())
|
||||
self.assertIsNone(h.getHostname())
|
||||
self.assertEqual(h.getUsers(), [])
|
||||
self.assertEqual(h.getDbs(), [])
|
||||
self.assertEqual(h.searchDb(), [])
|
||||
self.assertEqual(h.getStatements(), [])
|
||||
self.assertEqual(h.getPasswordHashes(), {})
|
||||
self.assertEqual(h.getPrivileges(), {})
|
||||
|
||||
def test_is_dba_always_true(self):
|
||||
# on SQLite the current user is treated as having all privileges
|
||||
self.assertTrue(self._handler().isDba())
|
||||
|
||||
def test_search_column_raises(self):
|
||||
with self.assertRaises(SqlmapUnsupportedFeatureException):
|
||||
self._handler().searchColumn()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Base + helpers for Sybase/MaxDB/MSSQL extra/DB2/Informix/Firebird/HSQLDB
|
||||
# (former test_dbms_enum_b.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _fresh_cached():
|
||||
kb.data.cachedDbs = []
|
||||
kb.data.cachedTables = {}
|
||||
kb.data.cachedColumns = {}
|
||||
kb.data.cachedUsers = []
|
||||
kb.data.cachedUsersPrivileges = {}
|
||||
kb.data.cachedCounts = {}
|
||||
kb.data.cachedStatements = []
|
||||
kb.data.banner = None
|
||||
|
||||
|
||||
class _NoOpDumper(object):
|
||||
"""Swallow every dumper call so search methods don't emit/prompt."""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return lambda *a, **k: None
|
||||
|
||||
|
||||
def _handler(display_name, dirname):
|
||||
"""Instantiate the full *Map handler for the given DBMS."""
|
||||
set_dbms(display_name)
|
||||
main = importlib.import_module("plugins.dbms.%s" % dirname)
|
||||
cls = [getattr(main, n) for n in dir(main) if n.endswith("Map")][0]
|
||||
return cls()
|
||||
|
||||
|
||||
class _EnumBaseB(unittest.TestCase):
|
||||
"""Snapshot/restore every global these enumerators mutate."""
|
||||
|
||||
# subclasses set these
|
||||
display_name = None
|
||||
dirname = None
|
||||
|
||||
def setUp(self):
|
||||
# config snapshot
|
||||
self._direct = conf.direct
|
||||
self._batch = conf.batch
|
||||
self._db = conf.db
|
||||
self._tbl = conf.tbl
|
||||
self._col = conf.col
|
||||
self._user = conf.user
|
||||
self._exclude = conf.exclude
|
||||
self._search = conf.search
|
||||
self._getBanner = conf.getBanner
|
||||
self._excludeSysDbs = conf.excludeSysDbs
|
||||
self._dumper = conf.get("dumper")
|
||||
|
||||
# kb snapshot
|
||||
self._cached = {k: kb.data.get(k) for k in (
|
||||
"cachedDbs", "cachedTables", "cachedColumns", "cachedUsers",
|
||||
"cachedUsersPrivileges", "cachedCounts", "cachedStatements", "banner",
|
||||
)}
|
||||
self._hintValue = kb.hintValue
|
||||
self._injectionData = kb.injection.data
|
||||
self._currentDb = kb.data.get("currentDb")
|
||||
self._hasIS = kb.data.get("has_information_schema")
|
||||
|
||||
# injection layer snapshot
|
||||
self._gv = inject.getValue
|
||||
self._cbe = getattr(inject, "checkBooleanExpression", None)
|
||||
|
||||
# baseline config the in-band/non-interactive paths need
|
||||
conf.direct = True
|
||||
conf.batch = True
|
||||
kb.data.has_information_schema = True
|
||||
_fresh_cached()
|
||||
|
||||
# restore the chosen DBMS for every test
|
||||
self.handler = _handler(self.display_name, self.dirname)
|
||||
# the enumeration module whose pivotDumpTable some tests stub
|
||||
self.em = importlib.import_module("plugins.dbms.%s.enumeration" % self.dirname)
|
||||
|
||||
def tearDown(self):
|
||||
conf.direct = self._direct
|
||||
conf.batch = self._batch
|
||||
conf.db = self._db
|
||||
conf.tbl = self._tbl
|
||||
conf.col = self._col
|
||||
conf.user = self._user
|
||||
conf.exclude = self._exclude
|
||||
conf.search = self._search
|
||||
conf.getBanner = self._getBanner
|
||||
conf.excludeSysDbs = self._excludeSysDbs
|
||||
conf.dumper = self._dumper
|
||||
|
||||
for k, v in self._cached.items():
|
||||
kb.data[k] = v
|
||||
kb.hintValue = self._hintValue
|
||||
kb.injection.data = self._injectionData
|
||||
kb.data.currentDb = self._currentDb
|
||||
kb.data.has_information_schema = self._hasIS
|
||||
|
||||
inject.getValue = self._gv
|
||||
if self._cbe is not None:
|
||||
inject.checkBooleanExpression = self._cbe
|
||||
if hasattr(self.em, "pivotDumpTable"):
|
||||
# restore the pristine reference from the wrapper module
|
||||
import lib.utils.pivotdumptable as _pdt
|
||||
self.em.pivotDumpTable = _pdt.pivotDumpTable
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sybase
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestSybaseEnum(_EnumBaseB):
|
||||
display_name = "Sybase"
|
||||
dirname = "sybase"
|
||||
|
||||
def _pivot(self, *value_lists):
|
||||
"""Make em.pivotDumpTable return canned (entries, lengths) per call.
|
||||
|
||||
Each successive call pops the next mapping of {colName: [values]}.
|
||||
"""
|
||||
calls = list(value_lists)
|
||||
|
||||
def fake(table, colList, count=None, blind=True, alias=None):
|
||||
mapping = calls.pop(0) if calls else {}
|
||||
entries = {}
|
||||
lengths = {}
|
||||
for col in colList:
|
||||
vals = mapping.get(col.split(".")[-1], [])
|
||||
entries[col] = list(vals)
|
||||
lengths[col] = 0
|
||||
return entries, lengths
|
||||
|
||||
self.em.pivotDumpTable = fake
|
||||
|
||||
def test_get_users(self):
|
||||
self._pivot({"name": ["sa", "guest"]})
|
||||
users = self.handler.getUsers()
|
||||
self.assertIn("sa", users)
|
||||
self.assertIn("guest", users)
|
||||
|
||||
def test_get_dbs(self):
|
||||
self._pivot({"name": ["master", "model"]})
|
||||
dbs = self.handler.getDbs()
|
||||
self.assertEqual(sorted(dbs), ["master", "model"])
|
||||
|
||||
def test_get_tables(self):
|
||||
conf.db = "testdb"
|
||||
self._pivot({"name": ["users", "logs"]})
|
||||
tables = self.handler.getTables()
|
||||
self.assertIn("testdb", tables)
|
||||
self.assertEqual(sorted(tables["testdb"]), ["logs", "users"])
|
||||
|
||||
def test_get_columns(self):
|
||||
conf.db = "testdb"
|
||||
conf.tbl = "users"
|
||||
# column pivot returns name + usertype: REAL Sybase numeric type ids that
|
||||
# getColumns resolves through SYBASE_TYPES (7 -> "int", 2 -> "varchar").
|
||||
from lib.core.dicts import SYBASE_TYPES
|
||||
self._pivot({"name": ["id", "name"], "usertype": ["7", "2"]})
|
||||
cols = self.handler.getColumns()
|
||||
self.assertIn("testdb", cols)
|
||||
# table key is identifier-normalized (may be schema-qualified)
|
||||
tbls = cols["testdb"]
|
||||
self.assertTrue(any("users" in t for t in tbls))
|
||||
colset = list(tbls.values())[0]
|
||||
# the VALUE is the resolved type name, not the raw usertype number:
|
||||
# proves the SYBASE_TYPES numeric->name mapping actually ran.
|
||||
self.assertEqual(colset["id"], SYBASE_TYPES[7]) # "int"
|
||||
self.assertEqual(colset["name"], SYBASE_TYPES[2]) # "varchar"
|
||||
|
||||
def test_get_privileges(self):
|
||||
# getPrivileges -> getUsers (pivot) then isDba (checkBooleanExpression).
|
||||
# Drive the admin-set branch BOTH ways via the isDba oracle so the result
|
||||
# is not forced by a constant-True stub.
|
||||
conf.user = None
|
||||
|
||||
# oracle True: every user is flagged DBA -> admins == all users
|
||||
self._pivot({"name": ["sa", "guest"]})
|
||||
inject.checkBooleanExpression = lambda *a, **k: True
|
||||
privs, admins = self.handler.getPrivileges()
|
||||
self.assertIn("sa", privs) # users still enumerated as privilege keys
|
||||
self.assertIn("guest", privs)
|
||||
self.assertEqual(admins, set(["sa", "guest"]))
|
||||
|
||||
# oracle False: nobody is a DBA -> admins is empty, but users still listed
|
||||
_fresh_cached()
|
||||
self._pivot({"name": ["sa", "guest"]})
|
||||
inject.checkBooleanExpression = lambda *a, **k: False
|
||||
privs, admins = self.handler.getPrivileges()
|
||||
self.assertIn("sa", privs)
|
||||
self.assertEqual(admins, set())
|
||||
|
||||
def test_search_not_implemented(self):
|
||||
# these intentionally return [] with a warning on Sybase
|
||||
self.assertEqual(self.handler.searchDb(), [])
|
||||
self.assertEqual(self.handler.searchTable(), [])
|
||||
self.assertEqual(self.handler.searchColumn(), [])
|
||||
|
||||
def test_get_hostname(self):
|
||||
# not possible on Sybase; just must not raise
|
||||
self.assertIsNone(self.handler.getHostname())
|
||||
|
||||
def test_get_statements(self):
|
||||
self.assertEqual(self.handler.getStatements(), [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SAP MaxDB
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestMaxDBEnum(_EnumBaseB):
|
||||
display_name = "SAP MaxDB"
|
||||
dirname = "maxdb"
|
||||
|
||||
def _pivot(self, *value_lists):
|
||||
calls = list(value_lists)
|
||||
|
||||
def fake(table, colList, count=None, blind=True, alias=None):
|
||||
mapping = calls.pop(0) if calls else {}
|
||||
entries = {}
|
||||
lengths = {}
|
||||
for col in colList:
|
||||
vals = mapping.get(col.split(".")[-1], [])
|
||||
entries[col] = list(vals)
|
||||
lengths[col] = 0
|
||||
return entries, lengths
|
||||
|
||||
self.em.pivotDumpTable = fake
|
||||
|
||||
def test_get_dbs(self):
|
||||
self._pivot({"schemaname": ["SYSTEM", "DOMAIN"]})
|
||||
dbs = self.handler.getDbs()
|
||||
self.assertEqual(sorted(dbs), ["DOMAIN", "SYSTEM"])
|
||||
|
||||
def test_get_tables(self):
|
||||
conf.db = "SYSTEM"
|
||||
self._pivot({"tablename": ["USERS", "TABLES"]})
|
||||
tables = self.handler.getTables()
|
||||
# db key is identifier-normalized (uppercase names get quoted)
|
||||
self.assertEqual(len(tables), 1)
|
||||
tbls = list(tables.values())[0]
|
||||
self.assertEqual(sorted(tbls), ["TABLES", "USERS"])
|
||||
|
||||
def test_get_columns(self):
|
||||
conf.db = "SYSTEM"
|
||||
conf.tbl = "USERS"
|
||||
self._pivot({
|
||||
"columnname": ["ID", "NAME"],
|
||||
"datatype": ["INTEGER", "CHAR"],
|
||||
"len": ["4", "32"],
|
||||
})
|
||||
cols = self.handler.getColumns()
|
||||
self.assertEqual(len(cols), 1)
|
||||
tbls = list(cols.values())[0]
|
||||
self.assertIn("USERS", tbls)
|
||||
self.assertEqual(tbls["USERS"]["ID"], "INTEGER(4)")
|
||||
|
||||
def test_get_privileges_empty(self):
|
||||
self.assertEqual(self.handler.getPrivileges(), {})
|
||||
|
||||
def test_get_password_hashes_empty(self):
|
||||
self.assertEqual(self.handler.getPasswordHashes(), {})
|
||||
|
||||
def test_get_hostname(self):
|
||||
self.assertIsNone(self.handler.getHostname())
|
||||
|
||||
def test_get_statements(self):
|
||||
self.assertEqual(self.handler.getStatements(), [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Microsoft SQL Server (methods NOT covered by TestMSSQLServerEnum above)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestMSSQLServerExtraEnum(_EnumBaseB):
|
||||
display_name = "Microsoft SQL Server"
|
||||
dirname = "mssqlserver"
|
||||
|
||||
def test_get_privileges(self):
|
||||
# getPrivileges -> getUsers (generic, inject.getValue) then isDba.
|
||||
# Exercise the admin-set branch BOTH ways via the isDba oracle.
|
||||
conf.user = None
|
||||
inject.getValue = lambda q, *a, **k: ["sa", "BUILTIN\\Administrators"]
|
||||
|
||||
# oracle True: all users flagged DBA
|
||||
inject.checkBooleanExpression = lambda *a, **k: True
|
||||
privs, admins = self.handler.getPrivileges()
|
||||
self.assertIn("sa", privs)
|
||||
self.assertEqual(admins, set(["sa", "BUILTIN\\Administrators"]))
|
||||
|
||||
# oracle False: none are DBA -> empty admin set, users still enumerated
|
||||
_fresh_cached()
|
||||
inject.getValue = lambda q, *a, **k: ["sa", "BUILTIN\\Administrators"]
|
||||
inject.checkBooleanExpression = lambda *a, **k: False
|
||||
privs, admins = self.handler.getPrivileges()
|
||||
self.assertIn("sa", privs)
|
||||
self.assertEqual(admins, set())
|
||||
|
||||
def test_search_table(self):
|
||||
conf.db = "testdb"
|
||||
conf.tbl = "users"
|
||||
# in-band branch: getValue returns matching table name(s)
|
||||
inject.getValue = lambda q, *a, **k: ["users"]
|
||||
# capture the discovered tables instead of dumping them
|
||||
captured = {}
|
||||
conf.dumper = _NoOpDumper()
|
||||
self.handler.dumpFoundTables = lambda tables: captured.update(tables)
|
||||
self.handler.searchTable()
|
||||
# at least one database mapped to the matched table
|
||||
flat = set()
|
||||
for tbls in captured.values():
|
||||
flat.update(tbls)
|
||||
self.assertTrue(any("users" in t for t in flat))
|
||||
|
||||
def test_search_column(self):
|
||||
conf.db = "testdb"
|
||||
conf.tbl = None
|
||||
conf.col = "password"
|
||||
# exact match (no wildcard) so no recursive getColumns call;
|
||||
# getValue returns the tables that contain the column
|
||||
inject.getValue = lambda q, *a, **k: ["users"]
|
||||
captured = {}
|
||||
conf.dumper = _NoOpDumper()
|
||||
self.handler.dumpFoundColumn = lambda dbs, foundCols, colConsider: captured.update(dbs)
|
||||
self.handler.searchColumn()
|
||||
# the searched column was located in at least one table
|
||||
flat = set()
|
||||
for tbls in captured.values():
|
||||
flat.update(tbls)
|
||||
self.assertTrue(any("users" in t for t in flat))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# IBM DB2
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestDB2Enum(_EnumBaseB):
|
||||
display_name = "IBM DB2"
|
||||
dirname = "db2"
|
||||
|
||||
def test_get_password_hashes_empty(self):
|
||||
self.assertEqual(self.handler.getPasswordHashes(), {})
|
||||
|
||||
def test_get_statements_empty(self):
|
||||
self.assertEqual(self.handler.getStatements(), [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Informix
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestInformixEnum(_EnumBaseB):
|
||||
display_name = "Informix"
|
||||
dirname = "informix"
|
||||
|
||||
def test_search_db(self):
|
||||
self.assertEqual(self.handler.searchDb(), [])
|
||||
|
||||
def test_search_table(self):
|
||||
self.assertEqual(self.handler.searchTable(), [])
|
||||
|
||||
def test_search_column(self):
|
||||
self.assertEqual(self.handler.searchColumn(), [])
|
||||
|
||||
def test_get_statements(self):
|
||||
self.assertEqual(self.handler.getStatements(), [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Firebird
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestFirebirdEnum(_EnumBaseB):
|
||||
display_name = "Firebird"
|
||||
dirname = "firebird"
|
||||
|
||||
def test_get_dbs_empty(self):
|
||||
self.assertEqual(self.handler.getDbs(), [])
|
||||
|
||||
def test_get_password_hashes_empty(self):
|
||||
self.assertEqual(self.handler.getPasswordHashes(), {})
|
||||
|
||||
def test_search_db_empty(self):
|
||||
self.assertEqual(self.handler.searchDb(), [])
|
||||
|
||||
def test_get_hostname(self):
|
||||
self.assertIsNone(self.handler.getHostname())
|
||||
|
||||
def test_get_statements_empty(self):
|
||||
self.assertEqual(self.handler.getStatements(), [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# HSQLDB
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestHSQLDBEnum(_EnumBaseB):
|
||||
display_name = "HSQLDB"
|
||||
dirname = "hsqldb"
|
||||
|
||||
def test_get_banner(self):
|
||||
conf.getBanner = True
|
||||
kb.data.banner = None
|
||||
# getValue returns a single-element LIST; getBanner pipes it through
|
||||
# unArrayizeValue, which must unwrap it to the scalar banner string.
|
||||
inject.getValue = lambda q, *a, **k: ["HSQLDB 2.5.1"]
|
||||
banner = self.handler.getBanner()
|
||||
self.assertEqual(banner, "HSQLDB 2.5.1")
|
||||
|
||||
def test_get_privileges_empty(self):
|
||||
self.assertEqual(self.handler.getPrivileges(), {})
|
||||
|
||||
def test_get_hostname(self):
|
||||
self.assertIsNone(self.handler.getHostname())
|
||||
|
||||
def test_get_statements_empty(self):
|
||||
self.assertEqual(self.handler.getStatements(), [])
|
||||
|
||||
def test_get_current_db_default_schema(self):
|
||||
from lib.core.settings import HSQLDB_DEFAULT_SCHEMA
|
||||
self.assertEqual(self.handler.getCurrentDb(), HSQLDB_DEFAULT_SCHEMA)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue