github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/examples/lookupsid.py (about) 1 #!/usr/bin/env python 2 # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 3 # 4 # This software is provided under under a slightly modified version 5 # of the Apache Software License. See the accompanying LICENSE file 6 # for more information. 7 # 8 # DCE/RPC lookup sid brute forcer example 9 # 10 # Author: 11 # Alberto Solino (@agsolino) 12 # 13 # Reference for: 14 # DCE/RPC [MS-LSAT] 15 from __future__ import division 16 from __future__ import print_function 17 import sys 18 import logging 19 import argparse 20 import codecs 21 22 from impacket.examples import logger 23 from impacket import version 24 from impacket.dcerpc.v5 import transport, lsat, lsad 25 from impacket.dcerpc.v5.samr import SID_NAME_USE 26 from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED 27 from impacket.dcerpc.v5.rpcrt import DCERPCException 28 29 30 class LSALookupSid: 31 KNOWN_PROTOCOLS = { 32 135: {'bindstr': r'ncacn_ip_tcp:%s', 'set_host': False}, 33 139: {'bindstr': r'ncacn_np:%s[\pipe\lsarpc]', 'set_host': True}, 34 445: {'bindstr': r'ncacn_np:%s[\pipe\lsarpc]', 'set_host': True}, 35 } 36 37 def __init__(self, username='', password='', domain='', port = None, 38 hashes = None, domain_sids = False, maxRid=4000): 39 40 self.__username = username 41 self.__password = password 42 self.__port = port 43 self.__maxRid = int(maxRid) 44 self.__domain = domain 45 self.__lmhash = '' 46 self.__nthash = '' 47 self.__domain_sids = domain_sids 48 if hashes is not None: 49 self.__lmhash, self.__nthash = hashes.split(':') 50 51 def dump(self, remoteName, remoteHost): 52 53 logging.info('Brute forcing SIDs at %s' % remoteName) 54 55 stringbinding = self.KNOWN_PROTOCOLS[self.__port]['bindstr'] % remoteName 56 logging.info('StringBinding %s'%stringbinding) 57 rpctransport = transport.DCERPCTransportFactory(stringbinding) 58 rpctransport.set_dport(self.__port) 59 60 if self.KNOWN_PROTOCOLS[self.__port]['set_host']: 61 rpctransport.setRemoteHost(remoteHost) 62 63 if hasattr(rpctransport, 'set_credentials'): 64 # This method exists only for selected protocol sequences. 65 rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) 66 67 try: 68 self.__bruteForce(rpctransport, self.__maxRid) 69 except Exception as e: 70 if logging.getLogger().level == logging.DEBUG: 71 import traceback 72 traceback.print_exc() 73 logging.critical(str(e)) 74 raise 75 76 def __bruteForce(self, rpctransport, maxRid): 77 dce = rpctransport.get_dce_rpc() 78 entries = [] 79 dce.connect() 80 81 # Want encryption? Uncomment next line 82 # But make SIMULTANEOUS variable <= 100 83 #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) 84 85 # Want fragmentation? Uncomment next line 86 #dce.set_max_fragment_size(32) 87 88 dce.bind(lsat.MSRPC_UUID_LSAT) 89 90 resp = lsad.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES) 91 policyHandle = resp['PolicyHandle'] 92 93 if self.__domain_sids: # get the Domain SID 94 resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyPrimaryDomainInformation) 95 domainSid = resp['PolicyInformation']['PolicyPrimaryDomainInfo']['Sid'].formatCanonical() 96 else: # Get the target host SID 97 resp = lsad.hLsarQueryInformationPolicy2(dce, policyHandle, lsad.POLICY_INFORMATION_CLASS.PolicyAccountDomainInformation) 98 domainSid = resp['PolicyInformation']['PolicyAccountDomainInfo']['DomainSid'].formatCanonical() 99 100 logging.info('Domain SID is: %s' % domainSid) 101 102 soFar = 0 103 SIMULTANEOUS = 1000 104 for j in range(maxRid//SIMULTANEOUS+1): 105 if (maxRid - soFar) // SIMULTANEOUS == 0: 106 sidsToCheck = (maxRid - soFar) % SIMULTANEOUS 107 else: 108 sidsToCheck = SIMULTANEOUS 109 110 if sidsToCheck == 0: 111 break 112 113 sids = list() 114 for i in range(soFar, soFar+sidsToCheck): 115 sids.append(domainSid + '-%d' % i) 116 try: 117 lsat.hLsarLookupSids(dce, policyHandle, sids,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta) 118 except DCERPCException as e: 119 if str(e).find('STATUS_NONE_MAPPED') >= 0: 120 soFar += SIMULTANEOUS 121 continue 122 elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0: 123 resp = e.get_packet() 124 else: 125 raise 126 127 for n, item in enumerate(resp['TranslatedNames']['Names']): 128 if item['Use'] != SID_NAME_USE.SidTypeUnknown: 129 print("%d: %s\\%s (%s)" % ( 130 soFar + n, resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name'], item['Name'], 131 SID_NAME_USE.enumItems(item['Use']).name)) 132 soFar += SIMULTANEOUS 133 134 dce.disconnect() 135 136 return entries 137 138 139 # Process command-line arguments. 140 if __name__ == '__main__': 141 # Init the example's logger theme 142 logger.init() 143 # Explicitly changing the stdout encoding format 144 if sys.stdout.encoding is None: 145 # Output is redirected to a file 146 sys.stdout = codecs.getwriter('utf8')(sys.stdout) 147 print(version.BANNER) 148 149 parser = argparse.ArgumentParser() 150 151 parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>') 152 parser.add_argument('maxRid', action='store', default = '4000', nargs='?', help='max Rid to check (default 4000)') 153 154 group = parser.add_argument_group('connection') 155 156 group.add_argument('-target-ip', action='store', metavar="ip address", help='IP Address of the target machine. ' 157 'If omitted it will use whatever was specified as target. This is useful when target is the ' 158 'NetBIOS name and you cannot resolve it') 159 group.add_argument('-port', choices=['135', '139', '445'], nargs='?', default='445', metavar="destination port", 160 help='Destination port to connect to SMB Server') 161 group.add_argument('-domain-sids', action='store_true', help='Enumerate Domain SIDs (will likely forward requests to the DC)') 162 163 group = parser.add_argument_group('authentication') 164 165 group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') 166 group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful when proxying through smbrelayx)') 167 168 if len(sys.argv)==1: 169 parser.print_help() 170 sys.exit(1) 171 172 options = parser.parse_args() 173 174 import re 175 176 domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( 177 options.target).groups('') 178 179 #In case the password contains '@' 180 if '@' in remoteName: 181 password = password + '@' + remoteName.rpartition('@')[0] 182 remoteName = remoteName.rpartition('@')[2] 183 184 if domain is None: 185 domain = '' 186 187 if password == '' and username != '' and options.hashes is None and options.no_pass is False: 188 from getpass import getpass 189 password = getpass("Password:") 190 191 if options.target_ip is None: 192 options.target_ip = remoteName 193 194 lookup = LSALookupSid(username, password, domain, int(options.port), options.hashes, options.domain_sids, options.maxRid) 195 try: 196 lookup.dump(remoteName, options.target_ip) 197 except: 198 pass