Skip to content

Commit e8f8d7e

Browse files
author
adriaan.bosch
committed
mssql: add --database flag to list databases or tables in a named DB
1 parent 83b7148 commit e8f8d7e

2 files changed

Lines changed: 84 additions & 1 deletion

File tree

nxc/protocols/mssql.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,3 +435,83 @@ def rid_brute(self, max_rid=None):
435435

436436
so_far += simultaneous
437437
return entries
438+
439+
def _qname(self, ident: str) -> str:
440+
if ident is None:
441+
return "[]"
442+
return "[" + str(ident).replace("]", "]]") + "]"
443+
444+
def _exec(self, sql: str, params=None):
445+
try:
446+
return self.conn.sql_query(sql, params=params) if params is not None else self.conn.sql_query(sql)
447+
except TypeError:
448+
if params is not None:
449+
return self.conn.sql_query(sql, params)
450+
raise
451+
452+
def list_databases(self):
453+
try:
454+
q = (
455+
"SELECT d.name AS DatabaseName, "
456+
" suser_sname(d.owner_sid) AS Owner "
457+
"FROM sys.databases d "
458+
"ORDER BY d.name;"
459+
)
460+
rows = self._exec(q) or []
461+
if not rows:
462+
self.logger.display("No databases returned")
463+
return
464+
465+
self.logger.display("Enumerated databases")
466+
self.logger.highlight(f"{'Database Name':<30} {'Owner':<25}")
467+
self.logger.highlight(f"{'-'*30} {'-'*25}")
468+
for r in rows:
469+
self.logger.highlight(f"{r.get('DatabaseName',''):<30} {r.get('Owner',''):<25}")
470+
self.logger.highlight(f"Total: {len(rows)} database(s)")
471+
except Exception as e:
472+
self.logger.fail(f"Failed to enumerate databases: {e}")
473+
self.logger.debug("list_databases error", exc_info=True)
474+
475+
def database(self):
476+
db_arg = self.args.database
477+
478+
# nxc --database (no value) -> list
479+
if db_arg is True or db_arg is None:
480+
self.list_databases()
481+
return
482+
483+
# nxc --database <name> -> tables
484+
if isinstance(db_arg, str):
485+
try:
486+
safe = db_arg.replace("'", "''")
487+
exists = self._exec(f"SELECT 1 FROM sys.databases WHERE name = N'{safe}';")
488+
if not exists:
489+
self.logger.fail(f"Database [{db_arg}] does not exist on the server.")
490+
return
491+
492+
tq = (
493+
f"SELECT t.name AS TableName, t.modify_date "
494+
f"FROM {self._qname(db_arg)}.sys.tables t "
495+
f"ORDER BY t.name;"
496+
)
497+
rows = self._exec(tq) or []
498+
except Exception as e:
499+
self.logger.fail(f"Insufficient permissions or query error in [{db_arg}]: {e}")
500+
self.logger.debug("database() error", exc_info=True)
501+
return
502+
503+
if not rows:
504+
self.logger.display(f"Database [{db_arg}] has no user tables.")
505+
return
506+
507+
self.logger.display(f"Tables in database: {db_arg}")
508+
self.logger.highlight(f"{'Table Name':<50} {'Last Modified':<25}")
509+
self.logger.highlight(f"{'-'*50} {'-'*25}")
510+
for r in rows:
511+
mod = r.get('modify_date', '')
512+
if mod and hasattr(mod, 'strftime'):
513+
mod = mod.strftime("%Y-%m-%d %H:%M:%S")
514+
self.logger.highlight(f"{r.get('TableName',''):<50} {str(mod):<25}")
515+
self.logger.highlight(f"Total: {len(rows)} table(s)")
516+
return
517+

nxc/protocols/mssql/proto_args.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ def proto_args(parser, parents):
66
mssql_parser.add_argument("-H", "--hash", metavar="HASH", dest="hash", nargs="+", default=[], help="NTLM hash(es) or file(s) containing NTLM hashes")
77
mssql_parser.add_argument("--port", default=1433, type=int, metavar="PORT", help="MSSQL port")
88
mssql_parser.add_argument("--mssql-timeout", help="SQL server connection timeout", type=int, default=5)
9-
mssql_parser.add_argument("-q", "--query", dest="mssql_query", metavar="QUERY", type=str, help="execute the specified query against the MSSQL DB")
9+
10+
qgroup = mssql_parser.add_mutually_exclusive_group()
11+
qgroup.add_argument("-q", "--query", dest="mssql_query", metavar="SQL", type=str, help="execute the specified query against the mssql db")
12+
qgroup.add_argument("--database", nargs="?", const=True, metavar="NAME", help="list databases or list tables for NAME")
1013

1114
dgroup = mssql_parser.add_mutually_exclusive_group()
1215
dgroup.add_argument("-d", metavar="DOMAIN", dest="domain", type=str, help="domain name")

0 commit comments

Comments
 (0)