def get_membersof(self, kwargs): """ List the members of `group`. Arguments: @verbose:bool Results will contain full information #group:string Group to list members """ group = kwargs["group"] verbose = kwargs.get("verbose", False) results = self.ldap.query(GROUP_DN_FILTER.format(group=group), ["distinguishedName", "objectSid"]) if results: group_dn = results[0]["distinguishedName"] else: error("Group {group} does not exists".format(group=group)) primary_group_id = results[0]["objectSid"].split('-')[-1] results = self.ldap.query( USERS_IN_GROUP_FILTER.format(group=group_dn, primary_group_id=primary_group_id)) self.display(results, verbose)
def __init__(self, ldap_connection, format="json"): try: self.ldap = ldap_connection except ActiveDirectoryView.ActiveDirectoryLdapException as e: error(e) if format == "json": self.__display = self.__display_json
def action_unlock(self, kwargs): """ Unlock `user`. Arguments: #user:string User to unlock """ user = kwargs["user"] if self.engine.unlock(user): info("User {username} unlocked (or was already unlocked)".format(username=user)) else: error("Unable to unlock {username}, check privileges".format(username=user))
def get_from_guid(self, kwargs): """ Return the object associated with the given `guid`. Arguments: @verbose:bool Results will contain full information #guid:string GUID to search for """ guid = kwargs["guid"] verbose = kwargs.get("verbose", False) try: self.display(self.engine.resolve_guid(guid), verbose) except ActiveDirectoryView.ActiveDirectoryLdapInvalidGUID: error("Invalid GUID")
def get_memberships(self, kwargs): """ List the group for which `users` belongs to. Arguments: #user:string User to list memberships @recursive:bool List recursively the groups """ user = kwargs["user"] recursive = kwargs.get("recursive", False) already_printed = set() def lookup_groups(dn, leading_sp, already_treated): groups = [] results = self.ldap.query("(distinguishedName={})".format(dn), ["memberOf"]) for result in results: if "memberOf" in result: for group_dn in result["memberOf"]: if group_dn not in already_treated: print("{g:>{width}}".format(g=group_dn, width=leading_sp + len(group_dn))) already_treated.add(group_dn) treated = lookup_groups(group_dn, leading_sp + 4, already_treated) return treated return already_treated results = self.ldap.query(USER_IN_GROUPS_FILTER.format(username=user), ["memberOf"]) for result in results: if "memberOf" in result: for group_dn in result["memberOf"]: print(group_dn) if recursive: already_printed.add(group_dn) s = lookup_groups(group_dn, 4, already_printed) already_printed.union(s) else: error("No groups for user {}".format(user))
def get_zone(self, kwargs): """ Return the records of a DNS zone. Arguments: #dns_zone:string DNS zone to retrieve records """ dns_zone = kwargs["dns_zone"] try: results = self.engine.query( self.engine.ZONE_FILTER(), base=','.join([f"DC={dns_zone}", "CN=MicrosoftDNS,DC=DomainDNSZones", self.engine.base_dn]) ) except LdapActiveDirectoryView.ActiveDirectoryLdapException as e: error(e) else: self.display(results)
def get_memberships(self, kwargs): """ List the group for which `account` belongs to. Arguments: #account:string User to list memberships @recursive:bool List recursively the groups """ account = kwargs["account"] recursive = kwargs.get("recursive", False) already_printed = set() def lookup_groups(dn, leading_sp, already_treated): groups = [] results = self.engine.query(self.engine.DISTINGUISHED_NAME(dn), ["memberOf"]) for result in results: if "memberOf" in result: for group_dn in result["memberOf"]: if group_dn not in already_treated: print("{g:>{width}}".format(g=group_dn, width=leading_sp + len(group_dn))) already_treated.add(group_dn) lookup_groups(group_dn, leading_sp + 4, already_treated) return already_treated results = self.engine.query(self.engine.USER_IN_GROUPS_FILTER(account), ["memberOf"]) for result in results: if "memberOf" in result: for group_dn in result["memberOf"]: print(group_dn) if recursive: already_printed.add(group_dn) s = lookup_groups(group_dn, 4, already_printed) already_printed.union(s) else: error(f"Account {account} doesn't belong to any group")
def misc_search(self, kwargs): """ Query the LDAP with `filter` and retrieve ALL or `attributes` if specified. Arguments: #filter:string LDAP filter to search for #attributes:string = 'ALL' Comma separated list of attributes to display, ALL for every possible attribute """ attr = kwargs["attributes"] filter_ = kwargs["filter"] try: if attr and attr != "ALL": results = self.engine.query(filter_, attr.split(",")) else: results = self.engine.query(filter_) self.display(results, True) except Exception as e: error(e)
def get_from_sid(self, kwargs): """ Return the object associated with the given `sid`. Arguments: @verbose:bool Results will contain full information #sid:string SID to search for """ sid = kwargs["sid"] verbose = kwargs.get("verbose", False) try: result = self.engine.resolve_sid(sid) if isinstance(result, str): print(result) else: self.display(result, verbose) except ActiveDirectoryView.ActiveDirectoryInvalidSID: error("Invalid SID")
def misc_search(self, kwargs): """ Query the LDAP with `filter` and retrieve ALL or `attributes` if specified. Arguments: #filter:string LDAP filter to search for #attributes:string = 'ALL' Comma separated list of attributes to display, ALL for every possible attribute """ attr = kwargs["attributes"] filter_ = kwargs["filter"] try: if attr and attr != "ALL": results = self.engine.query(filter_, attr.split(",")) else: results = self.engine.query(filter_) self.display(results, True) except PyAsn1UnicodeDecodeError as e: error("Decoding error with the filter") except Exception as e: if e.__str__() == "": error("An exception occurred with the provided filter") else: error(e)
def action_modify_password(self, kwargs): """ Change `user`'s password. Arguments: #user:string User to unlock #newpassword:string New password #currpassword:string = None Current password """ user = kwargs["user"] new = kwargs["newpassword"] curr = kwargs.get("currpassword", None) if curr == "None": curr = None if self.engine.modify_password(user, curr, new): info("Password of {username} changed".format(username=user)) else: error("Unable to change {username}'s password, check privileges or try with ldaps://".format(username=user))
def main(): parser = ArgumentParser() parser.add_argument("-o", "--outfile", default="", help="Store the results in a file") parser.add_argument( "--security_desc", action="store_true", help="Enable the retrieval of security descriptors in ldeep results") sub = parser.add_subparsers(title="Mode", dest="mode", description="Available modes", help="Backend engine to retrieve data") sub.required = True ldap = sub.add_parser("ldap", description="LDAP mode") cache = sub.add_parser("cache", description="Cache mode") ldap.add_argument("-d", "--domain", required=True, help="The domain as NetBIOS or FQDN") ldap.add_argument("-s", "--ldapserver", required=True, help="The LDAP path (ex : ldap://corp.contoso.com:389)") ldap.add_argument( "-b", "--base", default="", help= "LDAP base for query (by default, this value is pulled from remote Ldap)" ) cache.add_argument( "-d", "--dir", default=".", type=str, help="Use saved JSON files in specified directory as cache") cache.add_argument("-p", "--prefix", required=True, type=str, help="Prefix of ldeep saved files") ntlm = ldap.add_argument_group("NTLM authentication") ntlm.add_argument("-u", "--username", help="The username") ntlm.add_argument("-p", "--password", help="The password or the corresponding NTLM hash") kerberos = ldap.add_argument_group("Kerberos authentication") kerberos.add_argument( "-k", "--kerberos", action="store_true", help= "For Kerberos authentication, ticket file should be pointed by $KRB5NAME env variable" ) anonymous = ldap.add_argument_group("Anonymous authentication") anonymous.add_argument("-a", "--anonymous", action="store_true", help="Perform anonymous binds") Ldeep.add_subparsers(ldap, "ldap", ["list_", "get_", "misc_", "action_"], title="commands", description="available commands") Ldeep.add_subparsers(cache, "cache", ["list_", "get_"], title="commands", description="available commands") args = parser.parse_args() # Output if args.outfile: sys.stdout = Logger(args.outfile, quiet=False) cache = "prefix" in args # figuring out whether we use the cache or not # main if cache: try: query_engine = CacheActiveDirectoryView(args.dir, args.prefix) except CacheActiveDirectoryView.CacheActiveDirectoryDirNotFoundException as e: error(e) else: try: # Authentication method = "NTLM" if args.kerberos: method = "Kerberos" elif args.username: method = "NTLM" elif args.anonymous: method = "anonymous" else: error( "Lack of authentication options: either Kerberos, Username with Password (can be a NTLM hash) or Anonymous." ) query_engine = LdapActiveDirectoryView(args.ldapserver, args.domain, args.base, args.username, args.password, method) except LdapActiveDirectoryView.ActiveDirectoryLdapException as e: error(e) # If `security_desc` are requested, enable LDAP Security Descriptor flags and modify the default attributes # In cache mode, the security_desc corresponding JSON field will be kept if args.security_desc: query_engine.set_controls(LDAP_SERVER_SD_FLAGS_OID_SEC_DESC) query_engine.set_all_attributes([ ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, "ntSecurityDescriptor" ]) ldeep = Ldeep(query_engine) try: ldeep.dispatch_command(args) except CacheActiveDirectoryView.CacheActiveDirectoryException as e: error(e) except NotImplementedError: error("Feature not yet available")
def main(): parser = ArgumentParser() parser.add_argument("-d", "--fqdn", help="The domain FQDN (ex : domain.local)", required=True) parser.add_argument( "-s", "--ldapserver", help="The LDAP path (ex : ldap://corp.contoso.com:389)", required=True) parser.add_argument("-b", "--base", default="", help="LDAP base for query") parser.add_argument("-o", "--outfile", default="", help="Store the results in a file") ntlm = parser.add_argument_group("NTLM authentication") ntlm.add_argument("-u", "--username", help="The username") ntlm.add_argument("-p", "--password", help="The password or the corresponding NTLM hash") kerberos = parser.add_argument_group("Kerberos authentication") kerberos.add_argument( "-k", "--kerberos", action="store_true", help= "For Kerberos authentication, ticket file should be pointed by $KRB5NAME env variable" ) anonymous = parser.add_argument_group("Anonymous authentication") anonymous.add_argument("-a", "--anonymous", action="store_true", help="Perform anonymous binds") Ldeep.add_subparsers(parser, ["list_", "get_", "misc_", "action_"], title="commands", description="available commands") args = parser.parse_args() # Authentication method = "NTLM" if args.kerberos: method = "Kerberos" elif args.username: method = "NTLM" elif args.anonymous: method = "anonymous" else: error( "Lack of authentication options: either Kerberos or Username with Password (can be a NTLM hash)." ) # Output if args.outfile: sys.stdout = Logger(args.outfile, quiet=False) # main try: ldap_connection = ActiveDirectoryView(args.ldapserver, args.fqdn, args.base, args.username, args.password, method) except ActiveDirectoryView.ActiveDirectoryLdapException as e: error(e) ldeep = Ldeep(ldap_connection) ldeep.dispatch_command(args)