Advertisement
Guest User

Untitled

a guest
Nov 10th, 2016
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.45 KB | None | 0 0
  1. #!/opt/agent/venv/bin/python
  2. # Copyright (c) 2003-2016 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. # A similar approach to smbexec but executing commands through WMI.
  9. # Main advantage here is it runs under the user (has to be Admin)
  10. # account, not SYSTEM, plus, it doesn't generate noisy messages
  11. # in the event log that smbexec.py does when creating a service.
  12. # Drawback is it needs DCOM, hence, I have to be able to access
  13. # DCOM ports at the target machine.
  14. #
  15. # Author:
  16. # beto (@agsolino)
  17. #
  18. # Reference for:
  19. # DCOM
  20. #
  21.  
  22. import sys
  23. import os
  24. import cmd
  25. import argparse
  26. import time
  27. import logging
  28. import string
  29. import ntpath
  30.  
  31. from impacket.examples import logger
  32. from impacket import version
  33. from impacket.smbconnection import SMBConnection, SMB_DIALECT, SMB2_DIALECT_002, SMB2_DIALECT_21
  34. from impacket.dcerpc.v5.dcomrt import DCOMConnection
  35. from impacket.dcerpc.v5.dcom import wmi
  36. from impacket.dcerpc.v5.dtypes import NULL
  37.  
  38. OUTPUT_FILENAME = '__' + str(time.time())
  39.  
  40. class WMIEXEC:
  41. def __init__(self, command='', username='', password='', domain='', hashes=None, aesKey=None, share=None,
  42. noOutput=False, doKerberos=False, kdcHost=None):
  43. self.__command = command
  44. self.__username = username
  45. self.__password = password
  46. self.__domain = domain
  47. self.__lmhash = ''
  48. self.__nthash = ''
  49. self.__aesKey = aesKey
  50. self.__share = share
  51. self.__noOutput = noOutput
  52. self.__doKerberos = doKerberos
  53. self.__kdcHost = kdcHost
  54. self.shell = None
  55. if hashes is not None:
  56. self.__lmhash, self.__nthash = hashes.split(':')
  57.  
  58. def run(self, addr):
  59. if self.__noOutput is False:
  60. smbConnection = SMBConnection(addr, addr)
  61. if self.__doKerberos is False:
  62. smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
  63. else:
  64. smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
  65. self.__nthash, self.__aesKey, kdcHost=self.__kdcHost)
  66.  
  67. dialect = smbConnection.getDialect()
  68. if dialect == SMB_DIALECT:
  69. logging.info("SMBv1 dialect used")
  70. elif dialect == SMB2_DIALECT_002:
  71. logging.info("SMBv2.0 dialect used")
  72. elif dialect == SMB2_DIALECT_21:
  73. logging.info("SMBv2.1 dialect used")
  74. else:
  75. logging.info("SMBv3.0 dialect used")
  76. else:
  77. smbConnection = None
  78.  
  79. dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,
  80. self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost)
  81. try:
  82. iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login)
  83. iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
  84. iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
  85. iWbemLevel1Login.RemRelease()
  86.  
  87. win32Process,_ = iWbemServices.GetObject('Win32_Process')
  88.  
  89. self.shell = RemoteShell(self.__share, win32Process, smbConnection)
  90. if self.__command != ' ':
  91. self.shell.onecmd(self.__command)
  92. else:
  93. self.shell.cmdloop()
  94. except (Exception, KeyboardInterrupt), e:
  95. #import traceback
  96. #traceback.print_exc()
  97. logging.error(str(e))
  98. if smbConnection is not None:
  99. smbConnection.logoff()
  100. dcom.disconnect()
  101. sys.stdout.flush()
  102. sys.exit(1)
  103.  
  104. if smbConnection is not None:
  105. print "try logoff"
  106. smbConnection.logoff()
  107. print "successfully logout"
  108. dcom.disconnect()
  109. print "successfully disconnected"
  110. time.sleep(10)
  111.  
  112. class RemoteShell(cmd.Cmd):
  113. def __init__(self, share, win32Process, smbConnection):
  114. cmd.Cmd.__init__(self)
  115. self.__share = share
  116. self.__output = '\\' + OUTPUT_FILENAME
  117. self.__outputBuffer = ''
  118. self.__shell = 'cmd.exe /Q /c '
  119. self.__win32Process = win32Process
  120. self.__transferClient = smbConnection
  121. self.__pwd = 'C:\\'
  122. self.__noOutput = False
  123. self.intro = '[!] Launching semi-interactive shell - Careful what you execute\n[!] Press help for extra shell commands'
  124.  
  125. # We don't wanna deal with timeouts from now on.
  126. if self.__transferClient is not None:
  127. self.__transferClient.setTimeout(100000)
  128. self.do_cd('\\')
  129. else:
  130. self.__noOutput = True
  131.  
  132. def do_shell(self, s):
  133. os.system(s)
  134.  
  135. def do_help(self, line):
  136. print """
  137. lcd {path} - changes the current local directory to {path}
  138. exit - terminates the server process (and this session)
  139. put {src_file, dst_path} - uploads a local file to the dst_path (dst_path = default current directory)
  140. get {file} - downloads pathname to the current local dir
  141. ! {cmd} - executes a local shell cmd
  142. """
  143.  
  144. def do_lcd(self, s):
  145. if s == '':
  146. print os.getcwd()
  147. else:
  148. try:
  149. os.chdir(s)
  150. except Exception, e:
  151. logging.error(str(e))
  152.  
  153. def do_get(self, src_path):
  154. try:
  155. import ntpath
  156. newPath = ntpath.normpath(ntpath.join(self.__pwd, src_path))
  157. drive, tail = ntpath.splitdrive(newPath)
  158. filename = ntpath.basename(tail)
  159. fh = open(filename,'wb')
  160. logging.info("Downloading %s\\%s" % (drive, tail))
  161. self.__transferClient.getFile(drive[:-1]+'$', tail, fh.write)
  162. fh.close()
  163. except Exception, e:
  164. logging.error(str(e))
  165. os.remove(filename)
  166. pass
  167.  
  168. def do_put(self, s):
  169. try:
  170. params = s.split(' ')
  171. if len(params) > 1:
  172. src_path = params[0]
  173. dst_path = params[1]
  174. elif len(params) == 1:
  175. src_path = params[0]
  176. dst_path = ''
  177.  
  178. src_file = os.path.basename(src_path)
  179. fh = open(src_path, 'rb')
  180. dst_path = string.replace(dst_path, '/','\\')
  181. import ntpath
  182. pathname = ntpath.join(ntpath.join(self.__pwd,dst_path), src_file)
  183. drive, tail = ntpath.splitdrive(pathname)
  184. logging.info("Uploading %s to %s" % (src_file, pathname))
  185. self.__transferClient.putFile(drive[:-1]+'$', tail, fh.read)
  186. fh.close()
  187. except Exception, e:
  188. logging.critical(str(e))
  189. pass
  190.  
  191. def do_exit(self, s):
  192. return True
  193.  
  194. def emptyline(self):
  195. return False
  196.  
  197. def do_cd(self, s):
  198. self.execute_remote('cd ' + s)
  199. if len(self.__outputBuffer.strip('\r\n')) > 0:
  200. print self.__outputBuffer
  201. self.__outputBuffer = ''
  202. else:
  203. self.__pwd = ntpath.normpath(ntpath.join(self.__pwd, s))
  204. self.execute_remote('cd ')
  205. self.__pwd = self.__outputBuffer.strip('\r\n')
  206. self.prompt = self.__pwd + '>'
  207. self.__outputBuffer = ''
  208.  
  209. def default(self, line):
  210. # Let's try to guess if the user is trying to change drive
  211. if len(line) == 2 and line[1] == ':':
  212. # Execute the command and see if the drive is valid
  213. self.execute_remote(line)
  214. if len(self.__outputBuffer.strip('\r\n')) > 0:
  215. # Something went wrong
  216. print self.__outputBuffer
  217. self.__outputBuffer = ''
  218. else:
  219. # Drive valid, now we should get the current path
  220. self.__pwd = line
  221. self.execute_remote('cd ')
  222. self.__pwd = self.__outputBuffer.strip('\r\n')
  223. self.prompt = self.__pwd + '>'
  224. self.__outputBuffer = ''
  225. else:
  226. if line != '':
  227. self.send_data(line)
  228.  
  229. def get_output(self):
  230. def output_callback(data):
  231. self.__outputBuffer += data
  232.  
  233. if self.__noOutput is True:
  234. self.__outputBuffer = ''
  235. return
  236.  
  237. while True:
  238. try:
  239. self.__transferClient.getFile(self.__share, self.__output, output_callback)
  240. break
  241. except Exception, e:
  242. if str(e).find('STATUS_SHARING_VIOLATION') >=0:
  243. # Output not finished, let's wait
  244. time.sleep(1)
  245. pass
  246. else:
  247. #print str(e)
  248. pass
  249. self.__transferClient.deleteFile(self.__share, self.__output)
  250.  
  251. def execute_remote(self, data):
  252. command = self.__shell + data
  253. if self.__noOutput is False:
  254. command += ' 1> ' + '\\\\127.0.0.1\\%s' % self.__share + self.__output + ' 2>&1'
  255. self.__win32Process.Create(command, self.__pwd, None)
  256. self.get_output()
  257.  
  258. def send_data(self, data):
  259. self.execute_remote(data)
  260. print self.__outputBuffer
  261. self.__outputBuffer = ''
  262.  
  263.  
  264. # Process command-line arguments.
  265. if __name__ == '__main__':
  266. # Init the example's logger theme
  267. logger.init()
  268. print version.BANNER
  269.  
  270. parser = argparse.ArgumentParser(add_help = True, description = "Executes a semi-interactive shell using Windows Management Instrumentation.")
  271. parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
  272. parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from (default ADMIN$)')
  273. parser.add_argument('-nooutput', action='store_true', default = False, help='whether or not to print the output (no SMB connection created)')
  274. parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
  275.  
  276. parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will launch a semi-interactive shell')
  277.  
  278. group = parser.add_argument_group('authentication')
  279.  
  280. group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
  281. group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
  282. group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line')
  283. group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)')
  284. group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ommited it use the domain part (FQDN) specified in the target parameter')
  285.  
  286. if len(sys.argv)==1:
  287. parser.print_help()
  288. sys.exit(1)
  289.  
  290. options = parser.parse_args()
  291.  
  292. if ' '.join(options.command) == ' ' and options.nooutput is True:
  293. logging.error("-nooutput switch and interactive shell not supported")
  294. sys.exit(1)
  295.  
  296. if options.debug is True:
  297. logging.getLogger().setLevel(logging.DEBUG)
  298. else:
  299. logging.getLogger().setLevel(logging.INFO)
  300.  
  301. import re
  302.  
  303. domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(
  304. options.target).groups('')
  305.  
  306. #In case the password contains '@'
  307. if '@' in address:
  308. password = password + '@' + address.rpartition('@')[0]
  309. address = address.rpartition('@')[2]
  310.  
  311. try:
  312. if domain is None:
  313. domain = ''
  314.  
  315. if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
  316. from getpass import getpass
  317. password = getpass("Password:")
  318.  
  319. if options.aesKey is not None:
  320. options.k = True
  321.  
  322. executer = WMIEXEC(' '.join(options.command), username, password, domain, options.hashes, options.aesKey,
  323. options.share, options.nooutput, options.k, options.dc_ip)
  324. executer.run(address)
  325. except (Exception, KeyboardInterrupt), e:
  326. #import traceback
  327. #print traceback.print_exc()
  328. logging.error(str(e))
  329. sys.exit(0)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement