github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/examples/reg.py (about)

     1  #!/usr/bin/env python
     2  # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
     3  #
     4  # This software is provided under a slightly modified version
     5  # of the Apache Software License. See the accompanying LICENSE file
     6  # for more information.
     7  #
     8  # Description: Remote registry manipulation tool.
     9  #              The idea is to provide similar functionality as the REG.EXE Windows utility.
    10  #
    11  # e.g:
    12  #    ./reg.py Administrator:password@targetMachine query -keyName HKLM\\Software\\Microsoft\\WBEM -s
    13  #
    14  # Author:
    15  #  Manuel Porto (@manuporto)
    16  #  Alberto Solino (@agsolino)
    17  #
    18  # Reference for: [MS-RRP]
    19  #
    20  from __future__ import division
    21  from __future__ import print_function
    22  import argparse
    23  import codecs
    24  import logging
    25  import sys
    26  import time
    27  from struct import unpack
    28  
    29  from impacket import version
    30  from impacket.dcerpc.v5 import transport, rrp, scmr, rpcrt
    31  from impacket.examples import logger
    32  from impacket.system_errors import ERROR_NO_MORE_ITEMS
    33  from impacket.structure import hexdump
    34  from impacket.smbconnection import SMBConnection
    35  
    36  
    37  class RemoteOperations:
    38      def __init__(self, smbConnection, doKerberos, kdcHost=None):
    39          self.__smbConnection = smbConnection
    40          self.__smbConnection.setTimeout(5 * 60)
    41          self.__serviceName = 'RemoteRegistry'
    42          self.__stringBindingWinReg = r'ncacn_np:445[\pipe\winreg]'
    43          self.__rrp = None
    44          self.__regHandle = None
    45  
    46          self.__doKerberos = doKerberos
    47          self.__kdcHost = kdcHost
    48  
    49          self.__disabled = False
    50          self.__shouldStop = False
    51          self.__started = False
    52  
    53          self.__stringBindingSvcCtl = r'ncacn_np:445[\pipe\svcctl]'
    54          self.__scmr = None
    55  
    56      def getRRP(self):
    57          return self.__rrp
    58  
    59      def __connectSvcCtl(self):
    60          rpc = transport.DCERPCTransportFactory(self.__stringBindingSvcCtl)
    61          rpc.set_smb_connection(self.__smbConnection)
    62          self.__scmr = rpc.get_dce_rpc()
    63          self.__scmr.connect()
    64          self.__scmr.bind(scmr.MSRPC_UUID_SCMR)
    65  
    66      def connectWinReg(self):
    67          rpc = transport.DCERPCTransportFactory(self.__stringBindingWinReg)
    68          rpc.set_smb_connection(self.__smbConnection)
    69          self.__rrp = rpc.get_dce_rpc()
    70          self.__rrp.connect()
    71          self.__rrp.bind(rrp.MSRPC_UUID_RRP)
    72  
    73      def __checkServiceStatus(self):
    74          # Open SC Manager
    75          ans = scmr.hROpenSCManagerW(self.__scmr)
    76          self.__scManagerHandle = ans['lpScHandle']
    77          # Now let's open the service
    78          ans = scmr.hROpenServiceW(self.__scmr, self.__scManagerHandle, self.__serviceName)
    79          self.__serviceHandle = ans['lpServiceHandle']
    80          # Let's check its status
    81          ans = scmr.hRQueryServiceStatus(self.__scmr, self.__serviceHandle)
    82          if ans['lpServiceStatus']['dwCurrentState'] == scmr.SERVICE_STOPPED:
    83              logging.info('Service %s is in stopped state' % self.__serviceName)
    84              self.__shouldStop = True
    85              self.__started = False
    86          elif ans['lpServiceStatus']['dwCurrentState'] == scmr.SERVICE_RUNNING:
    87              logging.debug('Service %s is already running' % self.__serviceName)
    88              self.__shouldStop = False
    89              self.__started = True
    90          else:
    91              raise Exception('Unknown service state 0x%x - Aborting' % ans['CurrentState'])
    92  
    93          # Let's check its configuration if service is stopped, maybe it's disabled :s
    94          if self.__started is False:
    95              ans = scmr.hRQueryServiceConfigW(self.__scmr, self.__serviceHandle)
    96              if ans['lpServiceConfig']['dwStartType'] == 0x4:
    97                  logging.info('Service %s is disabled, enabling it' % self.__serviceName)
    98                  self.__disabled = True
    99                  scmr.hRChangeServiceConfigW(self.__scmr, self.__serviceHandle, dwStartType=0x3)
   100              logging.info('Starting service %s' % self.__serviceName)
   101              scmr.hRStartServiceW(self.__scmr, self.__serviceHandle)
   102              time.sleep(1)
   103  
   104      def enableRegistry(self):
   105          self.__connectSvcCtl()
   106          self.__checkServiceStatus()
   107          self.connectWinReg()
   108  
   109      def __restore(self):
   110          # First of all stop the service if it was originally stopped
   111          if self.__shouldStop is True:
   112              logging.info('Stopping service %s' % self.__serviceName)
   113              scmr.hRControlService(self.__scmr, self.__serviceHandle, scmr.SERVICE_CONTROL_STOP)
   114          if self.__disabled is True:
   115              logging.info('Restoring the disabled state for service %s' % self.__serviceName)
   116              scmr.hRChangeServiceConfigW(self.__scmr, self.__serviceHandle, dwStartType=0x4)
   117  
   118      def finish(self):
   119          self.__restore()
   120          if self.__rrp is not None:
   121              self.__rrp.disconnect()
   122          if self.__scmr is not None:
   123              self.__scmr.disconnect()
   124  
   125  
   126  class RegHandler:
   127      def __init__(self, username, password, domain, options):
   128          self.__username = username
   129          self.__password = password
   130          self.__domain = domain
   131          self.__options = options
   132          self.__action = options.action.upper()
   133          self.__lmhash = ''
   134          self.__nthash = ''
   135          self.__aesKey = options.aesKey
   136          self.__doKerberos = options.k
   137          self.__kdcHost = options.dc_ip
   138          self.__smbConnection = None
   139          self.__remoteOps = None
   140  
   141          # It's possible that this is defined somewhere, but I couldn't find where
   142          self.__regValues = {0: 'REG_NONE', 1: 'REG_SZ', 2: 'REG_EXPAND_SZ', 3: 'REG_BINARY', 4: 'REG_DWORD',
   143                              5: 'REG_DWORD_BIG_ENDIAN', 6: 'REG_LINK', 7: 'REG_MULTI_SZ', 11: 'REG_QWORD'}
   144  
   145          if options.hashes is not None:
   146              self.__lmhash, self.__nthash = options.hashes.split(':')
   147  
   148      def connect(self, remoteName, remoteHost):
   149          self.__smbConnection = SMBConnection(remoteName, remoteHost, sess_port=int(self.__options.port))
   150  
   151          if self.__doKerberos:
   152              self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
   153                                                 self.__nthash, self.__aesKey, self.__kdcHost)
   154          else:
   155              self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
   156  
   157      def run(self, remoteName, remoteHost):
   158          self.connect(remoteName, remoteHost)
   159          self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost)
   160  
   161          try:
   162              self.__remoteOps.enableRegistry()
   163          except Exception as e:
   164              logging.debug(str(e))
   165              logging.warning('Cannot check RemoteRegistry status. Hoping it is started...')
   166              self.__remoteOps.connectWinReg()
   167  
   168          try:
   169              dce = self.__remoteOps.getRRP()
   170  
   171              if self.__action == 'QUERY':
   172                  self.query(dce, self.__options.keyName)
   173              else:
   174                  logging.error('Method %s not implemented yet!' % self.__action)
   175          except (Exception, KeyboardInterrupt) as e:
   176              #import traceback
   177              #traceback.print_exc()
   178              logging.critical(str(e))
   179          finally:
   180              if self.__remoteOps:
   181                  self.__remoteOps.finish()
   182  
   183      def query(self, dce, keyName):
   184          # Let's strip the root key
   185          try:
   186              rootKey = keyName.split('\\')[0]
   187              subKey = '\\'.join(keyName.split('\\')[1:])
   188          except Exception:
   189              raise Exception('Error parsing keyName %s' % keyName)
   190  
   191          if rootKey.upper() == 'HKLM':
   192              ans = rrp.hOpenLocalMachine(dce)
   193          elif rootKey.upper() == 'HKU':
   194              ans = rrp.hOpenCurrentUser(dce)
   195          elif rootKey.upper() == 'HKCR':
   196              ans = rrp.hOpenClassesRoot(dce)
   197          else:
   198              raise Exception('Invalid root key %s ' % rootKey)
   199  
   200          hRootKey = ans['phKey']
   201  
   202          ans2 = rrp.hBaseRegOpenKey(dce, hRootKey, subKey,
   203                                     samDesired=rrp.MAXIMUM_ALLOWED | rrp.KEY_ENUMERATE_SUB_KEYS | rrp.KEY_QUERY_VALUE)
   204  
   205          if self.__options.v:
   206              print(keyName)
   207              value = rrp.hBaseRegQueryValue(dce, ans2['phkResult'], self.__options.v)
   208              print('\t' + self.__options.v + '\t' + self.__regValues.get(value[0], 'KEY_NOT_FOUND') + '\t', str(value[1]))
   209          elif self.__options.ve:
   210              print(keyName)
   211              value = rrp.hBaseRegQueryValue(dce, ans2['phkResult'], '')
   212              print('\t' + '(Default)' + '\t' + self.__regValues.get(value[0], 'KEY_NOT_FOUND') + '\t', str(value[1]))
   213          elif self.__options.s:
   214              self.__print_all_subkeys_and_entries(dce, subKey + '\\', ans2['phkResult'], 0)
   215          else:
   216              print(keyName)
   217              self.__print_key_values(dce, ans2['phkResult'])
   218              i = 0
   219              while True:
   220                  try:
   221                      key = rrp.hBaseRegEnumKey(dce, ans2['phkResult'], i)
   222                      print(keyName + '\\' + key['lpNameOut'][:-1])
   223                      i += 1
   224                  except Exception:
   225                      break
   226                      # ans5 = rrp.hBaseRegGetVersion(rpc, ans2['phkResult'])
   227                      # ans3 = rrp.hBaseRegEnumKey(rpc, ans2['phkResult'], 0)
   228  
   229      def __print_key_values(self, rpc, keyHandler):
   230          i = 0
   231          while True:
   232              try:
   233                  ans4 = rrp.hBaseRegEnumValue(rpc, keyHandler, i)
   234                  lp_value_name = ans4['lpValueNameOut'][:-1]
   235                  if len(lp_value_name) == 0:
   236                      lp_value_name = '(Default)'
   237                  lp_type = ans4['lpType']
   238                  lp_data = b''.join(ans4['lpData'])
   239                  print('\t' + lp_value_name + '\t' + self.__regValues.get(lp_type, 'KEY_NOT_FOUND') + '\t', end=' ')
   240                  self.__parse_lp_data(lp_type, lp_data)
   241                  i += 1
   242              except rrp.DCERPCSessionError as e:
   243                  if e.get_error_code() == ERROR_NO_MORE_ITEMS:
   244                      break
   245  
   246      def __print_all_subkeys_and_entries(self, rpc, keyName, keyHandler, index):
   247          index = 0
   248          while True:
   249              try:
   250                  subkey = rrp.hBaseRegEnumKey(rpc, keyHandler, index)
   251                  index += 1
   252                  ans = rrp.hBaseRegOpenKey(rpc, keyHandler, subkey['lpNameOut'],
   253                                            samDesired=rrp.MAXIMUM_ALLOWED | rrp.KEY_ENUMERATE_SUB_KEYS)
   254                  newKeyName = keyName + subkey['lpNameOut'][:-1] + '\\'
   255                  print(newKeyName)
   256                  self.__print_key_values(rpc, ans['phkResult'])
   257                  self.__print_all_subkeys_and_entries(rpc, newKeyName, ans['phkResult'], 0)
   258              except rrp.DCERPCSessionError as e:
   259                  if e.get_error_code() == ERROR_NO_MORE_ITEMS:
   260                      break
   261              except rpcrt.DCERPCException as e:
   262                  if str(e).find('access_denied') >= 0:
   263                      logging.error('Cannot access subkey %s, bypassing it' % subkey['lpNameOut'][:-1])
   264                      continue
   265                  elif str(e).find('rpc_x_bad_stub_data') >= 0:
   266                      logging.error('Fault call, cannot retrieve value for %s, bypassing it' % subkey['lpNameOut'][:-1])
   267                      return
   268                  raise
   269  
   270      @staticmethod
   271      def __parse_lp_data(valueType, valueData):
   272          try:
   273              if valueType == rrp.REG_SZ or valueType == rrp.REG_EXPAND_SZ:
   274                  if type(valueData) is int:
   275                      print('NULL')
   276                  else:
   277                      print("%s" % (valueData.decode('utf-16le')[:-1]))
   278              elif valueType == rrp.REG_BINARY:
   279                  print('')
   280                  hexdump(valueData, '\t')
   281              elif valueType == rrp.REG_DWORD:
   282                  print("0x%x" % (unpack('<L', valueData)[0]))
   283              elif valueType == rrp.REG_QWORD:
   284                  print("0x%x" % (unpack('<Q', valueData)[0]))
   285              elif valueType == rrp.REG_NONE:
   286                  try:
   287                      if len(valueData) > 1:
   288                          print('')
   289                          hexdump(valueData, '\t')
   290                      else:
   291                          print(" NULL")
   292                  except:
   293                      print(" NULL")
   294              elif valueType == rrp.REG_MULTI_SZ:
   295                  print("%s" % (valueData.decode('utf-16le')[:-2]))
   296              else:
   297                  print("Unknown Type 0x%x!" % valueType)
   298                  hexdump(valueData)
   299          except Exception as e:
   300              logging.debug('Exception thrown when printing reg value %s', str(e))
   301              print('Invalid data')
   302              pass
   303  
   304  
   305  if __name__ == '__main__':
   306  
   307      # Init the example's logger theme
   308      logger.init()
   309      # Explicitly changing the stdout encoding format
   310      if sys.stdout.encoding is None:
   311          # Output is redirected to a file
   312          sys.stdout = codecs.getwriter('utf8')(sys.stdout)
   313      print(version.BANNER)
   314  
   315      parser = argparse.ArgumentParser(add_help=True, description="Windows Register manipulation script.")
   316  
   317      parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
   318      parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
   319      subparsers = parser.add_subparsers(help='actions', dest='action')
   320  
   321      # A query command
   322      query_parser = subparsers.add_parser('query', help='Returns a list of the next tier of subkeys and entries that '
   323                                                         'are located under a specified subkey in the registry.')
   324      query_parser.add_argument('-keyName', action='store', required=True,
   325                                help='Specifies the full path of the subkey. The '
   326                                     'keyName must include a valid root key. Valid root keys for the local computer are: HKLM,'
   327                                     ' HKU.')
   328      query_parser.add_argument('-v', action='store', metavar="VALUENAME", required=False, help='Specifies the registry '
   329                             'value name that is to be queried. If omitted, all value names for keyName are returned. ')
   330      query_parser.add_argument('-ve', action='store_true', default=False, required=False, help='Queries for the default '
   331                                                                           'value or empty value name')
   332      query_parser.add_argument('-s', action='store_true', default=False, help='Specifies to query all subkeys and value '
   333                                                                               'names recursively.')
   334  
   335      # An add command
   336      # add_parser = subparsers.add_parser('add', help='Adds a new subkey or entry to the registry')
   337  
   338      # An delete command
   339      # delete_parser = subparsers.add_parser('delete', help='Deletes a subkey or entries from the registry')
   340  
   341      # A copy command
   342      # copy_parser = subparsers.add_parser('copy', help='Copies a registry entry to a specified location in the remote '
   343      #                                                   'computer')
   344  
   345      # A save command
   346      # save_parser = subparsers.add_parser('save', help='Saves a copy of specified subkeys, entries, and values of the '
   347      #                                                 'registry in a specified file.')
   348  
   349      # A load command
   350      # load_parser = subparsers.add_parser('load', help='Writes saved subkeys and entries back to a different subkey in '
   351      #                                                 'the registry.')
   352  
   353      # An unload command
   354      # unload_parser = subparsers.add_parser('unload', help='Removes a section of the registry that was loaded using the '
   355      #                                                     'reg load operation.')
   356  
   357      # A compare command
   358      # compare_parser = subparsers.add_parser('compare', help='Compares specified registry subkeys or entries')
   359  
   360      # A export command
   361      # status_parser = subparsers.add_parser('export', help='Creates a copy of specified subkeys, entries, and values into'
   362      #                                                     'a file')
   363  
   364      # A import command
   365      # import_parser = subparsers.add_parser('import', help='Copies a file containing exported registry subkeys, entries, '
   366      #                                                     'and values into the remote computer\'s registry')
   367  
   368  
   369      group = parser.add_argument_group('authentication')
   370  
   371      group.add_argument('-hashes', action="store", metavar="LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
   372      group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
   373      group.add_argument('-k', action="store_true",
   374                         help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on '
   375                              'target parameters. If valid credentials cannot be found, it will use the ones specified '
   376                              'in the command line')
   377      group.add_argument('-aesKey', action="store", metavar="hex key",
   378                         help='AES key to use for Kerberos Authentication (128 or 256 bits)')
   379  
   380      group = parser.add_argument_group('connection')
   381  
   382      group.add_argument('-dc-ip', action='store', metavar="ip address",
   383                         help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in '
   384                              'the target parameter')
   385      group.add_argument('-target-ip', action='store', metavar="ip address",
   386                         help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
   387                              'This is useful when target is the NetBIOS name and you cannot resolve it')
   388      group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port",
   389                         help='Destination port to connect to SMB Server')
   390  
   391      if len(sys.argv) == 1:
   392          parser.print_help()
   393          sys.exit(1)
   394  
   395      options = parser.parse_args()
   396  
   397      if options.debug is True:
   398          logging.getLogger().setLevel(logging.DEBUG)
   399      else:
   400          logging.getLogger().setLevel(logging.INFO)
   401  
   402      import re
   403  
   404      domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(
   405          options.target).groups('')
   406  
   407      # In case the password contains '@'
   408      if '@' in remoteName:
   409          password = password + '@' + remoteName.rpartition('@')[0]
   410          remoteName = remoteName.rpartition('@')[2]
   411  
   412      if options.target_ip is None:
   413          options.target_ip = remoteName
   414  
   415      if domain is None:
   416          domain = ''
   417  
   418      if options.aesKey is not None:
   419          options.k = True
   420  
   421      if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
   422          from getpass import getpass
   423  
   424          password = getpass("Password:")
   425  
   426      regHandler = RegHandler(username, password, domain, options)
   427      try:
   428          regHandler.run(remoteName, options.target_ip)
   429      except Exception as e:
   430          #import traceback
   431          #traceback.print_exc()
   432          logging.error(str(e))