github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/examples/mimikatz.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  # Description: Mini shell to control a remote mimikatz RPC server developed by @gentilkiwi
     9  #
    10  # Author:
    11  #  Alberto Solino (@agsolino)
    12  #
    13  # Reference for:
    14  #  SMB DCE/RPC 
    15  #
    16  from __future__ import division
    17  from __future__ import print_function
    18  import argparse
    19  import cmd
    20  import logging
    21  import os
    22  import sys
    23  
    24  from impacket import version
    25  from impacket.dcerpc.v5 import epm, mimilib
    26  from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE
    27  from impacket.dcerpc.v5.transport import DCERPCTransportFactory
    28  from impacket.examples import logger
    29  
    30  try:
    31      from Cryptodome.Cipher import ARC4
    32  except Exception:
    33      logging.critical("Warning: You don't have any crypto installed. You need pycryptodomex")
    34      logging.critical("See https://pypi.org/project/pycryptodomex/")
    35  
    36  # If you wanna have readline like functionality in Windows, install pyreadline
    37  try:
    38    import pyreadline as readline
    39  except ImportError:
    40    import readline
    41  
    42  class MimikatzShell(cmd.Cmd):
    43      def __init__(self, dce):
    44          cmd.Cmd.__init__(self)
    45          self.shell = None
    46  
    47          self.prompt = 'mimikatz # '
    48          self.tid = None
    49          self.intro = '' \
    50                      '  .#####.   mimikatz RPC interface\n'\
    51                      ' .## ^ ##.  "A La Vie, A L\' Amour "\n'\
    52                      ' ## / \ ##  /* * *\n'\
    53                      ' ## \ / ##   Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )\n'\
    54                      ' \'## v ##\'   http://blog.gentilkiwi.com/mimikatz             (oe.eo)\n'\
    55                      '  \'#####\'    Impacket client by Alberto Solino (@agsolino)    * * */\n\n'\
    56                      'Type help for list of commands'
    57          self.pwd = ''
    58          self.share = None
    59          self.loggedIn = True
    60          self.last_output = None
    61  
    62          self.dce = dce
    63  
    64          dh = mimilib.MimiDiffeH()
    65          blob = mimilib.PUBLICKEYBLOB()
    66          blob['y'] = dh.genPublicKey()[::-1]
    67          publicKey = mimilib.MIMI_PUBLICKEY()
    68          publicKey['sessionType'] = mimilib.CALG_RC4
    69          publicKey['cbPublicKey'] = 144
    70          publicKey['pbPublicKey'] = blob.getData()
    71          resp = mimilib.hMimiBind(self.dce, publicKey)
    72          blob = mimilib.PUBLICKEYBLOB(b''.join(resp['serverPublicKey']['pbPublicKey']))
    73  
    74          self.key = dh.getSharedSecret(blob['y'][::-1])[-16:][::-1]
    75          self.pHandle = resp['phMimi']
    76  
    77      def emptyline(self):
    78          pass
    79  
    80      def precmd(self,line):
    81          # switch to unicode
    82          #return line.encode('utf-8')
    83          return line
    84  
    85      def default(self, line):
    86          if line.startswith('*'):
    87              line = line[1:]
    88          command = (line.strip('\n')+'\x00').encode('utf-16le')
    89          command = ARC4.new(self.key).encrypt(command)
    90          resp = mimilib.hMimiCommand(self.dce, self.pHandle, command)
    91          cipherText = b''.join(resp['encResult'])
    92          cipher = ARC4.new(self.key)
    93          print(cipher.decrypt(cipherText).decode('utf-16le'))
    94  
    95      def onecmd(self,s):
    96          retVal = False
    97          try:
    98             retVal = cmd.Cmd.onecmd(self,s)
    99          except Exception as e:
   100             logging.debug("Exception:", exc_info=True)
   101             logging.error(e)
   102  
   103          return retVal
   104  
   105      def do_exit(self,line):
   106          if self.shell is not None:
   107              self.shell.close()
   108          return True
   109  
   110      def do_shell(self, line):
   111          output = os.popen(line).read()
   112          print(output)
   113          self.last_output = output
   114  
   115      def do_help(self,line):
   116          self.default('::')
   117  
   118  def main():
   119      # Init the example's logger theme
   120      logger.init()
   121      print(version.BANNER)
   122      parser = argparse.ArgumentParser(add_help = True, description = "SMB client implementation.")
   123  
   124      parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
   125      parser.add_argument('-file', type=argparse.FileType('r'), help='input file with commands to execute in the mini shell')
   126      parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
   127  
   128      group = parser.add_argument_group('authentication')
   129  
   130      group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
   131      group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
   132      group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
   133                                                         '(KRB5CCNAME) based on target parameters. If valid credentials '
   134                                                         'cannot be found, it will use the ones specified in the command '
   135                                                         'line')
   136      group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication '
   137                                                                              '(128 or 256 bits)')
   138  
   139      group = parser.add_argument_group('connection')
   140  
   141      group.add_argument('-dc-ip', action='store', metavar="ip address",
   142                         help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in '
   143                              'the target parameter')
   144      group.add_argument('-target-ip', action='store', metavar="ip address",
   145                         help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
   146                              'This is useful when target is the NetBIOS name and you cannot resolve it')
   147  
   148      if len(sys.argv)==1:
   149          parser.print_help()
   150          sys.exit(1)
   151  
   152      options = parser.parse_args()
   153  
   154      if options.debug is True:
   155          logging.getLogger().setLevel(logging.DEBUG)
   156      else:
   157          logging.getLogger().setLevel(logging.INFO)
   158  
   159      import re
   160      domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(
   161          options.target).groups('')
   162  
   163      #In case the password contains '@'
   164      if '@' in address:
   165          password = password + '@' + address.rpartition('@')[0]
   166          address = address.rpartition('@')[2]
   167  
   168      if options.target_ip is None:
   169          options.target_ip = address
   170  
   171      if domain is None:
   172          domain = ''
   173      
   174      if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
   175          from getpass import getpass
   176          password = getpass("Password:")
   177  
   178      if options.aesKey is not None:
   179          options.k = True
   180  
   181      if options.hashes is not None:
   182          lmhash, nthash = options.hashes.split(':')
   183      else:
   184          lmhash = ''
   185          nthash = ''
   186  
   187      bound = False
   188   
   189      try:
   190          if username != '':
   191              try:
   192                  # Let's try to do everything through SMB. If we'e lucky it might get everything encrypted
   193                  rpctransport = DCERPCTransportFactory(r'ncacn_np:%s[\pipe\epmapper]'%address)
   194                  rpctransport.set_credentials(username, password, domain, lmhash, nthash, options.aesKey)
   195                  dce = rpctransport.get_dce_rpc()
   196                  if options.k:
   197                      rpctransport.set_kerberos(True, options.dc_ip)
   198                      dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
   199                  dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
   200                  dce.connect()
   201                  # Give me the endpoint please!
   202                  stringBinding = epm.hept_map(address, mimilib.MSRPC_UUID_MIMIKATZ, protocol = 'ncacn_np', dce=dce)
   203  
   204                  # Thanks, let's now use the same SMB Connection to bind to mimi
   205                  rpctransport2 = DCERPCTransportFactory(stringBinding)
   206                  rpctransport2.set_smb_connection(rpctransport.get_smb_connection())
   207                  dce = rpctransport2.get_dce_rpc()
   208                  if options.k:
   209                      dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
   210                  dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
   211                  dce.connect()
   212                  dce.bind(mimilib.MSRPC_UUID_MIMIKATZ)
   213                  bound = True
   214              except Exception as e:
   215                  if str(e).find('ept_s_not_registered') >=0:
   216                      # Let's try ncacn_ip_tcp
   217                      stringBinding = epm.hept_map(address, mimilib.MSRPC_UUID_MIMIKATZ, protocol = 'ncacn_ip_tcp')
   218                  else:
   219                      raise
   220  
   221          else:
   222              stringBinding = epm.hept_map(address, mimilib.MSRPC_UUID_MIMIKATZ, protocol = 'ncacn_ip_tcp')
   223  
   224          if bound is False:
   225              rpctransport = DCERPCTransportFactory(stringBinding)
   226              rpctransport.set_credentials(username, password, domain, lmhash, nthash, options.aesKey)
   227              dce = rpctransport.get_dce_rpc()
   228              if options.k is True:
   229                  rpctransport.set_kerberos(True, options.dc_ip)
   230                  dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
   231              rpctransport.set_credentials(username, password, domain, lmhash, nthash)
   232              dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
   233              dce.connect()
   234              dce.bind(mimilib.MSRPC_UUID_MIMIKATZ)
   235  
   236          shell = MimikatzShell(dce)
   237  
   238          if options.file is not None:
   239              logging.info("Executing commands from %s" % options.file.name)
   240              for line in options.file.readlines():
   241                  if line[0] != '#':
   242                      print("# %s" % line, end=' ')
   243                      shell.onecmd(line)
   244                  else:
   245                      print(line, end=' ')
   246          else:
   247              shell.cmdloop()
   248      except Exception as e:
   249          logging.debug("Exception:", exc_info=True)
   250          logging.error(str(e))
   251  
   252  if __name__ == "__main__":
   253      main()