def __getLocalAdminSids(self): dce = self.__getDceBinding(self.__samrBinding) dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, 'Builtin') resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] resp = samr.hSamrEnumerateAliasesInDomain(dce, domainHandle) aliases = {} for alias in resp['Buffer']['Buffer']: aliases[alias['Name']] = alias['RelativeId'] resp = samr.hSamrOpenAlias(dce, domainHandle, desiredAccess=MAXIMUM_ALLOWED, aliasId=aliases['Administrators']) resp = samr.hSamrGetMembersInAlias(dce, resp['AliasHandle']) memberSids = [] for member in resp['Members']['Sids']: memberSids.append(member['SidPointer'].formatCanonical()) dce.disconnect() return memberSids
def getAliasMembers(self, domainHandle, aliasId): aliasHandle = self.getAliasHandle(domainHandle, aliasId) resp = samr.hSamrGetMembersInAlias(self.dce, aliasHandle) memberSids = [] for member in resp['Members']['Sids']: memberSids.append(member['SidPointer'].formatCanonical()) return memberSids
def __fetchAdminSidList(self, rpctransport): dce = rpctransport.get_dce_rpc() domain = None entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) admin_sids = [] try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] domainNames = [] for domain in domains: domainNames.append(domain['Name']) domain = "Builtin" resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domain) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] resp = samr.hSamrEnumerateAliasesInDomain(dce, domainHandle) for alias in resp['Buffer']['Buffer']: if alias['RelativeId'] == 544: # Admin group resp = samr.hSamrOpenAlias(dce, domainHandle, desiredAccess=MAXIMUM_ALLOWED, aliasId=alias['RelativeId']) resp = samr.hSamrGetMembersInAlias(dce, resp["AliasHandle"]) for member in resp["Members"]["Sids"]: admin_sids.append( member["SidPointer"].formatCanonical()) except ListUsersException as e: print("Error listing group: %s" % e) dce.disconnect() return admin_sids
def rpc_get_local_admins(self): binding = r'ncacn_np:%s[\PIPE\samr]' % self.addr dce = self.dce_rpc_connect(binding, samr.MSRPC_UUID_SAMR) if dce is None: logging.warning('Connection failed: %s' % binding) return try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] sid = RPC_SID() sid.fromCanonical('S-1-5-32') logging.debug('Opening domain handle') resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, desiredAccess=samr.DOMAIN_LOOKUP | MAXIMUM_ALLOWED, domainId=sid) domainHandle = resp['DomainHandle'] resp = samr.hSamrOpenAlias(dce, domainHandle, desiredAccess=samr.ALIAS_LIST_MEMBERS | MAXIMUM_ALLOWED, aliasId=544) resp = samr.hSamrGetMembersInAlias(dce, aliasHandle=resp['AliasHandle']) for member in resp['Members']['Sids']: sid_string = member['SidPointer'].formatCanonical() logging.debug('Found SID: %s' % sid_string) self.sids.append(sid_string) except DCERPCException as e: logging.debug('Exception connecting to RPC: %s', e) except Exception as e: if 'connection reset' in str(e): logging.debug('Connection was reset: %s', e) else: raise e dce.disconnect()
def __getLocalAdminSids(self): dce = self.__getDceBinding(self.__samrBinding) dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, 'Builtin') resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] resp = samr.hSamrOpenAlias(dce, domainHandle, desiredAccess=MAXIMUM_ALLOWED, aliasId=544) resp = samr.hSamrGetMembersInAlias(dce, resp['AliasHandle']) memberSids = [] for member in resp['Members']['Sids']: memberSids.append(member['SidPointer'].formatCanonical()) dce.disconnect() return memberSids
def rpc_get_local_admins(self): binding = r'ncacn_np:%s[\PIPE\samr]' % self.addr dce = self.dce_rpc_connect(binding, samr.MSRPC_UUID_SAMR) if dce is None: logging.warning('Connection failed: %s', binding) return try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] # Attempt to get the SID from this computer to filter local accounts later try: resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, self.samname[:-1]) self.sid = resp['DomainId'].formatCanonical() # This doesn't always work (for example on DCs) except DCERPCException as e: # Make it a string which is guaranteed not to match a SID self.sid = 'UNKNOWN' # Enumerate the domains known to this computer resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] # Query the builtin domain (derived from this SID) sid = RPC_SID() sid.fromCanonical('S-1-5-32') logging.debug('Opening domain handle') # Open a handle to this domain resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, desiredAccess=samr.DOMAIN_LOOKUP | MAXIMUM_ALLOWED, domainId=sid) domainHandle = resp['DomainHandle'] resp = samr.hSamrOpenAlias(dce, domainHandle, desiredAccess=samr.ALIAS_LIST_MEMBERS | MAXIMUM_ALLOWED, aliasId=544) resp = samr.hSamrGetMembersInAlias(dce, aliasHandle=resp['AliasHandle']) for member in resp['Members']['Sids']: sid_string = member['SidPointer'].formatCanonical() logging.debug('Found admin SID: %s', sid_string) if not sid_string.startswith(self.sid): # If the sid is known, we can add the admin value directly try: siddata = self.ad.sidcache.get(sid_string) logging.debug('Sid is cached: %s', siddata['principal']) self.admins.append({'Name': siddata['principal'], 'Type': siddata['type'].capitalize()}) except KeyError: # Append it to the list of unresolved SIDs self.admin_sids.append(sid_string) else: logging.debug('Ignoring local group %s', sid_string) except DCERPCException as e: logging.debug('Exception connecting to RPC: %s', e) except Exception as e: if 'connection reset' in str(e): logging.debug('Connection was reset: %s', e) else: raise e dce.disconnect()
def get_netlocalgroup(self, queried_groupname=str(), list_groups=False, recurse=False): from impacket.nt_errors import STATUS_MORE_ENTRIES results = list() resp = samr.hSamrConnect(self._rpc_connection) server_handle = resp['ServerHandle'] # We first list every domain in the SAM resp = samr.hSamrEnumerateDomainsInSamServer(self._rpc_connection, server_handle) domains = resp['Buffer']['Buffer'] domain_handles = dict() for local_domain in domains: resp = samr.hSamrLookupDomainInSamServer(self._rpc_connection, server_handle, local_domain['Name']) domain_sid = 'S-1-5-{}'.format('-'.join( str(x) for x in resp['DomainId']['SubAuthority'])) resp = samr.hSamrOpenDomain(self._rpc_connection, serverHandle=server_handle, domainId=resp['DomainId']) domain_handles[domain_sid] = resp['DomainHandle'] # If we list the groups if list_groups: # We browse every domain for domain_sid, domain_handle in domain_handles.items(): # We enumerate local groups in every domain enumeration_context = 0 groups = list() while True: resp = samr.hSamrEnumerateAliasesInDomain( self._rpc_connection, domain_handle, enumerationContext=enumeration_context) groups += resp['Buffer']['Buffer'] enumeration_context = resp['EnumerationContext'] if resp['ErrorCode'] != STATUS_MORE_ENTRIES: break # We get information on every group for group in groups: resp = samr.hSamrRidToSid(self._rpc_connection, domain_handle, rid=group['RelativeId']) sid = 'S-1-5-{}'.format('-'.join( str(x) for x in resp['Sid']['SubAuthority'])) resp = samr.hSamrOpenAlias(self._rpc_connection, domain_handle, aliasId=group['RelativeId']) alias_handle = resp['AliasHandle'] resp = samr.hSamrQueryInformationAlias( self._rpc_connection, alias_handle) final_group = rpcobj.Group(resp['Buffer']['General']) final_group.add_attributes({ 'server': self._target_computer, 'sid': sid }) results.append(final_group) samr.hSamrCloseHandle(self._rpc_connection, alias_handle) samr.hSamrCloseHandle(self._rpc_connection, domain_handle) # If we query a group else: queried_group_rid = None queried_group_domain_handle = None # If the user is looking for a particular group if queried_groupname: # We look for it in every domain for _, domain_handle in domain_handles.items(): try: resp = samr.hSamrLookupNamesInDomain( self._rpc_connection, domain_handle, [queried_groupname]) queried_group_rid = resp['RelativeIds']['Element'][0][ 'Data'] queried_group_domain_handle = domain_handle break except (DCERPCSessionError, KeyError, IndexError): continue else: raise ValueError( 'The group \'{}\' was not found on the target server'. format(queried_groupname)) # Otherwise, we look for the local Administrators group else: queried_group_rid = 544 resp = samr.hSamrLookupDomainInSamServer( self._rpc_connection, server_handle, 'BUILTIN') resp = samr.hSamrOpenDomain(self._rpc_connection, serverHandle=server_handle, domainId=resp['DomainId']) queried_group_domain_handle = resp['DomainHandle'] # We get a handle on the group, and list its members try: group = samr.hSamrOpenAlias(self._rpc_connection, queried_group_domain_handle, aliasId=queried_group_rid) resp = samr.hSamrGetMembersInAlias(self._rpc_connection, group['AliasHandle']) except DCERPCSessionError: raise ValueError( 'The name \'{}\' is not a valid group on the target server' .format(queried_groupname)) # For every user, we look for information in every local domain for member in resp['Members']['Sids']: attributes = dict() member_rid = member['SidPointer']['SubAuthority'][-1] member_sid = 'S-1-5-{}'.format('-'.join( str(x) for x in member['SidPointer']['SubAuthority'])) attributes['server'] = self._target_computer attributes['sid'] = member_sid for domain_sid, domain_handle in domain_handles.items(): # We've found a local member if member_sid.startswith(domain_sid): attributes['isdomain'] = False resp = samr.hSamrQueryInformationDomain( self._rpc_connection, domain_handle) member_domain = resp['Buffer']['General2']['I1'][ 'DomainName'] try: resp = samr.hSamrOpenUser(self._rpc_connection, domain_handle, userId=member_rid) member_handle = resp['UserHandle'] attributes['isgroup'] = False resp = samr.hSamrQueryInformationUser( self._rpc_connection, member_handle) attributes['name'] = '{}/{}'.format( member_domain, resp['Buffer']['General']['UserName']) except DCERPCSessionError: resp = samr.hSamrOpenAlias(self._rpc_connection, domain_handle, aliasId=member_rid) member_handle = resp['AliasHandle'] attributes['isgroup'] = True resp = samr.hSamrQueryInformationAlias( self._rpc_connection, member_handle) attributes['name'] = '{}/{}'.format( member_domain, resp['Buffer']['General']['Name']) attributes['lastlogin'] = str() break # It's a domain member else: attributes['isdomain'] = True if self._ldap_connection is not None: try: ad_object = self.get_adobject( queried_sid=member_sid)[0] member_dn = ad_object.distinguishedname member_domain = member_dn[member_dn. index('DC='):].replace( 'DC=', '').replace( ',', '.') try: attributes['name'] = '{}/{}'.format( member_domain, ad_object.samaccountname) except AttributeError: # Here, the member is a foreign security principal # TODO: resolve it properly attributes['name'] = '{}/{}'.format( member_domain, ad_object.objectsid) attributes['isgroup'] = ad_object.isgroup try: attributes['lastlogin'] = ad_object.lastlogon except AttributeError: attributes['lastlogin'] = str() except IndexError: # We did not manage to resolve this SID against the DC attributes['isdomain'] = False attributes['isgroup'] = False attributes['name'] = attributes['sid'] attributes['lastlogin'] = str() else: attributes['isgroup'] = False attributes['name'] = str() attributes['lastlogin'] = str() results.append(rpcobj.RPCObject(attributes)) # If we recurse and the member is a domain group, we query every member # TODO: implement check on self._domain_controller here? if self._ldap_connection and self._domain_controller and recurse and attributes[ 'isdomain'] and attributes['isgroup']: for domain_member in self.get_netgroupmember( full_data=True, recurse=True, queried_sid=attributes['sid']): domain_member_attributes = dict() domain_member_attributes['isdomain'] = True member_dn = domain_member.distinguishedname member_domain = member_dn[member_dn. index('DC='):].replace( 'DC=', '').replace(',', '.') domain_member_attributes['name'] = '{}/{}'.format( member_domain, domain_member.samaccountname) domain_member_attributes[ 'isgroup'] = domain_member.isgroup domain_member_attributes['isdomain'] = True domain_member_attributes['server'] = attributes['name'] domain_member_attributes[ 'sid'] = domain_member.objectsid try: domain_member_attributes[ 'lastlogin'] = ad_object.lastlogon except AttributeError: domain_member_attributes['lastlogin'] = str() results.append( rpcobj.RPCObject(domain_member_attributes)) return results
def rpc_get_group_members(self, group_rid, resultlist): binding = r'ncacn_np:%s[\PIPE\samr]' % self.addr unresolved = [] dce = self.dce_rpc_connect(binding, samr.MSRPC_UUID_SAMR) if dce is None: return try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] # Attempt to get the SID from this computer to filter local accounts later try: resp = samr.hSamrLookupDomainInSamServer( dce, serverHandle, self.samname[:-1]) self.sid = resp['DomainId'].formatCanonical() # This doesn't always work (for example on DCs) except DCERPCException as e: # Make it a string which is guaranteed not to match a SID self.sid = 'UNKNOWN' # Enumerate the domains known to this computer resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] # Query the builtin domain (derived from this SID) sid = RPC_SID() sid.fromCanonical('S-1-5-32') logging.debug('Opening domain handle') # Open a handle to this domain resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, desiredAccess=samr.DOMAIN_LOOKUP | MAXIMUM_ALLOWED, domainId=sid) domainHandle = resp['DomainHandle'] try: resp = samr.hSamrOpenAlias( dce, domainHandle, desiredAccess=samr.ALIAS_LIST_MEMBERS | MAXIMUM_ALLOWED, aliasId=group_rid) except samr.DCERPCSessionError as error: # Group does not exist if 'STATUS_NO_SUCH_ALIAS' in str(error): logging.debug('No group with RID %d exists', group_rid) return resp = samr.hSamrGetMembersInAlias(dce, aliasHandle=resp['AliasHandle']) for member in resp['Members']['Sids']: sid_string = member['SidPointer'].formatCanonical() logging.debug('Found %d SID: %s', group_rid, sid_string) if not sid_string.startswith(self.sid): # If the sid is known, we can add the admin value directly try: siddata = self.ad.sidcache.get(sid_string) if siddata is None: unresolved.append(sid_string) else: logging.debug('Sid is cached: %s', siddata['principal']) resultlist.append({ 'ObjectIdentifier': sid_string, 'ObjectType': siddata['type'].capitalize() }) except KeyError: # Append it to the list of unresolved SIDs unresolved.append(sid_string) else: logging.debug('Ignoring local group %s', sid_string) except DCERPCException as e: if 'rpc_s_access_denied' in str(e): logging.debug( 'Access denied while enumerating groups on %s, likely a patched OS', self.hostname) else: raise except Exception as e: if 'connection reset' in str(e): logging.debug('Connection was reset: %s', e) else: raise e dce.disconnect() return unresolved
def get_netlocalgroup(self, queried_groupname=str(), list_groups=False, recurse=False): from impacket.nt_errors import STATUS_MORE_ENTRIES results = list() resp = samr.hSamrConnect(self._rpc_connection) server_handle = resp['ServerHandle'] # We first list every domain in the SAM resp = samr.hSamrEnumerateDomainsInSamServer(self._rpc_connection, server_handle) domains = resp['Buffer']['Buffer'] domain_handles = dict() for local_domain in domains: resp = samr.hSamrLookupDomainInSamServer(self._rpc_connection, server_handle, local_domain['Name']) domain_sid = 'S-1-5-{}'.format('-'.join(str(x) for x in resp['DomainId']['SubAuthority'])) resp = samr.hSamrOpenDomain(self._rpc_connection, serverHandle=server_handle, domainId=resp['DomainId']) domain_handles[domain_sid] = resp['DomainHandle'] # If we list the groups if list_groups: # We browse every domain for domain_sid, domain_handle in domain_handles.items(): # We enumerate local groups in every domain enumeration_context = 0 groups = list() while True: resp = samr.hSamrEnumerateAliasesInDomain(self._rpc_connection, domain_handle, enumerationContext=enumeration_context) groups += resp['Buffer']['Buffer'] enumeration_context = resp['EnumerationContext'] if resp['ErrorCode'] != STATUS_MORE_ENTRIES: break # We get information on every group for group in groups: resp = samr.hSamrRidToSid(self._rpc_connection, domain_handle, rid=group['RelativeId']) sid = 'S-1-5-{}'.format('-'.join(str(x) for x in resp['Sid']['SubAuthority'])) resp = samr.hSamrOpenAlias(self._rpc_connection, domain_handle, aliasId=group['RelativeId']) alias_handle = resp['AliasHandle'] resp = samr.hSamrQueryInformationAlias(self._rpc_connection, alias_handle) final_group = rpcobj.Group(resp['Buffer']['General']) final_group.add_attributes({'server': self._target_computer, 'sid': sid}) results.append(final_group) samr.hSamrCloseHandle(self._rpc_connection, alias_handle) samr.hSamrCloseHandle(self._rpc_connection, domain_handle) # If we query a group else: queried_group_rid = None queried_group_domain_handle = None # If the user is looking for a particular group if queried_groupname: # We look for it in every domain for _, domain_handle in domain_handles.items(): try: resp = samr.hSamrLookupNamesInDomain(self._rpc_connection, domain_handle, [queried_groupname]) queried_group_rid = resp['RelativeIds']['Element'][0]['Data'] queried_group_domain_handle = domain_handle break except (DCERPCSessionError, KeyError, IndexError): continue else: raise ValueError('The group \'{}\' was not found on the target server'.format(queried_groupname)) # Otherwise, we look for the local Administrators group else: queried_group_rid = 544 resp = samr.hSamrLookupDomainInSamServer(self._rpc_connection, server_handle, 'BUILTIN') resp = samr.hSamrOpenDomain(self._rpc_connection, serverHandle=server_handle, domainId=resp['DomainId']) queried_group_domain_handle = resp['DomainHandle'] # We get a handle on the group, and list its members try: group = samr.hSamrOpenAlias(self._rpc_connection, queried_group_domain_handle, aliasId=queried_group_rid) resp = samr.hSamrGetMembersInAlias(self._rpc_connection, group['AliasHandle']) except DCERPCSessionError: raise ValueError('The name \'{}\' is not a valid group on the target server'.format(queried_groupname)) # For every user, we look for information in every local domain for member in resp['Members']['Sids']: attributes = dict() member_rid = member['SidPointer']['SubAuthority'][-1] member_sid = 'S-1-5-{}'.format('-'.join(str(x) for x in member['SidPointer']['SubAuthority'])) attributes['server'] = self._target_computer attributes['sid'] = member_sid for domain_sid, domain_handle in domain_handles.items(): # We've found a local member if member_sid.startswith(domain_sid): attributes['isdomain'] = False resp = samr.hSamrQueryInformationDomain(self._rpc_connection, domain_handle) member_domain = resp['Buffer']['General2']['I1']['DomainName'] try: resp = samr.hSamrOpenUser(self._rpc_connection, domain_handle, userId=member_rid) member_handle = resp['UserHandle'] attributes['isgroup'] = False resp = samr.hSamrQueryInformationUser(self._rpc_connection, member_handle) attributes['name'] = '{}/{}'.format(member_domain, resp['Buffer']['General']['UserName']) except DCERPCSessionError: resp = samr.hSamrOpenAlias(self._rpc_connection, domain_handle, aliasId=member_rid) member_handle = resp['AliasHandle'] attributes['isgroup'] = True resp = samr.hSamrQueryInformationAlias(self._rpc_connection, member_handle) attributes['name'] = '{}/{}'.format(member_domain, resp['Buffer']['General']['Name']) attributes['lastlogin'] = str() break # It's a domain member else: attributes['isdomain'] = True if self._ldap_connection is not None: try: ad_object = self.get_adobject(queried_sid=member_sid)[0] member_dn = ad_object.distinguishedname member_domain = member_dn[member_dn.index('DC='):].replace('DC=', '').replace(',', '.') try: attributes['name'] = '{}/{}'.format(member_domain, ad_object.samaccountname) except AttributeError: # Here, the member is a foreign security principal # TODO: resolve it properly attributes['name'] = '{}/{}'.format(member_domain, ad_object.objectsid) attributes['isgroup'] = ad_object.isgroup try: attributes['lastlogin'] = ad_object.lastlogon except AttributeError: attributes['lastlogin'] = str() except IndexError: # We did not manage to resolve this SID against the DC attributes['isdomain'] = False attributes['isgroup'] = False attributes['name'] = attributes['sid'] attributes['lastlogin'] = str() else: attributes['isgroup'] = False attributes['name'] = str() attributes['lastlogin'] = str() results.append(rpcobj.RPCObject(attributes)) # If we recurse and the member is a domain group, we query every member # TODO: implement check on self._domain_controller here? if self._ldap_connection and self._domain_controller and recurse and attributes['isdomain'] and attributes['isgroup']: for domain_member in self.get_netgroupmember(full_data=True, recurse=True, queried_sid=attributes['sid']): domain_member_attributes = dict() domain_member_attributes['isdomain'] = True member_dn = domain_member.distinguishedname member_domain = member_dn[member_dn.index('DC='):].replace('DC=', '').replace(',', '.') domain_member_attributes['name'] = '{}/{}'.format(member_domain, domain_member.samaccountname) domain_member_attributes['isgroup'] = domain_member.isgroup domain_member_attributes['isdomain'] = True domain_member_attributes['server'] = attributes['name'] domain_member_attributes['sid'] = domain_member.objectsid try: domain_member_attributes['lastlogin'] = ad_object.lastlogon except AttributeError: domain_member_attributes['lastlogin'] = str() results.append(rpcobj.RPCObject(domain_member_attributes)) return results