Skip to content

Commit fbd4e1a

Browse files
authored
Merge branch 'main' into patch-8
2 parents a9ef92b + 131e29e commit fbd4e1a

40 files changed

Lines changed: 965 additions & 258 deletions

nxc/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ def parse_credentials(self):
384384
if isfile(user):
385385
with open(user) as user_file:
386386
for line in user_file:
387-
if "\\" in line:
387+
if "\\" in line and len(line.split("\\")) == 2:
388388
domain_single, username_single = line.split("\\")
389389
else:
390390
domain_single = self.args.domain if hasattr(self.args, "domain") and self.args.domain else self.domain

nxc/modules/adcs.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ def on_login(self, context, connection):
4949

5050
try:
5151
sc = ldap.SimplePagedResultsControl()
52-
base_dn_root = connection.ldapConnection._baseDN if self.base_dn is None else self.base_dn
52+
base_dn_root = connection.ldap_connection._baseDN if self.base_dn is None else self.base_dn
5353

5454
if self.server is None:
55-
connection.ldapConnection.search(
55+
connection.ldap_connection.search(
5656
searchFilter=search_filter,
5757
attributes=[],
5858
sizeLimit=0,
@@ -61,7 +61,7 @@ def on_login(self, context, connection):
6161
searchBase="CN=Configuration," + base_dn_root,
6262
)
6363
else:
64-
connection.ldapConnection.search(
64+
connection.ldap_connection.search(
6565
searchFilter=search_filter + base_dn_root + ")",
6666
attributes=["certificateTemplates"],
6767
sizeLimit=0,

nxc/modules/daclread.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@ def on_login(self, context, connection):
274274
self.context = context
275275
"""On a successful LDAP login we perform a search for the targets' SID, their Security Descriptors and the principal's SID if there is one specified"""
276276
context.log.highlight("Be careful, this module cannot read the DACLS recursively.")
277-
self.baseDN = connection.ldapConnection._baseDN
278-
self.ldap_session = connection.ldapConnection
277+
self.baseDN = connection.ldap_connection._baseDN
278+
self.ldap_session = connection.ldap_connection
279279

280280
# Searching for the principal SID
281281
if self.principal_sAMAccountName is not None:

nxc/modules/enum_impersonate.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
class NXCModule:
2+
"""
3+
Enumerate SQL Server users with impersonation rights
4+
Module by deathflamingo
5+
"""
6+
7+
name = "enum_impersonate"
8+
description = "Enumerate users with impersonation privileges"
9+
supported_protocols = ["mssql"]
10+
opsec_safe = True
11+
multiple_hosts = True
12+
13+
def __init__(self):
14+
self.mssql_conn = None
15+
self.context = None
16+
17+
def on_login(self, context, connection):
18+
self.context = context
19+
self.mssql_conn = connection.conn
20+
impersonate_users = self.get_impersonate_users()
21+
if impersonate_users:
22+
self.context.log.success("Users with impersonation rights:")
23+
for user in impersonate_users:
24+
self.context.log.display(f" - {user}")
25+
else:
26+
self.context.log.fail("No users with impersonation rights found.")
27+
28+
def get_impersonate_users(self) -> list:
29+
"""
30+
Fetches a list of users with impersonation rights.
31+
32+
Returns
33+
-------
34+
list: List of user names.
35+
"""
36+
query = """
37+
SELECT DISTINCT b.name
38+
FROM sys.server_permissions a
39+
INNER JOIN sys.server_principals b
40+
ON a.grantor_principal_id = b.principal_id
41+
WHERE a.permission_name LIKE 'IMPERSONATE%'
42+
"""
43+
res = self.mssql_conn.sql_query(query)
44+
return [user["name"] for user in res] if res else []
45+
def options(self, context, module_options):
46+
pass

nxc/modules/enum_links.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class NXCModule:
2+
"""
3+
Enumerate SQL Server linked servers
4+
Module by deathflamingo, NeffIsBack
5+
"""
6+
7+
name = "enum_links"
8+
description = "Enumerate linked SQL Servers and their login configurations."
9+
supported_protocols = ["mssql"]
10+
opsec_safe = True
11+
multiple_hosts = True
12+
13+
def __init__(self):
14+
self.mssql_conn = None
15+
self.context = None
16+
17+
def options(self, context, module_options):
18+
pass
19+
20+
def on_login(self, context, connection):
21+
self.context = context
22+
self.mssql_conn = connection.conn
23+
linked_servers = self.get_linked_servers()
24+
if linked_servers:
25+
self.context.log.success("Linked servers found:")
26+
for server in linked_servers:
27+
self.context.log.display(f" - {server}")
28+
else:
29+
self.context.log.fail("No linked servers found.")
30+
31+
def on_admin_login(self, context, connection):
32+
res = self.mssql_conn.sql_query("EXEC sp_helplinkedsrvlogin")
33+
srvs = [srv for srv in res if srv["Local Login"] != "NULL"]
34+
if not srvs:
35+
self.context.log.fail("No linked servers found.")
36+
return
37+
self.context.log.success("Linked servers found:")
38+
for srv in srvs:
39+
self.context.log.display(f"Linked server: {srv['Linked Server']}")
40+
self.context.log.display(f" - Local login: {srv['Local Login']}")
41+
self.context.log.display(f" - Remote login: {srv['Remote Login']}")
42+
43+
def get_linked_servers(self) -> list:
44+
"""
45+
Fetches a list of linked servers.
46+
47+
Returns
48+
-------
49+
list: List of linked server names.
50+
"""
51+
query = "EXEC sp_linkedservers;"
52+
res = self.mssql_conn.sql_query(query)
53+
return [server["SRV_NAME"] for server in res] if res else []

nxc/modules/enum_logins.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
class NXCModule:
2+
"""
3+
Enumerate SQL Server logins
4+
Module by deathflamingo
5+
"""
6+
7+
name = "enum_logins"
8+
description = "Enumerate SQL Server logins"
9+
supported_protocols = ["mssql"]
10+
opsec_safe = True
11+
multiple_hosts = True
12+
13+
def __init__(self):
14+
self.mssql_conn = None
15+
self.context = None
16+
17+
def on_login(self, context, connection):
18+
self.context = context
19+
self.mssql_conn = connection.conn
20+
logins = self.get_logins()
21+
if logins:
22+
self.context.log.success("Logins found:")
23+
for login in logins:
24+
self.context.log.display(f" - {login}")
25+
else:
26+
self.context.log.fail("No logins found.")
27+
28+
def get_logins(self) -> list:
29+
"""
30+
Fetches a list of SQL Server logins.
31+
32+
Returns
33+
-------
34+
list: List of login names.
35+
"""
36+
query = "SELECT name FROM sys.server_principals WHERE type_desc = 'SQL_LOGIN';"
37+
res = self.mssql_conn.sql_query(query)
38+
return [login["name"] for login in res] if res else []
39+
def options(self, context, module_options):
40+
pass

nxc/modules/enum_trusts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def on_login(self, context, connection):
2121
attributes = ["flatName", "trustPartner", "trustDirection", "trustAttributes"]
2222

2323
context.log.debug(f"Search Filter={search_filter}")
24-
resp = connection.ldapConnection.search(searchFilter=search_filter, attributes=attributes, sizeLimit=0)
24+
resp = connection.ldap_connection.search(searchFilter=search_filter, attributes=attributes, sizeLimit=0)
2525

2626
trusts = []
2727
context.log.debug(f"Total of records returned {len(resp)}")

nxc/modules/exec_on_link.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
class NXCModule:
2+
"""
3+
Execute commands on linked servers
4+
Module by deathflamingo
5+
"""
6+
7+
name = "exec_on_link"
8+
description = "Execute commands on a SQL Server linked server"
9+
supported_protocols = ["mssql"]
10+
opsec_safe = False
11+
multiple_hosts = False
12+
13+
def __init__(self):
14+
self.mssql_conn = None
15+
self.context = None
16+
self.linked_server = None
17+
self.command = None
18+
19+
def options(self, context, module_options):
20+
"""
21+
LINKED_SERVER: The name of the linked server to execute the command on.
22+
COMMAND: The command to execute on the linked server.
23+
"""
24+
if "LINKED_SERVER" in module_options:
25+
self.linked_server = module_options["LINKED_SERVER"]
26+
if "COMMAND" in module_options:
27+
self.command = module_options["COMMAND"]
28+
29+
def on_login(self, context, connection):
30+
self.context = context
31+
self.mssql_conn = connection.conn
32+
if not self.linked_server or not self.command:
33+
self.context.log.fail("Please specify both LINKED_SERVER and COMMAND options.")
34+
return
35+
36+
self.execute_on_link()
37+
38+
def execute_on_link(self):
39+
"""Executes the specified command on the linked server."""
40+
query = f"EXEC ('{self.command}') AT [{self.linked_server}];"
41+
result = self.mssql_conn.sql_query(query)
42+
self.context.log.display(f"Command output: {result}")

nxc/modules/find-computer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def on_login(self, context, connection):
3939

4040
try:
4141
context.log.debug(f"Search Filter={search_filter}")
42-
resp = connection.ldapConnection.search(searchFilter=search_filter, attributes=["dNSHostName", "operatingSystem"], sizeLimit=0)
42+
resp = connection.ldap_connection.search(searchFilter=search_filter, attributes=["dNSHostName", "operatingSystem"], sizeLimit=0)
4343
except LDAPSearchError as e:
4444
if e.getErrorString().find("sizeLimitExceeded") >= 0:
4545
context.log.debug("sizeLimitExceeded exception caught, giving up and processing the data received")

nxc/modules/get-desc-users.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def on_login(self, context, connection):
4040

4141
try:
4242
context.log.debug(f"Search Filter={searchFilter}")
43-
resp = connection.ldapConnection.search(
43+
resp = connection.ldap_connection.search(
4444
searchFilter=searchFilter,
4545
attributes=["sAMAccountName", "description"],
4646
sizeLimit=0,

0 commit comments

Comments
 (0)