Merge pull request #224 from termanix/Update_active_users
Update LDAP active users lookup to match SMBmain
commit
2e311a150b
|
@ -846,32 +846,67 @@ class ldap(connection):
|
||||||
self.logger.fail(f"Skipping item, cannot process due to error {e}")
|
self.logger.fail(f"Skipping item, cannot process due to error {e}")
|
||||||
|
|
||||||
def active_users(self):
|
def active_users(self):
|
||||||
# Building the search filter
|
if len(self.args.active_users) > 0:
|
||||||
|
arg = True
|
||||||
|
self.logger.debug(f"Dumping users: {', '.join(self.args.active_users)}")
|
||||||
|
search_filter = "(sAMAccountType=805306368)" if self.username != "" else "(objectclass=*)"
|
||||||
|
search_filter_args = f"(|{''.join(f'(sAMAccountName={user})' for user in self.args.active_users)})"
|
||||||
|
else:
|
||||||
|
arg = False
|
||||||
|
self.logger.debug("Trying to dump all users")
|
||||||
search_filter = "(sAMAccountType=805306368)" if self.username != "" else "(objectclass=*)"
|
search_filter = "(sAMAccountType=805306368)" if self.username != "" else "(objectclass=*)"
|
||||||
attributes = ["sAMAccountName", "userAccountControl"]
|
|
||||||
|
|
||||||
resp = self.search(search_filter, attributes, sizeLimit=0)
|
# default to these attributes to mirror the SMB --users functionality
|
||||||
if resp:
|
request_attributes = ["sAMAccountName", "description", "badPwdCount", "pwdLastSet", "userAccountControl"]
|
||||||
for item in resp:
|
resp = self.search(search_filter, request_attributes, sizeLimit=0)
|
||||||
|
allusers = parse_result_attributes(resp)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
activeusers = []
|
||||||
|
argsusers = []
|
||||||
|
|
||||||
|
if arg:
|
||||||
|
resp_args = self.search(search_filter_args, request_attributes, sizeLimit=0)
|
||||||
|
users_args = parse_result_attributes(resp_args)
|
||||||
|
# This try except for, if user gives a doesn't exist username. If it does, parsing process is crashing
|
||||||
|
for i in range(len(self.args.active_users)):
|
||||||
|
try:
|
||||||
|
argsusers.append(users_args[i])
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.debug("Exception:", exc_info=True)
|
||||||
|
self.logger.debug(f"Skipping item, cannot process due to error {e}")
|
||||||
|
else:
|
||||||
|
argsusers = allusers
|
||||||
|
|
||||||
|
for user in allusers:
|
||||||
|
account_disabled = int(user.get("userAccountControl")) & 2
|
||||||
|
if not account_disabled:
|
||||||
|
count += 1
|
||||||
|
activeusers.append(user.get("sAMAccountName").lower())
|
||||||
|
|
||||||
|
if self.username == "":
|
||||||
|
self.logger.display(f"Total records returned: {len(resp):d}")
|
||||||
|
for item in resp_args:
|
||||||
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
|
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
|
||||||
continue
|
continue
|
||||||
sAMAccountName = ""
|
|
||||||
userAccountControl = ""
|
|
||||||
try:
|
|
||||||
if self.username == "":
|
|
||||||
self.logger.highlight(f"{item['objectName']}")
|
self.logger.highlight(f"{item['objectName']}")
|
||||||
else:
|
|
||||||
for attribute in item["attributes"]:
|
|
||||||
if str(attribute["type"]) == "sAMAccountName":
|
|
||||||
sAMAccountName = str(attribute["vals"][0])
|
|
||||||
elif str(attribute["type"]) == "userAccountControl":
|
|
||||||
userAccountControl = int(attribute["vals"][0])
|
|
||||||
account_disabled = userAccountControl & 2
|
|
||||||
if not account_disabled:
|
|
||||||
self.logger.highlight(f"{sAMAccountName}")
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.debug(f"Skipping item, cannot process due to error {e}")
|
|
||||||
return
|
return
|
||||||
|
self.logger.display(f"Total records returned: {len(allusers)}, Total {len(allusers) - count:d} user(s) disabled") if not arg else self.logger.display(f"Total records returned: {len(argsusers)}, Total {len(allusers) - count:d} user(s) disabled")
|
||||||
|
self.logger.highlight(f"{'-Username-':<30}{'-Last PW Set-':<20}{'-BadPW-':<8}{'-Description-':<60}")
|
||||||
|
|
||||||
|
for arguser in argsusers:
|
||||||
|
timestamp_seconds = int(arguser.get("pwdLastSet", "")) / 10**7
|
||||||
|
start_date = datetime(1601, 1, 1)
|
||||||
|
parsed_pw_last_set = (start_date + timedelta(seconds=timestamp_seconds)).replace(microsecond=0).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
if parsed_pw_last_set == "1601-01-01 00:00:00":
|
||||||
|
parsed_pw_last_set = "<never>"
|
||||||
|
|
||||||
|
if arguser.get("sAMAccountName").lower() in activeusers and arg is False:
|
||||||
|
self.logger.highlight(f"{arguser.get('sAMAccountName', ''):<30}{parsed_pw_last_set:<20}{arguser.get('badPwdCount', ''):<8}{arguser.get('description', ''):<60}")
|
||||||
|
elif (arguser.get("sAMAccountName").lower() not in activeusers) and arg is True:
|
||||||
|
self.logger.highlight(f"{arguser.get('sAMAccountName', '') + ' (Disabled)':<30}{parsed_pw_last_set:<20}{arguser.get('badPwdCount', ''):<8}{arguser.get('description', ''):<60}")
|
||||||
|
elif (arguser.get("sAMAccountName").lower() in activeusers):
|
||||||
|
self.logger.highlight(f"{arguser.get('sAMAccountName', ''):<30}{parsed_pw_last_set:<20}{arguser.get('badPwdCount', ''):<8}{arguser.get('description', ''):<60}")
|
||||||
|
|
||||||
def asreproast(self):
|
def asreproast(self):
|
||||||
if self.password == "" and self.nthash == "" and self.kerberos is False:
|
if self.password == "" and self.nthash == "" and self.kerberos is False:
|
||||||
|
|
|
@ -24,7 +24,7 @@ def proto_args(parser, std_parser, module_parser):
|
||||||
vgroup.add_argument("--groups", action="store_true", help="Enumerate domain groups")
|
vgroup.add_argument("--groups", action="store_true", help="Enumerate domain groups")
|
||||||
vgroup.add_argument("--dc-list", action="store_true", help="Enumerate Domain Controllers")
|
vgroup.add_argument("--dc-list", action="store_true", help="Enumerate Domain Controllers")
|
||||||
vgroup.add_argument("--get-sid", action="store_true", help="Get domain sid")
|
vgroup.add_argument("--get-sid", action="store_true", help="Get domain sid")
|
||||||
vgroup.add_argument("--active-users", action="store_true", help="Get Active Domain Users Accounts")
|
vgroup.add_argument("--active-users", nargs="*", help="Get Active Domain Users Accounts")
|
||||||
|
|
||||||
ggroup = ldap_parser.add_argument_group("Retrevie gmsa on the remote DC", "Options to play with gmsa")
|
ggroup = ldap_parser.add_argument_group("Retrevie gmsa on the remote DC", "Options to play with gmsa")
|
||||||
ggroup.add_argument("--gmsa", action="store_true", help="Enumerate GMSA passwords")
|
ggroup.add_argument("--gmsa", action="store_true", help="Enumerate GMSA passwords")
|
||||||
|
|
Loading…
Reference in New Issue