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 getForestSid(self): logging.debug('Calling NRPC DsrGetDcNameEx()') stringBinding = r'ncacn_np:%s[\pipe\netlogon]' % 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(MSRPC_UUID_NRPC) resp = hDsrGetDcNameEx(dce, NULL, NULL, NULL, NULL, 0) forestName = resp['DomainControllerInfo']['DnsForestName'][:-1] logging.debug('DNS Forest name is %s' % forestName) dce.disconnect() logging.debug('Calling LSAT hLsarQueryInformationPolicy2()') stringBinding = r'ncacn_np:%s[\pipe\lsarpc]' % forestName 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(MSRPC_UUID_LSAT) resp = hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | POLICY_LOOKUP_NAMES) policyHandle = resp['PolicyHandle'] resp = hLsarQueryInformationPolicy2(dce, policyHandle, POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) dce.disconnect() forestSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() logging.info("Forest SID: %s"% forestSid) return forestSid
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 __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 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: print("%d: %s\\%s (%s)" % (soFar + n, resp['ReferencedDomains']['Domains'][ item['DomainIndex']]['Name'], item['Name'], SID_NAME_USE.enumItems(item['Use']).name)) soFar += SIMULTANEOUS dce.disconnect() return entries
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']] domain_entry = self.ad.get_domain_by_name(domain) if domain_entry is not None: domain = ADUtils.ldap2domain(domain_entry['attributes']['distinguishedName']) # TODO: what if it isn't? Should we fall back to LDAP? if entry['Name'] != '': resolved_entry = ADUtils.resolve_sid_entry(entry, domain) logging.debug('Resolved SID to name: %s', resolved_entry['principal']) self.admins.append({'Name': resolved_entry['principal'], 'Type': resolved_entry['type'].capitalize()}) # Add it to our cache self.ad.sidcache.put(sid_string, resolved_entry) else: logging.warning('Resolved name is empty [%s]', entry) dce.disconnect()
def getPolicyHandle(self): resp = lsat.hLsarOpenPolicy2(self.dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) return resp['PolicyHandle']
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()