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