Advertisement
opexxx

wmiexec.py

May 15th, 2014
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.40 KB | None | 0 0
  1. #!/usr/bin/python
  2. # Copyright (c) 2003-2014 CORE Security Technologies
  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. # $Id$
  9. #
  10. # A similar approach to smbexec but executing commands through WMI.
  11. # Main advantage here is it runs under the user (has to be Admin)
  12. # account, not SYSTEM, plus, it doesn't generate noisy messages
  13. # in the event log that smbexec.py does when creating a service.
  14. # Drawback is it needs DCOM, hence, I have to be able to access
  15. # DCOM ports at the target machine.
  16. #
  17. # Author:
  18. #  beto (bethus@gmail.com)
  19. #
  20. # Reference for:
  21. #  DCOM
  22. #
  23.  
  24. import sys
  25. import os
  26. import cmd
  27. import argparse
  28. import time
  29. import ntpath
  30.  
  31. from impacket import version, ntlm
  32. from impacket.smbconnection import *
  33. from impacket.dcerpc.v5.dcomrt import DCOMConnection
  34. from impacket.dcerpc.v5.dcom import wmi
  35. from impacket.dcerpc.v5.dtypes import NULL
  36.  
  37. OUTPUT_FILENAME = '__'
  38.  
  39. class WMIEXEC:
  40.     def __init__(self, command = '', username = '', password = '', domain = '', hashes = None, share = None, noOutput=False):
  41.         self.__command = command
  42.         self.__username = username
  43.         self.__password = password
  44.         self.__domain = domain
  45.         self.__lmhash = ''
  46.         self.__nthash = ''
  47.         self.__share = share
  48.         self.__noOutput = noOutput
  49.         if hashes is not None:
  50.             self.__lmhash, self.__nthash = hashes.split(':')
  51.  
  52.     def run(self, addr):
  53.         if self.__noOutput is False:
  54.             smbConnection = SMBConnection(addr, addr)
  55.             smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
  56.             dialect = smbConnection.getDialect()
  57.             if dialect == SMB_DIALECT:
  58.                 print("SMBv1 dialect used")
  59.             elif dialect == SMB2_DIALECT_002:
  60.                 print("SMBv2.0 dialect used")
  61.             elif dialect == SMB2_DIALECT_21:
  62.                 print("SMBv2.1 dialect used")
  63.             else:
  64.                 print("SMBv3.0 dialect used")
  65.         else:
  66.             smbConnection = None
  67.  
  68.         dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, oxidResolver = True)
  69.  
  70.         iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login)
  71.         iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
  72.         iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
  73.         iWbemLevel1Login.RemRelease()
  74.  
  75.         win32Process,_ = iWbemServices.GetObject('Win32_Process')
  76.  
  77.         try:
  78.             self.shell = RemoteShell(self.__share, win32Process, smbConnection)
  79.             if self.__command != ' ':
  80.                 self.shell.onecmd(self.__command)
  81.             else:
  82.                 self.shell.cmdloop()
  83.         except  (Exception, KeyboardInterrupt), e:
  84.             #import traceback
  85.             #traceback.print_exc()
  86.             print e
  87.             if smbConnection is not None:
  88.                 smbConnection.logoff()
  89.             dcom.disconnect()
  90.             sys.stdout.flush()
  91.             sys.exit(1)
  92.  
  93.         if smbConnection is not None:
  94.             smbConnection.logoff()
  95.         dcom.disconnect()
  96.  
  97. class RemoteShell(cmd.Cmd):
  98.     def __init__(self, share, win32Process, smbConnection):
  99.         cmd.Cmd.__init__(self)
  100.         self.__share = share
  101.         self.__output = '\\' + OUTPUT_FILENAME
  102.         self.__outputBuffer = ''
  103.         self.__shell = 'cmd.exe /Q /c '
  104.         self.__win32Process = win32Process
  105.         self.__transferClient = smbConnection
  106.         self.__pwd = 'C:\\'
  107.         self.__noOutput = False
  108.         self.intro = '[!] Launching semi-interactive shell - Careful what you execute'
  109.  
  110.         # We don't wanna deal with timeouts from now on.
  111.         if self.__transferClient is not None:
  112.             self.__transferClient.setTimeout(100000)
  113.             self.do_cd('\\')
  114.         else:
  115.             self.__noOutput = True
  116.  
  117.     def do_shell(self, s):
  118.         os.system(s)
  119.  
  120.     def do_exit(self, s):
  121.         return True
  122.  
  123.     def emptyline(self):
  124.         return False
  125.  
  126.     def do_cd(self, s):
  127.         self.execute_remote('cd ' + s)
  128.         if len(self.__outputBuffer.strip('\r\n')) > 0:
  129.             print self.__outputBuffer
  130.             self.__outputBuffer = ''
  131.         else:
  132.             self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s))
  133.             self.execute_remote('cd ')
  134.             self.__pwd = self.__outputBuffer.strip('\r\n')
  135.             self.prompt = self.__pwd + '>'
  136.             self.__outputBuffer = ''
  137.  
  138.     def default(self, line):
  139.         # Let's try to guess if the user is trying to change drive
  140.         if len(line) == 2 and line[1] == ':':
  141.             # Execute the command and see if the drive is valid
  142.             self.execute_remote(line)
  143.             if len(self.__outputBuffer.strip('\r\n')) > 0:
  144.                 # Something went wrong
  145.                 print self.__outputBuffer
  146.                 self.__outputBuffer = ''
  147.             else:
  148.                 # Drive valid, now we should get the current path
  149.                 self.__pwd = line
  150.                 self.execute_remote('cd ')
  151.                 self.__pwd = self.__outputBuffer.strip('\r\n')
  152.                 self.prompt = self.__pwd + '>'
  153.                 self.__outputBuffer = ''
  154.         else:
  155.             if line != '':
  156.                 self.send_data(line)
  157.  
  158.     def get_output(self):
  159.         def output_callback(data):
  160.             self.__outputBuffer += data
  161.  
  162.         if self.__noOutput is True:
  163.             self.__outputBuffer = ''
  164.             return
  165.  
  166.         while True:
  167.             try:
  168.                 self.__transferClient.getFile(self.__share, self.__output, output_callback)
  169.                 break
  170.             except Exception, e:
  171.                 if str(e).find('STATUS_SHARING_VIOLATION') >=0:
  172.                     # Output not finished, let's wait
  173.                     time.sleep(1)
  174.                     pass
  175.                 else:
  176.                     #print str(e)
  177.                     pass
  178.         self.__transferClient.deleteFile(self.__share, self.__output)
  179.  
  180.     def execute_remote(self, data):
  181.         command = self.__shell + data
  182.         if self.__noOutput is False:
  183.             command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output  + ' 2>&1'
  184.         obj = self.__win32Process.Create(command, self.__pwd, None)
  185.         self.get_output()
  186.  
  187.     def send_data(self, data):
  188.         self.execute_remote(data)
  189.         print self.__outputBuffer
  190.         self.__outputBuffer = ''
  191.  
  192.  
  193. # Process command-line arguments.
  194. if __name__ == '__main__':
  195.     print version.BANNER
  196.  
  197.     parser = argparse.ArgumentParser()
  198.  
  199.     parser.add_argument('target', action='store', help='[domain/][username[:password]@]<address>')
  200.     parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from (default ADMIN$)')
  201.     parser.add_argument('-nooutput', action='store_true', default = False, help='whether or not to print the output (no SMB connection created)')
  202.  
  203.     parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will launch a semi-interactive shell')
  204.  
  205.     group = parser.add_argument_group('authentication')
  206.  
  207.     group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
  208.  
  209.     if len(sys.argv)==1:
  210.         parser.print_help()
  211.         sys.exit(1)
  212.  
  213.     options = parser.parse_args()
  214.  
  215.     if ' '.join(options.command) == ' ' and options.nooutput is True:
  216.         print "ERROR: -nooutput switch and interactive shell not supported"
  217.         sys.exit(1)
  218.    
  219.  
  220.     import re
  221.     domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('')
  222.  
  223.     try:
  224.         if domain is None:
  225.             domain = ''
  226.  
  227.         if password == '' and username != '' and options.hashes is None:
  228.             from getpass import getpass
  229.             password = getpass("Password:")
  230.  
  231.         executer = WMIEXEC(' '.join(options.command), username, password, domain, options.hashes, options.share, options.nooutput)
  232.         executer.run(address)
  233.     except (Exception, KeyboardInterrupt), e:
  234.         #import traceback
  235.         #print traceback.print_exc()
  236.         print '\nERROR: %s' % e
  237.     sys.exit(0)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement