diff --git a/nxc/protocols/ldap.py b/nxc/protocols/ldap.py index 386565cb..d841a804 100644 --- a/nxc/protocols/ldap.py +++ b/nxc/protocols/ldap.py @@ -792,6 +792,52 @@ class ldap(connection): self.logger.debug("Exception:", exc_info=True) self.logger.debug(f"Skipping item, cannot process due to error {e}") + def ous(self): + if self.args.ous: + # Find the OU's distinguished name first + self.logger.debug(f"Dumping users from OU: {self.args.ous}") + ou_resp = self.search( + f"(&(objectCategory=organizationalUnit)(ou={self.args.ous}))", + ["distinguishedName"], + ) + ou_parsed = parse_result_attributes(ou_resp) + + if not ou_parsed: + self.logger.fail(f"OU '{self.args.ous}' not found") + return + + self.logger.debug(f"Found OU DN: {ou_parsed[0]['distinguishedName']}") + + # Search for users scoped to that OU + resp = self.search( + "(&(objectCategory=person)(objectClass=user))", + ["sAMAccountName", "cn"], + baseDN=ou_parsed[0]["distinguishedName"], + ) + resp_parsed = parse_result_attributes(resp) + self.logger.debug(f"Total of records returned: {len(resp_parsed)}") + + if not resp_parsed: + self.logger.fail(f"OU '{self.args.ous}' has no users") + return + + self.logger.highlight(f"{'-sAMAccountName-':<30} -cn-") + for user in resp_parsed: + self.logger.highlight(f"{user.get('sAMAccountName'):<30} {user.get('cn', '')}") + else: + # List all OUs + self.logger.debug("Dumping all organizational units") + resp = self.search("(objectCategory=organizationalUnit)", ["ou", "distinguishedName"]) + resp_parsed = parse_result_attributes(resp) + self.logger.debug(f"Total of records returned: {len(resp_parsed)}") + + self.logger.highlight(f"{'-OU-':<40} -Distinguished Name-") + for ou in resp_parsed: + try: + self.logger.highlight(f"{ou['ou']:<40} {ou['distinguishedName']}") + except Exception as e: + self.logger.debug(f"Exception: {e}", exc_info=True) + def computers(self): resp = self.search(f"(sAMAccountType={SAM_MACHINE_ACCOUNT})", ["sAMAccountName"]) resp_parsed = parse_result_attributes(resp) diff --git a/nxc/protocols/ldap/proto_args.py b/nxc/protocols/ldap/proto_args.py index 63836860..aa836396 100644 --- a/nxc/protocols/ldap/proto_args.py +++ b/nxc/protocols/ldap/proto_args.py @@ -32,6 +32,7 @@ def proto_args(parser, parents): vgroup.add_argument("--users", nargs="*", help="Enumerate domain users") vgroup.add_argument("--users-export", help="Enumerate domain users and export them to the specified file") vgroup.add_argument("--groups", nargs="?", const="", help="Enumerate domain groups, if a group is specified than its members are enumerated") + vgroup.add_argument("--ous", nargs="?", const="", help="Specify OU name to query all users in that OU or list all OUs") vgroup.add_argument("--computers", action="store_true", help="Enumerate domain computers") vgroup.add_argument("--dc-list", action="store_true", help="Enumerate Domain Controllers") vgroup.add_argument("--get-sid", action="store_true", help="Get domain sid") diff --git a/tests/e2e_commands.txt b/tests/e2e_commands.txt index e966b9ea..40dcb99f 100644 --- a/tests/e2e_commands.txt +++ b/tests/e2e_commands.txt @@ -214,6 +214,8 @@ netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --simple-b netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --users netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --users-export /tmp/userlistOutputFilename.txt netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --groups +netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --ous +netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --ous TARGET_OU netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --get-sid netexec ldap TARGET_HOST -u LOGIN_USERNAME -p '' --asreproast /tmp/output.txt netexec ldap TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --kerberoasting /tmp/kerberoasting1.txt