Skip to content

Commit 166df14

Browse files
Merge branch 'main' into marshall-db-ip-fix
2 parents f0602c7 + aa832c5 commit 166df14

10 files changed

Lines changed: 109 additions & 116 deletions

File tree

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from impacket.ldap import ldapasn1 as ldapasn1_impacket
21
from impacket.ldap import ldap as ldap_impacket
32
from nxc.logger import nxc_logger
3+
from nxc.parsers.ldap_results import parse_result_attributes
44

55

66
class NXCModule:
@@ -20,7 +20,7 @@ def options(self, context, module_options):
2020
"""
2121

2222
def on_login(self, context, connection):
23-
searchFilter = "(objectclass=user)"
23+
searchFilter = "(unixUserPassword=*)"
2424

2525
try:
2626
context.log.debug(f"Search Filter={searchFilter}")
@@ -37,27 +37,10 @@ def on_login(self, context, connection):
3737
nxc_logger.debug(e)
3838
return False
3939

40-
answers = []
41-
context.log.debug(f"Total of records returned {len(resp)}")
42-
for item in resp:
43-
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
44-
continue
45-
sAMAccountName = ""
46-
unixUserPassword = []
47-
try:
48-
for attribute in item["attributes"]:
49-
if str(attribute["type"]) == "sAMAccountName":
50-
sAMAccountName = str(attribute["vals"][0])
51-
elif str(attribute["type"]) == "unixUserPassword":
52-
unixUserPassword = [str(i) for i in attribute["vals"]]
53-
if sAMAccountName != "" and len(unixUserPassword) > 0:
54-
answers.append([sAMAccountName, unixUserPassword])
55-
except Exception as e:
56-
context.log.debug("Exception:", exc_info=True)
57-
context.log.debug(f"Skipping item, cannot process due to error {e!s}")
58-
if len(answers) > 0:
40+
if resp:
41+
resp_parsed = parse_result_attributes(resp)
5942
context.log.success("Found following users: ")
60-
for answer in answers:
61-
context.log.highlight(f"User: {answer[0]} unixUserPassword: {answer[1]}")
43+
for user in resp_parsed:
44+
context.log.highlight(f"User: {user['sAMAccountName']} unixUserPassword: {user['unixUserPassword']}")
6245
else:
6346
context.log.fail("No unixUserPassword Found")

nxc/modules/get-userPassword.py

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from impacket.ldap import ldapasn1 as ldapasn1_impacket
21
from impacket.ldap import ldap as ldap_impacket
32
from nxc.logger import nxc_logger
3+
from nxc.parsers.ldap_results import parse_result_attributes
44

55

66
class NXCModule:
@@ -20,7 +20,7 @@ def options(self, context, module_options):
2020
"""
2121

2222
def on_login(self, context, connection):
23-
searchFilter = "(objectclass=user)"
23+
searchFilter = "(userPassword=*)"
2424

2525
try:
2626
context.log.debug(f"Search Filter={searchFilter}")
@@ -37,27 +37,10 @@ def on_login(self, context, connection):
3737
nxc_logger.debug(e)
3838
return False
3939

40-
answers = []
41-
context.log.debug(f"Total of records returned {len(resp)}")
42-
for item in resp:
43-
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
44-
continue
45-
sAMAccountName = ""
46-
userPassword = []
47-
try:
48-
for attribute in item["attributes"]:
49-
if str(attribute["type"]) == "sAMAccountName":
50-
sAMAccountName = str(attribute["vals"][0])
51-
elif str(attribute["type"]) == "userPassword":
52-
userPassword = [str(i) for i in attribute["vals"]]
53-
if sAMAccountName != "" and len(userPassword) > 0:
54-
answers.append([sAMAccountName, userPassword])
55-
except Exception as e:
56-
context.log.debug("Exception:", exc_info=True)
57-
context.log.debug(f"Skipping item, cannot process due to error {e!s}")
58-
if len(answers) > 0:
40+
if resp:
41+
resp_parsed = parse_result_attributes(resp)
5942
context.log.success("Found following users: ")
60-
for answer in answers:
61-
context.log.highlight(f"User: {answer[0]} userPassword: {answer[1]}")
43+
for user in resp_parsed:
44+
context.log.highlight(f"User: {user['sAMAccountName']} unixUserPassword: {user['userPassword']}")
6245
else:
63-
context.log.fail("No userPassword Found")
46+
context.log.fail("No unixUserPassword Found")

nxc/modules/wcc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def init_checks(self):
174174
ConfigCheck("IPv4 preferred over IPv6", "Checks if IPv4 is preferred over IPv6", checker_args=[[self, ("HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters", "DisabledComponents", (32, 255), in_)]]),
175175
ConfigCheck("Spooler service disabled", "Checks if the spooler service is disabled", checkers=[self.check_spooler_service]),
176176
ConfigCheck("WDigest authentication disabled", "Checks if WDigest authentication is disabled", checker_args=[[self, ("HKLM\\SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest", "UseLogonCredential", 0)]]),
177-
ConfigCheck("WSUS configuration", "Checks if WSUS configuration uses HTTPS", checkers=[self.check_wsus_running, None], checker_args=[[], [self, ("HKLM\\Software\\Policies\\Microsoft\\Windows\\WindowsUpdate", "WUServer", "https://", startswith), ("HKLM\\Software\\Policies\\Microsoft\\Windows\\WindowsUpdate", "UseWUServer", 0, operator.eq)]], checker_kwargs=[{}, {"options": {"lastWins": True}}]),
177+
ConfigCheck("WSUS configuration", "Checks if WSUS configuration uses HTTPS", checkers=[self.check_wsus_running, None], checker_args=[[], [self, ("HKLM\\Software\\Policies\\Microsoft\\Windows\\WindowsUpdate", "WUServer", "https://", startswith), ("HKLM\\Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU", "UseWUServer", 0, operator.eq)]], checker_kwargs=[{}, {"options": {"lastWins": True}}]),
178178
ConfigCheck("Small LSA cache", "Checks how many logons are kept in the LSA cache", checker_args=[[self, ("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", "CachedLogonsCount", 2, le)]]),
179179
ConfigCheck("AppLocker rules defined", "Checks if there are AppLocker rules defined", checkers=[self.check_applocker]),
180180
ConfigCheck("RDP expiration time", "Checks RDP session timeout", checker_args=[[self, ("HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows NT\\Terminal Services", "MaxDisconnectionTime", 0, operator.gt), ("HKCU\\SOFTWARE\\Policies\\Microsoft\\Windows NT\\Terminal Services", "MaxDisconnectionTime", 0, operator.gt)]]),

nxc/parsers/ldap_results.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ def parse_result_attributes(ldap_response):
1818
# If we can't decode the value, we'll just return the bytes
1919
val_decoded = val.__bytes__()
2020
val_list.append(val_decoded)
21-
attribute_map[str(attribute["type"])] = val_list if len(val_list) > 1 else val_list[0]
21+
if len(val_list) == 1:
22+
attribute_map[str(attribute["type"])] = val_list[0]
23+
else:
24+
attribute_map[str(attribute["type"])] = val_list
2225
parsed_response.append(attribute_map)
2326
return parsed_response

nxc/protocols/ldap.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import hashlib
44
import hmac
55
import os
6-
from errno import EHOSTUNREACH
6+
from errno import EHOSTUNREACH, ETIMEDOUT, ENETUNREACH
77
from binascii import hexlify
88
from datetime import datetime
99
from re import sub, I
@@ -211,7 +211,7 @@ def create_conn_obj(self):
211211
self.logger.debug(f"{e} on host {self.host}")
212212
return False
213213
except OSError as e:
214-
if e.errno == EHOSTUNREACH:
214+
if e.errno in (EHOSTUNREACH, ENETUNREACH, ETIMEDOUT):
215215
self.logger.info(f"Error connecting to {self.host} - {e}")
216216
return False
217217
else:
@@ -992,19 +992,20 @@ def query(self):
992992
self.logger.debug(f"Querying LDAP server with filter: {search_filter} and attributes: {attributes}")
993993
try:
994994
resp = self.search(search_filter, attributes, 0)
995+
resp_parsed = parse_result_attributes(resp)
995996
except LDAPFilterSyntaxError as e:
996997
self.logger.fail(f"LDAP Filter Syntax Error: {e}")
997998
return
998-
for item in resp:
999-
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
1000-
continue
1001-
self.logger.success(f"Response for object: {item['objectName']}")
1002-
for attribute in item["attributes"]:
1003-
attr = f"{attribute['type']}:"
1004-
vals = str(attribute["vals"]).replace("\n", "")
1005-
if "SetOf: " in vals:
1006-
vals = vals.replace("SetOf: ", "")
1007-
self.logger.highlight(f"{attr:<20} {vals}")
999+
for idx, entry in enumerate(resp_parsed):
1000+
self.logger.success(f"Response for object: {resp[idx]['objectName']}")
1001+
for attribute in entry:
1002+
if isinstance(entry[attribute], list) and entry[attribute]:
1003+
# Display first item in the same line as attribute
1004+
self.logger.highlight(f"{attribute:<20} {entry[attribute].pop(0)}")
1005+
for item in entry[attribute]:
1006+
self.logger.highlight(f"{'':<20} {item}")
1007+
else:
1008+
self.logger.highlight(f"{attribute:<20} {entry[attribute]}")
10081009

10091010
def find_delegation(self):
10101011
def printTable(items, header):

nxc/protocols/nfs.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,22 +246,23 @@ def shares(self):
246246
mnt_info = self.mount.mnt(share, self.auth)
247247
self.logger.debug(f"Mounted {share} - {mnt_info}")
248248
if mnt_info["status"] != 0:
249-
self.logger.fail(f"Error mounting share {share}: {NFSSTAT3[mnt_info['status']]}")
250-
continue
251-
file_handle = mnt_info["mountinfo"]["fhandle"]
249+
self.logger.debug(f"Error mounting share {share}: {NFSSTAT3[mnt_info['status']]}")
250+
self.logger.highlight(f"{'-':<11}{'---':<9}{'---'}/{'---':<12} {share:<30} {', '.join(network) if network else 'No network':<15}")
251+
else:
252+
file_handle = mnt_info["mountinfo"]["fhandle"]
252253

253-
info = self.nfs3.fsstat(file_handle, self.auth)
254-
free_space = info["resok"]["fbytes"]
255-
total_space = info["resok"]["tbytes"]
256-
used_space = total_space - free_space
254+
info = self.nfs3.fsstat(file_handle, self.auth)
255+
free_space = info["resok"]["fbytes"]
256+
total_space = info["resok"]["tbytes"]
257+
used_space = total_space - free_space
257258

258-
# Autodetectting the uid needed for the share
259-
attrs = self.nfs3.getattr(file_handle, auth=self.auth)
260-
self.auth["uid"] = attrs["attributes"]["uid"]
259+
# Autodetectting the uid needed for the share
260+
attrs = self.nfs3.getattr(file_handle, auth=self.auth)
261+
self.auth["uid"] = attrs["attributes"]["uid"]
261262

262-
read_perm, write_perm, exec_perm = self.get_permissions(file_handle)
263-
self.mount.umnt(self.auth)
264-
self.logger.highlight(f"{self.auth['uid']:<11}{'r' if read_perm else '-'}{'w' if write_perm else '-'}{('x' if exec_perm else '-'):<7}{convert_size(used_space)}/{convert_size(total_space):<9} {share:<30} {', '.join(network) if network else 'No network':<15}")
263+
read_perm, write_perm, exec_perm = self.get_permissions(file_handle)
264+
self.mount.umnt(self.auth)
265+
self.logger.highlight(f"{self.auth['uid']:<11}{'r' if read_perm else '-'}{'w' if write_perm else '-'}{('x' if exec_perm else '-'):<7}{convert_size(used_space) + "/" + convert_size(total_space):<16} {share:<30} {', '.join(network) if network else 'No network':<15}")
265266
except Exception as e:
266267
self.logger.fail(f"Failed to list share: {share} - {e}")
267268

nxc/protocols/nfs/proto_args.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
def proto_args(parser, parents):
22
nfs_parser = parser.add_parser("nfs", help="own stuff using NFS", parents=parents)
33
nfs_parser.add_argument("--port", type=int, default=111, help="NFS portmapper port (default: %(default)s)")
4-
nfs_parser.add_argument("--nfs-timeout", type=int, default=30, help="NFS connection timeout (default: %(default)ss)")
4+
nfs_parser.add_argument("--nfs-timeout", type=int, default=5, help="NFS connection timeout (default: %(default)ss)")
55

66
dgroup = nfs_parser.add_argument_group("NFS Mapping/Enumeration", "Options for Mapping/Enumerating NFS")
77
dgroup.add_argument("--share", help="Specify a share, e.g. for --ls, --get-file, --put-file")

0 commit comments

Comments
 (0)