def hSamrChangePasswordUser(self): try: serverHandle = samr.hSamrConnect(self.dce, self.address + '\x00')['ServerHandle'] domainSID = samr.hSamrLookupDomainInSamServer(self.dce, serverHandle, self.domain)['DomainId'] domainHandle = samr.hSamrOpenDomain(self.dce, serverHandle, domainId=domainSID)['DomainHandle'] userRID = samr.hSamrLookupNamesInDomain(self.dce, domainHandle, (self.username,))['RelativeIds']['Element'][0] userHandle = samr.hSamrOpenUser(self.dce, domainHandle, userId=userRID)['UserHandle'] except Exception as e: if 'STATUS_NO_SUCH_DOMAIN' in str(e): logging.critical('Wrong realm. Try to set the domain name for the target user account explicitly in format DOMAIN/username.') return else: raise e try: resp = samr.hSamrChangePasswordUser(self.dce, userHandle, self.oldPassword, newPassword='', oldPwdHashNT=self.oldPwdHashNT, newPwdHashLM=self.newPwdHashLM, newPwdHashNT=self.newPwdHashNT) except Exception as e: if 'STATUS_PASSWORD_RESTRICTION' in str(e): logging.critical('Some password update rule has been violated. For example, the password history policy may prohibit the use of recent passwords.') else: raise e else: if resp['ErrorCode'] == 0: logging.info('NTLM hashes were changed successfully.') else: logging.error('Non-zero return code, something weird happened.') resp.dump()
def bind(self, bind): # bind handler using LSAT or RPC try: self.__bind = bind if self.__verb: stdout.write(f"[*] Binding to {self.__bind.upper()}\n") self.__dce = self.__trans.get_dce_rpc() self.__dce.connect() if self.__bind == 'rpc': self.__dce.bind(MSRPC_UUID_NRPC) elif self.__bind == 'lsat': self.__dce.bind(lsat.MSRPC_UUID_LSAT) elif self.__bind == 'samr': self.__dce.bind(samr.MSRPC_UUID_SAMR) handle = samr.hSamrOpenDomain(self.__dce, self.__trans) elif self.__bind == 'smb': self.__dce.bind() stdout.write(f"[+] {self.__bind} handler bind to {self.__host} successful\n") return self.__dce except DCERPCException as DCERPCExcept: stderr.write(f"[-] {DCERPCExcept}\n") except KeyError as kerr: stderr.write(f"[-] KeyError: {kerr}") except Exception as _except: stderr.write(f"[-] {_except}\n")
def enum(self): #logging.info('Retrieving endpoint list from %s' % addr) entries = [] protodef = PassPolDump.KNOWN_PROTOCOLS['{}/SMB'.format(self.protocol)] port = protodef[1] logging.info("Trying protocol %s..." % self.protocol) rpctransport = transport.SMBTransport(self.addr, port, r'\samr', self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, doKerberos = self.doKerberos) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] self.logger.success('Dumping password policy') self.get_pass_pol(self.addr, rpctransport, dce, domainHandle)
def __fetchlist(self, rpctransport): dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] self.log.info('[+] Found domain: {0}'.format(domains[0]['Name'])) self.log.info("[*] Enumerating RID {0} in the {1} domain..\n".format( self.rid, domains[0]['Name'])) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] request = samr.SamrOpenGroup() request['DomainHandle'] = domainHandle request['DesiredAccess'] = samr.MAXIMUM_ALLOWED request['GroupId'] = self.rid try: resp = dce.request(request) except Exception, e: if 'STATUS_NO_SUCH_DOMAIN' in str(e): raise
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 __obtain_domain_handle(dce, domain_id=MACHINE_DOMAIN): """ Obtain domain handle for samr protocol commands :param dce: DCE/RPC object :param domain_id: Domain ID to use MACHINE/BUILTIN :return: (bytes) domain handle """ resp = samr.hSamrConnect(dce) server_handle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, server_handle) domains = resp['Buffer']['Buffer'] # Two domain will be found, BUILTIN and MACHINE print('Found domain(s):') for domain in domains: print(" . %s" % domain['Name']) logging.info("Using domain %s" % domains[domain_id]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, server_handle, domains[domain_id]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=server_handle, domainId=resp['DomainId'], desiredAccess=samr.MAXIMUM_ALLOWED) domain_handle = resp['DomainHandle'] return domain_handle
def getDomainHandle(self, domainName): resp = samr.hSamrLookupDomainInSamServer(self.dce, self.serverHandle, domainName) resp = samr.hSamrOpenDomain(self.dce, serverHandle=self.serverHandle, domainId=resp['DomainId']) return resp['DomainHandle']
def dump(self, addr): logging.info('Retrieving endpoint list from %s' % addr) # Try all requested protocols until one works. entries = [] for protocol in self.__protocols: protodef = PassPolDump.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) rpctransport = transport.SMBTransport(addr, port, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos = self.__doKerberos) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] self.__logger.success('Dumping password policy') self.get_pass_pol(addr, rpctransport, dce, domainHandle)
def fetchList(self, rpctransport): dce = DCERPC_v5(rpctransport) dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) # Setup Connection resp = samr.hSamrConnect2(dce) if resp['ErrorCode'] != 0: raise Exception('Connect error') resp2 = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle=resp['ServerHandle'], enumerationContext=0, preferedMaximumLength=500) if resp2['ErrorCode'] != 0: raise Exception('Connect error') resp3 = samr.hSamrLookupDomainInSamServer(dce, serverHandle=resp['ServerHandle'], name=resp2['Buffer']['Buffer'][0]['Name']) if resp3['ErrorCode'] != 0: raise Exception('Connect error') resp4 = samr.hSamrOpenDomain(dce, serverHandle=resp['ServerHandle'], desiredAccess=samr.MAXIMUM_ALLOWED, domainId=resp3['DomainId']) if resp4['ErrorCode'] != 0: raise Exception('Connect error') self.__domains = resp2['Buffer']['Buffer'] domainHandle = resp4['DomainHandle'] # End Setup re = samr.hSamrQueryInformationDomain2(dce, domainHandle=domainHandle, domainInformationClass=samr.DOMAIN_INFORMATION_CLASS.DomainPasswordInformation) self.__min_pass_len = re['Buffer']['Password']['MinPasswordLength'] or "None" self.__pass_hist_len = re['Buffer']['Password']['PasswordHistoryLength'] or "None" self.__max_pass_age = convert(int(re['Buffer']['Password']['MaxPasswordAge']['LowPart']), int(re['Buffer']['Password']['MaxPasswordAge']['HighPart'])) self.__min_pass_age = convert(int(re['Buffer']['Password']['MinPasswordAge']['LowPart']), int(re['Buffer']['Password']['MinPasswordAge']['HighPart'])) self.__pass_prop = d2b(re['Buffer']['Password']['PasswordProperties']) re = samr.hSamrQueryInformationDomain2(dce, domainHandle=domainHandle, domainInformationClass=samr.DOMAIN_INFORMATION_CLASS.DomainLockoutInformation) self.__rst_accnt_lock_counter = convert(0, re['Buffer']['Lockout']['LockoutObservationWindow'], lockout=True) self.__lock_accnt_dur = convert(0, re['Buffer']['Lockout']['LockoutDuration'], lockout=True) self.__accnt_lock_thres = re['Buffer']['Lockout']['LockoutThreshold'] or "None" re = samr.hSamrQueryInformationDomain2(dce, domainHandle=domainHandle, domainInformationClass=samr.DOMAIN_INFORMATION_CLASS.DomainLogoffInformation) self.__force_logoff_time = convert(re['Buffer']['Logoff']['ForceLogoff']['LowPart'], re['Buffer']['Logoff']['ForceLogoff']['HighPart']) self.pass_pol = {'min_pass_len': self.__min_pass_len, 'pass_hist_len': self.__pass_hist_len, 'max_pass_age': self.__max_pass_age, 'min_pass_age': self.__min_pass_age, 'pass_prop': self.__pass_prop, 'rst_accnt_lock_counter': self.__rst_accnt_lock_counter, 'lock_accnt_dur': self.__lock_accnt_dur, 'accnt_lock_thres': self.__accnt_lock_thres, 'force_logoff_time': self.__force_logoff_time}
def __fetchlist(self, rpctransport): dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] self.log.info('[+] Found domain: {0}'.format(domains[0]['Name'])) self.log.info("[*] Enumerating RID {0} in the {1} domain..\n".format(self.rid, domains[0]['Name'])) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] request = samr.SamrOpenGroup() request['DomainHandle'] = domainHandle request['DesiredAccess'] = samr.MAXIMUM_ALLOWED request['GroupId'] = self.rid try: resp = dce.request(request) except samr.DCERPCSessionError: raise request = samr.SamrGetMembersInGroup() request['GroupHandle'] = resp['GroupHandle'] resp = dce.request(request) rids = resp.fields['Members'].fields['Data'].fields['Members'].fields['Data'].fields['Data'] mutex = Lock() for rid in rids: try: resp = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, rid.fields['Data']) rid_data = samr.hSamrQueryInformationUser2(dce, resp['UserHandle'], samr.USER_INFORMATION_CLASS.UserAllInformation) except samr.DCERPCSessionError as e: # Occasionally an ACCESS_DENIED is rasied even though the user has permissions? # Other times a STATUS_NO_SUCH_USER is raised when a rid apparently doesn't exist, even though it reported back as existing. self.log.debug(e) continue if self.fqdn: rid_data = rid_data['Buffer']['All']['UserName'].replace('$', '') + '.' + self.fqdn else: rid_data = rid_data['Buffer']['All']['UserName'].replace('$', '') samr.hSamrCloseHandle(dce, resp['UserHandle']) if self.dns_lookup: # Threading because DNS lookups are slow t = Thread(target=self.get_ip, args=(rid_data, mutex,)) t.start() else: self.log.info(rid_data) self.data.append(rid_data) dce.disconnect()
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 __fetchList(self, rpctransport): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] print('Found domain(s):') for domain in domains: print(" . %s" % domain['Name']) logging.info("Looking up users in domain %s" % domains[0]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, enumerationContext = enumerationContext) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user['RelativeId']) print("Found user: %s, uid = %d" % (user['Name'], user['RelativeId'] )) info = samr.hSamrQueryInformationUser2(dce, r['UserHandle'],samr.USER_INFORMATION_CLASS.UserAllInformation) entry = (user['Name'], user['RelativeId'], info['Buffer']['All']) entries.append(entry) samr.hSamrCloseHandle(dce, r['UserHandle']) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except ListUsersException as e: logging.critical("Error listing users: %s" % e) dce.disconnect() return entries
def __fetchList(self, rpctransport): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] print 'Found domain(s):' for domain in domains: print " . %s" % domain['Name'] print "Looking up users in domain %s" % domains[0]['Name'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] done = False status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, enumerationContext = enumerationContext) except Exception, e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: r = samr.hSamrOpenUser(dce, domainHandle, samr.USER_READ_GENERAL | samr.USER_READ_PREFERENCES | samr.USER_READ_ACCOUNT, user['RelativeId']) print "Found user: %s, uid = %d" % (user['Name'], user['RelativeId'] ) info = samr.hSamrQueryInformationUser2(dce, r['UserHandle'],samr.USER_INFORMATION_CLASS.UserAllInformation) entry = (user['Name'], user['RelativeId'], info['Buffer']['All']) entries.append(entry) samr.hSamrCloseHandle(dce, r['UserHandle']) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except ListUsersException, e: print "Error listing users: %s" % e
def connectSamr(self, domain): rpc = transport.DCERPCTransportFactory(self.__stringBindingSamr) rpc.set_smb_connection(self.__smbConnection) self.__samr = rpc.get_dce_rpc() self.__samr.connect() self.__samr.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(self.__samr) serverHandle = resp['ServerHandle'] resp = samr.hSamrLookupDomainInSamServer(self.__samr, serverHandle, domain) resp = samr.hSamrOpenDomain(self.__samr, serverHandle=serverHandle, domainId=resp['DomainId']) self.__domainHandle = resp['DomainHandle'] self.__domainName = domain
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 initialize_dce(self, rpctransport): dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) server_handle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, server_handle) domains = resp['Buffer']['Buffer'] self.log.info('[+] Found domain: {0}'.format(domains[0]['Name'])) resp = samr.hSamrLookupDomainInSamServer(dce, server_handle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=server_handle, domainId=resp['DomainId']) domain_handle = resp['DomainHandle'] if self.enumerate_groups: self.log.info('[*] Enumerating all Domain Group RIDs (Group/RID)') self.enumerate_domain_groups(dce, domain_handle) elif self.enumerate_users: self.log.info( '[*] Enumerating all Domain Users (RID/Username/Name/Description)' ) self.enumerate_domain_users(dce, domain_handle) elif self.enumerate_pass_policy: self.log.info('[*] Enumerating domain password policy') self.enumerate_password_policy(dce, domain_handle) else: self.log.info('[*] Enumerating RID {0} in the {1} domain..'.format( self.rid, domains[0]['Name'])) try: self.enumerate_user_info(dce, domain_handle) dce.disconnect() return except samr.DCERPCSessionError: self.log.debug( '[*] RID is not for a user. Trying again as a group.') pass try: self.enumerate_users_in_group(dce, domain_handle) except samr.DCERPCSessionError: self.log.debug('[*] RID is not for a group either') self.log.info('[-] RID not found') dce.disconnect()
def getDomainMachines(self): if self.__kdcHost is not None: domainController = self.__kdcHost elif self.__domain is not '': domainController = self.__domain else: raise Exception('A domain is needed!') logging.info('Getting machine\'s list from %s' % domainController) rpctransport = transport.SMBTransport(domainController, 445, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos, kdcHost = self.__kdcHost) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] logging.info("Looking up users in domain %s" % domains[0]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, samr.USER_WORKSTATION_TRUST_ACCOUNT, enumerationContext=enumerationContext) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: self.__machinesList.append(user['Name'][:-1]) logging.debug('Machine name - rid: %s - %d'% (user['Name'], user['RelativeId'])) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except Exception as e: raise e dce.disconnect()
def getDomainMachines(self): if self.__kdcHost is not None: domainController = self.__kdcHost elif self.__domain is not '': domainController = self.__domain else: raise Exception('A domain is needed!') logging.info('Getting machine\'s list from %s' % domainController) rpctransport = transport.SMBTransport(domainController, 445, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos, kdcHost = self.__kdcHost) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] logging.info("Looking up users in domain %s" % domains[0]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle,domains[0]['Name'] ) resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, samr.USER_WORKSTATION_TRUST_ACCOUNT, enumerationContext=enumerationContext) except DCERPCException, e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: self.__machinesList.append(user['Name'][:-1]) logging.debug('Machine name - rid: %s - %d'% (user['Name'], user['RelativeId'])) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except Exception as e: raise e dce.disconnect()
def _open_domain_handle(self, dce, server_handle, domain_name): lookup_domain_resp = samr.hSamrLookupDomainInSamServer( dce, server_handle, domain_name) domain_sid = lookup_domain_resp[self.DOMAIN_ID] self.logger.debug(f"Opening domain {domain_name}...") open_domain_response = samr.hSamrOpenDomain(dce, server_handle, domainId=domain_sid) domain_handle = open_domain_response[self.DOMAIN_HANDLE] self.logger.debug(f"Domain {domain_name} opened!") return domain_handle
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 dump(self, addr): logging.info('Retrieving endpoint list from %s' % addr) # Try all requested protocols until one works. entries = [] for protocol in self.__protocols: protodef = PassPolDump.KNOWN_PROTOCOLS[protocol] port = protodef[1] logging.info("Trying protocol %s..." % protocol) rpctransport = transport.SMBTransport(addr, port, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] self.__logger.success('Dumping password policy') self.get_pass_pol(addr, rpctransport, dce, domainHandle)
def enum(self): #logging.info('Retrieving endpoint list from %s' % addr) entries = [] protodef = PassPolDump.KNOWN_PROTOCOLS['{}/SMB'.format(self.protocol)] port = protodef[1] logging.info("Trying protocol %s..." % self.protocol) rpctransport = transport.SMBTransport(self.addr, port, r'\samr', self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, doKerberos=self.doKerberos) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] self.logger.success('Dumping password policy') self.get_pass_pol(self.addr, rpctransport, dce, domainHandle)
def getUserSID(self): stringBinding = r'ncacn_np:%s[\pipe\samr]' % self.__kdcHost rpctransport = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpctransport, 'set_credentials'): rpctransport.set_credentials(self.__username,self.__password, self.__domain, self.__lmhash, self.__nthash) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, self.__domain) domainId = resp['DomainId'] resp = samr.hSamrOpenDomain(dce, serverHandle, domainId = domainId) domainHandle = resp['DomainHandle'] resp = samr.hSamrLookupNamesInDomain(dce, domainHandle, (self.__username,)) # Let's pick the relative ID rid = resp['RelativeIds']['Element'][0]['Data'] logging.info("User SID: %s-%s"% (domainId.formatCanonical(), rid)) return domainId, rid
def hSamrSetInformationUser(self): try: serverHandle = samr.hSamrConnect(self.dce, self.address + '\x00')['ServerHandle'] domainSID = samr.hSamrLookupDomainInSamServer(self.dce, serverHandle, self.domain)['DomainId'] domainHandle = samr.hSamrOpenDomain(self.dce, serverHandle, domainId=domainSID)['DomainHandle'] userRID = samr.hSamrLookupNamesInDomain(self.dce, domainHandle, (self.username,))['RelativeIds']['Element'][0] userHandle = samr.hSamrOpenUser(self.dce, domainHandle, userId=userRID)['UserHandle'] except Exception as e: if 'STATUS_NO_SUCH_DOMAIN' in str(e): logging.critical('Wrong realm. Try to set the domain name for the target user account explicitly in format DOMAIN/username.') return else: raise e try: resp = samr.hSamrSetNTInternal1(self.dce, userHandle, self.newPassword, self.newPwdHashNT) except Exception as e: raise e else: if resp['ErrorCode'] == 0: logging.info('Credentials were injected into SAM successfully.') else: logging.error('Non-zero return code, something weird happened.') resp.dump()
def __get_domain_handels(dce: DCERPC) -> Dict[str, str]: """ Request domain handel using DCERPC :param dce: DCE/RPC session :return: mapping of domain name -> domain handel """ domains = {} resp = samr.hSamrConnect(dce) server_handle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, server_handle) raw_domains = resp['Buffer']['Buffer'] domain_names = [domain["Name"] for domain in raw_domains] logger.info(f'Found domain(s): {", ".join(domain_names)}') for domain_name in domain_names: resp = samr.hSamrLookupDomainInSamServer(dce, server_handle, domain_name) resp = samr.hSamrOpenDomain(dce, serverHandle=server_handle, domainId=resp['DomainId']) domain_handle = resp['DomainHandle'] domains[domain_name] = domain_handle return domains
def doSAMRAdd(self, rpctransport): dce = rpctransport.get_dce_rpc() servHandle = None domainHandle = None userHandle = None try: dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) samrConnectResponse = samr.hSamrConnect5( dce, '\\\\%s\x00' % self.__target, samr.SAM_SERVER_ENUMERATE_DOMAINS | samr.SAM_SERVER_LOOKUP_DOMAIN) servHandle = samrConnectResponse['ServerHandle'] samrEnumResponse = samr.hSamrEnumerateDomainsInSamServer( dce, servHandle) domains = samrEnumResponse['Buffer']['Buffer'] domainsWithoutBuiltin = list( filter(lambda x: x['Name'].lower() != 'builtin', domains)) if len(domainsWithoutBuiltin) > 1: domain = list( filter(lambda x: x['Name'].lower() == self.__domainNetbios, domains)) if len(domain) != 1: logging.critical( "This server provides multiple domains and '%s' isn't one of them.", self.__domainNetbios) logging.critical("Available domain(s):") for domain in domains: logging.error(" * %s" % domain['Name']) logging.critical( "Consider using -domain-netbios argument to specify which one you meant." ) raise Exception() else: selectedDomain = domain[0]['Name'] else: selectedDomain = domainsWithoutBuiltin[0]['Name'] samrLookupDomainResponse = samr.hSamrLookupDomainInSamServer( dce, servHandle, selectedDomain) domainSID = samrLookupDomainResponse['DomainId'] if logging.getLogger().level == logging.DEBUG: logging.info("Opening domain %s..." % selectedDomain) samrOpenDomainResponse = samr.hSamrOpenDomain( dce, servHandle, samr.DOMAIN_LOOKUP | samr.DOMAIN_CREATE_USER, domainSID) domainHandle = samrOpenDomainResponse['DomainHandle'] if self.__noAdd or self.__delete: try: checkForUser = samr.hSamrLookupNamesInDomain( dce, domainHandle, [self.__computerName]) except samr.DCERPCSessionError as e: if e.error_code == 0xc0000073: raise Exception("Account %s not found in domain %s!" % (self.__computerName, selectedDomain)) else: raise userRID = checkForUser['RelativeIds']['Element'][0] if self.__delete: access = samr.DELETE message = "delete" else: access = samr.USER_FORCE_PASSWORD_CHANGE message = "set password for" try: openUser = samr.hSamrOpenUser(dce, domainHandle, access, userRID) userHandle = openUser['UserHandle'] except samr.DCERPCSessionError as e: if e.error_code == 0xc0000022: raise Exception( "User %s doesn't have right to %s %s!" % (self.__username, message, self.__computerName)) else: raise else: if self.__computerName is not None: try: checkForUser = samr.hSamrLookupNamesInDomain( dce, domainHandle, [self.__computerName]) raise Exception( "Account %s already exists! If you just want to set a password, use -no-add." % self.__computerName) except samr.DCERPCSessionError as e: if e.error_code != 0xc0000073: raise else: foundUnused = False while not foundUnused: self.__computerName = self.generateComputerName() try: checkForUser = samr.hSamrLookupNamesInDomain( dce, domainHandle, [self.__computerName]) except samr.DCERPCSessionError as e: if e.error_code == 0xc0000073: foundUnused = True else: raise try: createUser = samr.hSamrCreateUser2InDomain( dce, domainHandle, self.__computerName, samr.USER_WORKSTATION_TRUST_ACCOUNT, samr.USER_FORCE_PASSWORD_CHANGE, ) except samr.DCERPCSessionError as e: if e.error_code == 0xc0000022: raise Exception( "User %s doesn't have right to create a machine account!" % self.__username) elif e.error_code == 0xc00002e7: raise Exception("User %s machine quota exceeded!" % self.__username) else: raise userHandle = createUser['UserHandle'] if self.__delete: samr.hSamrDeleteUser(dce, userHandle) logging.info("Successfully deleted %s." % self.__computerName) userHandle = None else: samr.hSamrSetPasswordInternal4New(dce, userHandle, self.__computerPassword) if self.__noAdd: logging.info( "Successfully set password of %s to %s." % (self.__computerName, self.__computerPassword)) else: logging.info( "Successfully added machine account %s with password %s." % (self.__computerName, self.__computerPassword)) except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.critical(str(e)) finally: if userHandle is not None: samr.hSamrCloseHandle(dce, userHandle) if domainHandle is not None: samr.hSamrCloseHandle(dce, domainHandle) if servHandle is not None: samr.hSamrCloseHandle(dce, servHandle) dce.disconnect()
def __fetchList(self, rpctransport): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] print('Found domain(s):') for domain in domains: print(" . %s" % domain['Name']) logging.info("Looking up users in domain %s" % domains[0]['Name']) resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain( dce, domainHandle, enumerationContext=enumerationContext) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user['RelativeId']) print("Found user: %s, uid = %d" % (user['Name'], user['RelativeId'])) info = samr.hSamrQueryInformationUser2( dce, r['UserHandle'], samr.USER_INFORMATION_CLASS.UserAllInformation) entry = (user['Name'], user['RelativeId'], info['Buffer']['All']) entries.append(entry) samr.hSamrCloseHandle(dce, r['UserHandle']) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except ListUsersException as e: logging.critical("Error listing users: %s" % e) dce.disconnect() return entries
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 __fetchUserList(self, rpctransport): dce = rpctransport.get_dce_rpc() domain = None entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] domain = domains[0]['Name'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain( dce, domainHandle, enumerationContext=enumerationContext) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: try: r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user['RelativeId']) info = samr.hSamrQueryInformationUser2( dce, r['UserHandle'], samr.USER_INFORMATION_CLASS.UserAllInformation) entry = (domain, user['Name'], user['RelativeId'], info['Buffer']['All']) yield entry samr.hSamrCloseHandle(dce, r['UserHandle']) except DCERPCSessionError: pass enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except ListUsersException as e: print("Error listing users: %s" % e) dce.disconnect()
def fetchList(self, rpctransport): dce = DCERPC_v5(rpctransport) dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) # Setup Connection resp = samr.hSamrConnect2(dce) if resp['ErrorCode'] != 0: raise Exception('Connect error') resp2 = samr.hSamrEnumerateDomainsInSamServer( dce, serverHandle=resp['ServerHandle'], enumerationContext=0, preferedMaximumLength=500) if resp2['ErrorCode'] != 0: raise Exception('Connect error') resp3 = samr.hSamrLookupDomainInSamServer( dce, serverHandle=resp['ServerHandle'], name=resp2['Buffer']['Buffer'][0]['Name']) if resp3['ErrorCode'] != 0: raise Exception('Connect error') resp4 = samr.hSamrOpenDomain(dce, serverHandle=resp['ServerHandle'], desiredAccess=samr.MAXIMUM_ALLOWED, domainId=resp3['DomainId']) if resp4['ErrorCode'] != 0: raise Exception('Connect error') self.__domains = resp2['Buffer']['Buffer'] domainHandle = resp4['DomainHandle'] # End Setup status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain( dce, domainHandle, enumerationContext=enumerationContext) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: self.logger.error('Error enumerating domain user(s)') break resp = e.get_packet() self.logger.success('Enumerated domain user(s)') for user in resp['Buffer']['Buffer']: r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user['RelativeId']) info = samr.hSamrQueryInformationUser2( dce, r['UserHandle'], samr.USER_INFORMATION_CLASS.UserAllInformation) (username, uid, info_user) = (user['Name'], user['RelativeId'], info['Buffer']['All']) self.logger.highlight('{}\\{:<30} {}'.format( self.domain, user['Name'], info_user['AdminComment'])) self.users.append(user['Name']) samr.hSamrCloseHandle(dce, r['UserHandle']) enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] dce.disconnect()
def __samr_users(self, usrdomain=None): ''' Enumerate users on the system ''' self.__samr_domains(True) encoding = sys.getdefaultencoding() for domain_name, domain in self.domains_dict.items(): if usrdomain and usrdomain.upper() != domain_name.upper(): continue logger.info('Looking up users in domain %s' % domain_name) resp = samr.hSamrLookupDomainInSamServer(self.__dce, self.__mgr_handle, domain_name) resp = samr.hSamrOpenDomain(self.__dce, serverHandle=self.__mgr_handle, domainId=resp['DomainId']) self.__domain_context_handle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enum_context = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateUsersInDomain( self.__dce, self.__domain_context_handle, enumerationContext=enum_context) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for user in resp['Buffer']['Buffer']: r = samr.hSamrOpenUser(self.__dce, self.__domain_context_handle, samr.MAXIMUM_ALLOWED, user['RelativeId']) logger.debug('Found user %s (UID: %d)' % (user['Name'], user['RelativeId'])) info = samr.hSamrQueryInformationUser2( self.__dce, r['UserHandle'], samr.USER_INFORMATION_CLASS.UserAllInformation) entry = (user['Name'], user['RelativeId'], info['Buffer']['All']) self.users_list.add(entry) samr.hSamrCloseHandle(self.__dce, r['UserHandle']) enum_context = resp['EnumerationContext'] status = resp['ErrorCode'] if self.users_list: num = len(self.users_list) logger.info('Retrieved %d user%s' % (num, 's' if num > 1 else '')) else: logger.info('No users enumerated') for entry in self.users_list: user, uid, info = entry print(user) print(' User ID: %d' % uid) print(' Group ID: %d' % info['PrimaryGroupId']) if info['UserAccountControl'] & samr.USER_ACCOUNT_DISABLED: account_disabled = 'True' else: account_disabled = 'False' print(' Enabled: %s' % account_disabled) try: print(' Logon count: %d' % info['LogonCount']) except ValueError: pass lastLogon = (info['LastLogon']['HighPart'] << 32) + info['LastLogon']['LowPart'] if lastLogon == 0: lastLogon = '<never>' else: lastLogon = str( datetime.fromtimestamp(self.getUnixTime(lastLogon))) try: print(' Last Logon: %s' % lastLogon) except ValueError: pass lastLogoff = (info['LastLogoff']['HighPart'] << 32) + info['LastLogoff']['LowPart'] if lastLogoff == 0: lastLogoff = '<never>' else: lastLogoff = str( datetime.fromtimestamp(self.getUnixTime(lastLogoff))) try: print(' Last Logoff: %s' % lastLogoff) except ValueError: pass pwdLastSet = (info['PasswordLastSet']['HighPart'] << 32) + info['PasswordLastSet']['LowPart'] if pwdLastSet == 0: pwdLastSet = '<never>' else: pwdLastSet = str( datetime.fromtimestamp(self.getUnixTime(pwdLastSet))) try: print(' Last password set: %s' % pwdLastSet) except ValueError: pass if info['PasswordExpired'] == 0: password_expired = 'False' elif info['PasswordExpired'] == 1: password_expired = 'True' try: print(' Password expired: %s' % password_expired) except ValueError: pass if info['UserAccountControl'] & samr.USER_DONT_EXPIRE_PASSWORD: dont_expire = 'True' else: dont_expire = 'False' try: print(' Password does not expire: %s' % dont_expire) except ValueError: pass pwdCanChange = (info['PasswordCanChange']['HighPart'] << 32) + info['PasswordCanChange']['LowPart'] if pwdCanChange == 0: pwdCanChange = '<never>' else: pwdCanChange = str( datetime.fromtimestamp(self.getUnixTime(pwdCanChange))) try: print(' Password can change: %s' % pwdCanChange) except ValueError: pass try: pwdMustChange = ( info['PasswordMustChange']['HighPart'] << 32) + info['PasswordMustChange']['LowPart'] if pwdMustChange == 0: pwdMustChange = '<never>' else: pwdMustChange = str( datetime.fromtimestamp( self.getUnixTime(pwdMustChange))) except: pwdMustChange = '<never>' try: print(' Password must change: %s' % pwdMustChange) except ValueError: pass try: print(' Bad password count: %d' % info['BadPasswordCount']) except ValueError: pass try: print(' Full name: %s' % info['FullName']) except ValueError: pass try: print(' Home directory: %s' % info['HomeDirectory']) except ValueError: pass try: print(' Home directory drive: %s' % info['HomeDirectoryDrive']) except ValueError: pass try: print(' Script path: %s' % info['ScriptPath']) except ValueError: pass try: print(' Profile path: %s' % info['ProfilePath']) except ValueError: pass try: print(' Admin comment: %s' % info['AdminComment']) except ValueError: pass try: print(' Workstations: %s' % info['WorkStations']) except ValueError: pass try: print(' User comment: %s' % info['UserComment']) except ValueError: pass self.users_list = set()
def __samr_pswpolicy(self, usrdomain=None): self.__samr_domains(False) for domain_name, domain in self.domains_dict.items(): if usrdomain and usrdomain.upper() != domain_name.upper(): continue print('Looking up password policy in domain %s' % domain_name) resp = samr.hSamrLookupDomainInSamServer( self.__dce, serverHandle=self.__mgr_handle, name=domain_name) if resp['ErrorCode'] != 0: raise Exception('Connect error') resp = samr.hSamrOpenDomain(self.__dce, serverHandle=self.__mgr_handle, desiredAccess=samr.MAXIMUM_ALLOWED, domainId=resp['DomainId']) if resp['ErrorCode'] != 0: raise Exception('Connect error') domainHandle = resp['DomainHandle'] # End Setup domain_passwd = samr.DOMAIN_INFORMATION_CLASS.DomainPasswordInformation re = samr.hSamrQueryInformationDomain2( self.__dce, domainHandle=domainHandle, domainInformationClass=domain_passwd) self.__min_pass_len = ( re['Buffer']['Password']['MinPasswordLength'] or "None") pass_hist_len = re['Buffer']['Password']['PasswordHistoryLength'] self.__pass_hist_len = pass_hist_len or "None" self.__max_pass_age = convert( int(re['Buffer']['Password']['MaxPasswordAge']['LowPart']), int(re['Buffer']['Password']['MaxPasswordAge']['HighPart'])) self.__min_pass_age = convert( int(re['Buffer']['Password']['MinPasswordAge']['LowPart']), int(re['Buffer']['Password']['MinPasswordAge']['HighPart'])) self.__pass_prop = d2b( re['Buffer']['Password']['PasswordProperties']) domain_lockout = samr.DOMAIN_INFORMATION_CLASS.DomainLockoutInformation re = samr.hSamrQueryInformationDomain2( self.__dce, domainHandle=domainHandle, domainInformationClass=domain_lockout) self.__rst_accnt_lock_counter = convert( 0, re['Buffer']['Lockout']['LockoutObservationWindow'], lockout=True) self.__lock_accnt_dur = convert( 0, re['Buffer']['Lockout']['LockoutDuration'], lockout=True) self.__accnt_lock_thres = re['Buffer']['Lockout'][ 'LockoutThreshold'] or "None" domain_logoff = samr.DOMAIN_INFORMATION_CLASS.DomainLogoffInformation re = samr.hSamrQueryInformationDomain2( self.__dce, domainHandle=domainHandle, domainInformationClass=domain_logoff) self.__force_logoff_time = convert( re['Buffer']['Logoff']['ForceLogoff']['LowPart'], re['Buffer']['Logoff']['ForceLogoff']['HighPart']) self.print_friendly()
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 enumPasswordPolicy(self): rpctransport = transport.SMBTransport(self.__addr, self.__port, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] domain = domains[0]["Name"] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] if self.__host_domain == "": domain = "WORKGROUP" else: domain = self.__host_domain resp = samr.hSamrQueryInformationDomain( dce, domainHandle, samr.DOMAIN_INFORMATION_CLASS.DomainPasswordInformation) pass_complexity = resp['Buffer']['Password']['PasswordProperties'] min_pass_len = resp['Buffer']['Password']['MinPasswordLength'] pass_hst_len = resp['Buffer']['Password']['PasswordHistoryLength'] max_pass_age = self.__convert( resp['Buffer']['Password']['MaxPasswordAge']['LowPart'], resp['Buffer']['Password']['MaxPasswordAge']['HighPart'], 1) min_pass_age = self.__convert( resp['Buffer']['Password']['MinPasswordAge']['LowPart'], resp['Buffer']['Password']['MinPasswordAge']['HighPart'], 1) resp = samr.hSamrQueryInformationDomain2( dce, domainHandle, samr.DOMAIN_INFORMATION_CLASS.DomainLockoutInformation) lock_threshold = int(resp['Buffer']['Lockout']['LockoutThreshold']) lock_duration = None if lock_threshold != 0: lock_duration = int( resp['Buffer']['Lockout']['LockoutDuration']) / -600000000 dce.disconnect() return { 'complexity': pass_complexity, 'minimum_length': min_pass_len, 'history_length': pass_hst_len, 'maximum_age': max_pass_age, 'minimum_age': min_pass_age, 'lock_threshold': lock_threshold, 'lock_duration': lock_duration, }
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_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 __fetchGroupList(self, rpctransport): dce = rpctransport.get_dce_rpc() domain = None entries = [] dce.connect() dce.bind(samr.MSRPC_UUID_SAMR) try: resp = samr.hSamrConnect(dce) serverHandle = resp['ServerHandle'] resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle) domains = resp['Buffer']['Buffer'] domain = domains[0]['Name'] resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name']) resp = samr.hSamrOpenDomain(dce, serverHandle=serverHandle, domainId=resp['DomainId']) domainHandle = resp['DomainHandle'] status = STATUS_MORE_ENTRIES enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: resp = samr.hSamrEnumerateGroupsInDomain( dce, domainHandle, enumerationContext=enumerationContext) except DCERPCException as e: if str(e).find('STATUS_MORE_ENTRIES') < 0: raise resp = e.get_packet() for group in resp['Buffer']['Buffer']: r = samr.hSamrOpenGroup(dce, domainHandle, samr.MAXIMUM_ALLOWED, group['RelativeId']) info = samr.hSamrQueryInformationGroup( dce, r['GroupHandle'], samr.GROUP_INFORMATION_CLASS.GroupGeneralInformation) # Query members in group try: members_info = samr.hSamrGetMembersInGroup( dce, r['GroupHandle']) members = { "Count": members_info["Members"]["MemberCount"], "RelativeIds": [], } for member in members_info["Members"]["Members"]: members["RelativeIds"].append( int(vars(member)["fields"]["Data"])) entry = (domain, group['Name'], group['RelativeId'], info['Buffer']['General'], members) yield entry samr.hSamrCloseHandle(dce, r['GroupHandle']) except DCERPCSessionError: pass enumerationContext = resp['EnumerationContext'] status = resp['ErrorCode'] except ListUsersException as e: print("Error listing group: %s" % e) dce.disconnect()