From e131096243bb8bce984b624e118d4aa12c8311b6 Mon Sep 17 00:00:00 2001 From: wil Date: Fri, 1 Mar 2024 01:04:51 +0100 Subject: [PATCH] Add lapsV2 detection --- VERSION | 2 +- ldeep/__main__.py | 24 +++++++++++++++++++++--- ldeep/views/ldap_activedirectory.py | 3 ++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 46354d7..b649b91 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.52 +1.0.53 diff --git a/ldeep/__main__.py b/ldeep/__main__.py index 8ec4416..68ce069 100755 --- a/ldeep/__main__.py +++ b/ldeep/__main__.py @@ -1030,16 +1030,16 @@ def get_laps(self, kwargs): @computer:string Target computer where LAPS is set """ - computer = kwargs["computer"] if kwargs["computer"] else "*" + computer = kwargs.get("computer", "*") verbose = kwargs.get("verbose", False) attributes = ALL if verbose else ["dNSHostName", "ms-Mcs-AdmPwd", "ms-Mcs-AdmPwdExpirationTime"] try: + # LAPSv1 entries = self.engine.query(self.engine.LAPS_FILTER(computer), attributes) for entry in entries: if not verbose: - # TODO: deal with self.display for better code cn = entry['dNSHostName'] password = entry['ms-Mcs-AdmPwd'] try: @@ -1050,8 +1050,26 @@ def get_laps(self, kwargs): print(f'{cn} {password} {expiration_date}') else: self.display(entries, verbose) + except LDAPAttributeError: + try: + # LAPSv2 + attributes = ALL if verbose else ["dNSHostName", "msLAPS-EncryptedPassword", "msLAPS-PasswordExpirationTime"] + entries = self.engine.query(self.engine.LAPS2_FILTER(computer), attributes) + computers = list(entries) + computer_count = len(computers) + if computer_count > 0: + print("LAPSv2 detected, password decryption is not implemented") + if not verbose: + for c in computers: + if c['msLAPS-EncryptedPassword']: + print(f"{c['dNSHostName']}:::{b64encode(c['msLAPS-EncryptedPassword'])}") + else: + print(f"{c['dNSHostName']}") + except Exception as e: + print(e) + error("No LAPS related attribute has been detected") except Exception as e: - error(e) + error(f"{e}. No LAPS attribute or not enough permission to read it.") def get_object(self, kwargs): """ diff --git a/ldeep/views/ldap_activedirectory.py b/ldeep/views/ldap_activedirectory.py index 27c163a..ca425d3 100644 --- a/ldeep/views/ldap_activedirectory.py +++ b/ldeep/views/ldap_activedirectory.py @@ -166,7 +166,8 @@ class LdapActiveDirectoryView(ActiveDirectoryView): AUTH_POLICIES_FILTER = lambda _: "(objectClass=msDS-AuthNPolicy)" SILOS_FILTER = lambda _: "(objectClass=msDS-AuthNPolicySilo)" SILO_FILTER = lambda _, s: f"(&(objectClass=msDS-AuthNPolicySilo)(cn={s}))" - LAPS_FILTER = lambda _, s: f"(&(objectCategory=computer)(ms-MCS-AdmPwd=*)(cn={s}))" + LAPS_FILTER = lambda _, s: f"(&(objectCategory=computer)(ms-Mcs-AdmPwdExpirationTime=*)(cn={s}))" + LAPS2_FILTER = lambda _, s: f"(&(objectCategory=computer)(msLAPS-PasswordExpirationTime=*)(cn={s}))" SMSA_FILTER = lambda _: "(ObjectClass=msDS-ManagedServiceAccount)" BITLOCKERKEY_FILTER = lambda _: "(objectClass=msFVE-RecoveryInformation)" FSMO_DOMAIN_NAMING_FILTER = lambda _: "(&(objectClass=crossRefContainer)(fSMORoleOwner=*))"