def __bruteForce(self, rpctransport, maxRid): dce = rpctransport.get_dce_rpc() dce.connect() # Want encryption? Uncomment next line # But make SIMULTANEOUS variable <= 100 # dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) # Want fragmentation? Uncomment next line # dce.set_max_fragment_size(32) dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsat.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp["PolicyHandle"] resp = lsad.hLsarQueryInformationPolicy2( dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation ) domainSid = resp["PolicyInformation"]["PolicyAccountDomainInfo"]["DomainSid"].formatCanonical() soFar = 0 SIMULTANEOUS = 1000 for j in range(maxRid / SIMULTANEOUS + 1): if (maxRid - soFar) / SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS if sidsToCheck == 0: break sids = list() for i in xrange(soFar, soFar + sidsToCheck): sids.append(domainSid + "-%d" % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException, e: if str(e).find("STATUS_NONE_MAPPED") >= 0: soFar += SIMULTANEOUS continue elif str(e).find("STATUS_SOME_NOT_MAPPED") >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp["TranslatedNames"]["Names"]): if item["Use"] != SID_NAME_USE.SidTypeUnknown: self.__logger.highlight( "%d: %s\\%s (%s)" % ( soFar + n, resp["ReferencedDomains"]["Domains"][item["DomainIndex"]]["Name"], item["Name"], SID_NAME_USE.enumItems(item["Use"]).name, ) ) soFar += SIMULTANEOUS
def __bruteForce(self, rpctransport, maxRid): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() # Want encryption? Uncomment next line # But make SIMULTANEOUS variable <= 100 #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) # Want fragmentation? Uncomment next line #dce.set_max_fragment_size(32) dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsat.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] if self.__domain_sids: # get the Domain SID resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyPrimaryDomainInformation) domainSid = resp['PolicyInformation']['PolicyPrimaryDomainInfo']['Sid'].formatCanonical() else: # Get the target host SID resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() logging.info('Domain SID is: %s' % domainSid) soFar = 0 SIMULTANEOUS = 1000 for j in range(maxRid/SIMULTANEOUS+1): if (maxRid - soFar) / SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS if sidsToCheck == 0: break sids = list() for i in xrange(soFar, soFar+sidsToCheck): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException, e: if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp['TranslatedNames']['Names']): if item['Use'] != SID_NAME_USE.SidTypeUnknown: print "%d: %s\\%s (%s)" % ( soFar + n, resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name) soFar += SIMULTANEOUS
def __resolveSids(self, sids): dce = self.__getDceBinding(self.__lsaBinding) dce.connect() dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsat.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = lsat.hLsarLookupSids(dce, policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) names = [] for n, item in enumerate(resp['TranslatedNames']['Names']): names.append(u"{}\\{}".format(resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'].encode('utf-16-le'), item['Name'])) dce.disconnect() return names
def test_hLsarLookupSids(self): dce, rpctransport, policyHandle = self.connect() resp = lsat.hLsarLookupNames(dce, policyHandle, ('Administrator',)) #resp.dump() domainSid = resp['ReferencedDomains']['Domains'][0]['Sid'].formatCanonical() sids = list() for i in range(1000): sids.append(domainSid + '-%d' % (500+i)) try: resp = lsat.hLsarLookupSids(dce, policyHandle, sids ) #resp.dump() except Exception, e: if str(e).find('STATUS_SOME_NOT_MAPPED') < 0: raise else: resp = e.get_packet()
def __lookupSidUidGen(self, sid_uid_gen): rpctransport = transport.SMBTransport(self.__addr, self.__port, r'\lsarpc', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos=self.__doKerberos) dce = rpctransport.get_dce_rpc() domain = None entries = [] dce.connect() dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsad.hLsarOpenPolicy2( dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = lsad.hLsarQueryInformationPolicy2( dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo'][ 'DomainSid'].formatCanonical() SIMULTANEOUS = 1000 while True: empty = True sids = [] for i in sid_uid_gen: empty = False if type(i) == int: i = domainSid + '-%d' % i sids.append(i) if len(sids) >= SIMULTANEOUS: break if empty: break try: resp = lsat.hLsarLookupSids( dce, policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException as e: if str(e).find('STATUS_NONE_MAPPED') >= 0: continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp['TranslatedNames']['Names']): if item['Use'] != SID_NAME_USE.SidTypeUnknown: yield { 'domain': resp['ReferencedDomains']['Domains'][ item['DomainIndex']]['Name'], 'name': item['Name'], 'type': SID_NAME_USE.enumItems(item['Use']).name } dce.disconnect()
def rpc_resolve_sids(self): """ Resolve any remaining unknown SIDs for local administrator accounts. """ # If all sids were already cached, we can just return if len(self.admin_sids) == 0: return binding = r'ncacn_np:%s[\PIPE\lsarpc]' % self.addr dce = self.dce_rpc_connect(binding, lsat.MSRPC_UUID_LSAT) if dce is None: logging.warning('Connection failed') return try: resp = lsat.hLsarOpenPolicy2( dce, lsat.POLICY_LOOKUP_NAMES | MAXIMUM_ALLOWED) except Exception as e: if str(e).find('Broken pipe') >= 0: return else: raise policyHandle = resp['PolicyHandle'] # We could look up the SIDs all at once, but if not all SIDs are mapped, we don't know which # ones were resolved and which not, making it impossible to map them in the cache. # Therefor we use more SAMR calls at the start, but after a while most SIDs will be reliable # in our cache and this function doesn't even need to get called anymore. for sid_string in self.admin_sids: try: resp = lsat.hLsarLookupSids( dce, policyHandle, [sid_string], lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException as e: if str(e).find('STATUS_NONE_MAPPED') >= 0: logging.warning( 'SID %s lookup failed, return status: STATUS_NONE_MAPPED', sid_string) # Try next SID continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: # Not all could be resolved, work with the ones that could resp = e.get_packet() else: raise domains = [] for entry in resp['ReferencedDomains']['Domains']: domains.append(entry['Name']) for entry in resp['TranslatedNames']['Names']: domain = domains[entry['DomainIndex']] domainEntry = self.ad.get_domain_by_name(domain) if domainEntry is not None: domain = ADUtils.ldap2domain( domainEntry['attributes']['distinguishedName']) if entry['Name'] != '': logging.debug('Resolved SID to name: %s@%s' % (entry['Name'], domain)) self.admins.append({ 'computer': self.hostname, 'name': unicode(entry['Name']), 'use': ADUtils.translateSidType(entry['Use']), 'domain': domain }) # Add it to our cache self.ad.sidcache.put(sid_string, (entry, domain)) else: logging.warning('Resolved name is empty [%s]', entry) dce.disconnect()
def __bruteForce(self, rpctransport, maxRid): dce = rpctransport.get_dce_rpc() entries = [] dce.connect() # Want encryption? Uncomment next line # But make SIMULTANEOUS variable <= 100 #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) # Want fragmentation? Uncomment next line #dce.set_max_fragment_size(32) dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsat.hLsarOpenPolicy2( dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] if self.__domain_sids: # get the Domain SID resp = lsad.hLsarQueryInformationPolicy2( dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyPrimaryDomainInformation) domainSid = resp['PolicyInformation']['PolicyPrimaryDomainInfo'][ 'Sid'].formatCanonical() else: # Get the target host SID resp = lsad.hLsarQueryInformationPolicy2( dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo'][ 'DomainSid'].formatCanonical() logging.info('Domain SID is: %s' % domainSid) soFar = 0 SIMULTANEOUS = 1000 for j in range(maxRid / SIMULTANEOUS + 1): if (maxRid - soFar) / SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS if sidsToCheck == 0: break sids = list() for i in xrange(soFar, soFar + sidsToCheck): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException, e: if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp['TranslatedNames']['Names']): if item['Use'] != SID_NAME_USE.SidTypeUnknown: print "%d: %s\\%s (%s)" % ( soFar + n, resp['ReferencedDomains']['Domains'][ item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name) soFar += SIMULTANEOUS
def rpc_resolve_sids(self): binding = r'ncacn_np:%s[\PIPE\lsarpc]' % self.addr dce = self.dce_rpc_connect(binding, lsat.MSRPC_UUID_LSAT) if dce is None: logging.warning('Connection failed') return try: resp = lsat.hLsarOpenPolicy2( dce, lsat.POLICY_LOOKUP_NAMES | MAXIMUM_ALLOWED) except Exception as e: if str(e).find('Broken pipe') >= 0: return else: raise policyHandle = resp['PolicyHandle'] try: resp = lsat.hLsarLookupSids(dce, policyHandle, self.sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException as e: if str(e).find('STATUS_NONE_MAPPED') >= 0: logging.warning( 'SID lookup failed, return status: STATUS_NONE_MAPPED') raise elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: # Not all could be resolved, work with the ones that could resp = e.get_packet() else: raise domains = [] for entry in resp['ReferencedDomains']['Domains']: logging.debug('Found referenced domain: %s' % entry['Name']) domains.append(entry['Name']) i = 0 for entry in resp['TranslatedNames']['Names']: domain = domains[entry['DomainIndex']] domainEntry = self.ad.get_domain_by_name(domain) if domainEntry is not None: domain = ADUtils.ldap2domain( domainEntry['attributes']['distinguishedName']) if entry['Name'] != '': logging.debug('Resolved SID to name: %s@%s' % (entry['Name'], domain)) self.admins.append({ 'computer': self.hostname, 'name': unicode(entry['Name']), 'use': ADUtils.translateSidType(entry['Use']), 'domain': domain, 'sid': self.sids[i] }) i = i + 1 else: logging.warning('Resolved name is empty [%s]', entry) dce.disconnect()
def run(self): global getting_usernames global got_usernames if getting_usernames: return getting_usernames = True rpctransport = transport.SMBTransport( self.__SMBConnection.getRemoteHost(), filename=r'\lsarpc', smb_connection=self.__SMBConnection) dce = rpctransport.get_dce_rpc() maxRid = 50000 dce.connect() dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsat.hLsarOpenPolicy2( dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] # Get Domain Sid if we are in a domain logging.info('Dumping usernames') resp = lsad.hLsarQueryInformationPolicy2( dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyPrimaryDomainInformation) in_domain = True if resp['PolicyInformation']['PolicyPrimaryDomainInfo']['Sid']: domainSid = resp['PolicyInformation']['PolicyPrimaryDomainInfo'][ 'Sid'].formatCanonical() else: # If we get an exception, maybe we aren't in a domain. Get local Sid instead logging.info( 'Target not joined to a domain. Getting local accounts instead' ) in_domain = False resp = lsad.hLsarQueryInformationPolicy2( dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo'][ 'DomainSid'].formatCanonical() fh = None if self.config.outputFile: try: fh = open(self.config.outputFile, 'w+') except Exception: logging.exception('Could not open file for writing') soFar = 0 SIMULTANEOUS = 1000 for j in range(maxRid / SIMULTANEOUS + 1): if (maxRid - soFar) / SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS if sidsToCheck == 0: break sids = list() for i in xrange(soFar, soFar + sidsToCheck): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids, lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException as e: if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp['TranslatedNames']['Names']): if item['Use'] != SID_NAME_USE.SidTypeUnknown: line = "%d: %s\\%s (%s)" % ( soFar + n, resp['ReferencedDomains']['Domains'][ item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name) print(line) if fh: fh.write(line + '\n') soFar += SIMULTANEOUS if fh: fh.close() dce.disconnect() if in_domain: # Only works if we are relaying to a domain member SAMRDump().dump(self.__SMBConnection) got_usernames = True
def rid_brute(self, maxRid=None): entries = [] if not maxRid: maxRid = int(self.args.rid_brute) KNOWN_PROTOCOLS = { 135: {'bindstr': r'ncacn_ip_tcp:%s', 'set_host': False}, 139: {'bindstr': r'ncacn_np:{}[\pipe\lsarpc]', 'set_host': True}, 445: {'bindstr': r'ncacn_np:{}[\pipe\lsarpc]', 'set_host': True}, } try: stringbinding = KNOWN_PROTOCOLS[self.args.port]['bindstr'].format(self.host) logging.debug('StringBinding {}'.format(stringbinding)) rpctransport = transport.DCERPCTransportFactory(stringbinding) rpctransport.set_dport(self.args.port) if KNOWN_PROTOCOLS[self.args.port]['set_host']: rpctransport.setRemoteHost(self.host) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.username, self.password, self.domain, self.lmhash, self.nthash) dce = rpctransport.get_dce_rpc() dce.connect() except Exception as e: self.logger.error('Error creating DCERPC connection: {}'.format(e)) return entries # Want encryption? Uncomment next line # But make SIMULTANEOUS variable <= 100 #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) # Want fragmentation? Uncomment next line #dce.set_max_fragment_size(32) self.logger.success('Brute forcing RIDs') dce.bind(lsat.MSRPC_UUID_LSAT) resp = lsad.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() soFar = 0 SIMULTANEOUS = 1000 for j in range(maxRid//SIMULTANEOUS+1): if (maxRid - soFar) // SIMULTANEOUS == 0: sidsToCheck = (maxRid - soFar) % SIMULTANEOUS else: sidsToCheck = SIMULTANEOUS if sidsToCheck == 0: break sids = list() for i in range(soFar, soFar+sidsToCheck): sids.append(domainSid + '-%d' % i) try: lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) except DCERPCException as e: if str(e).find('STATUS_NONE_MAPPED') >= 0: soFar += SIMULTANEOUS continue elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: resp = e.get_packet() else: raise for n, item in enumerate(resp['TranslatedNames']['Names']): if item['Use'] != SID_NAME_USE.SidTypeUnknown: rid = soFar + n domain = resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'] user = item['Name'] sid_type = SID_NAME_USE.enumItems(item['Use']).name self.logger.highlight("{}: {}\\{} ({})".format(rid, domain, user, sid_type)) entries.append({'rid': rid, 'domain': domain, 'username': user, 'sidtype': sid_type}) soFar += SIMULTANEOUS dce.disconnect() return entries