Files
2026-04-26 14:05:44 +08:00

171 lines
8.9 KiB
Python

import logging
import uuid
import sys
from io import StringIO
from impacket.dcerpc.v5.dtypes import NULL
from lib.checkError import checkError
from lib.module_base import ModuleBase
class executeScript_Toolkit(ModuleBase):
name = "execute-script"
description = "Execute script file."
@staticmethod
def register_parser(subparsers):
p = subparsers.add_parser(executeScript_Toolkit.name, help=executeScript_Toolkit.description)
p.add_argument("-lang", action="store", help="Specify script language, support 'VBScript' and 'JScript', default is VBScript.")
p.add_argument("-script", action="store", help="VBS or JS filename containing the script you want to run")
p.add_argument("-filter", action="store", help="The WQL filter string that will trigger the script.")
p.add_argument("-timer", action="store", help="The amount of milliseconds after the script will be triggered, 1000 milliseconds = 1 second")
p.add_argument("-remove", action="store", help="Remove wmi event with specify ID.")
p.add_argument("-deep-clean", action="store_true", help="Remove all wmi events with auto enumeration.")
return p
@staticmethod
def run(iWbemLevel1Login, dcom, options, **kwargs):
toolkit = executeScript_Toolkit(iWbemLevel1Login)
script_lang = "JScript" if options.lang == "JScript" else "VBScript"
if options.script and options.filter:
toolkit.ExecuteScript(script_lang=script_lang, script_file=options.script, filer_Query=options.filter)
if options.script and options.timer:
toolkit.ExecuteScript(script_lang=script_lang, script_file=options.script, timer=options.timer)
if options.remove:
toolkit.remove_Event(options.remove)
if options.deep_clean:
toolkit.deep_RemoveEvent()
def __init__(self, iWbemLevel1Login):
self.iWbemLevel1Login = iWbemLevel1Login
self.logger = logging.getLogger("wmiexec-pro")
def ExecuteScript(self, script_lang="VBScript", script_file=None, script_content=None, filer_Query=None, timer=1000, returnTag=False, BlockVerbose=False, iWbemServices=None, return_iWbemServices=False):
if not script_content and script_file:
with open(script_file, "r") as f:
script_content = f.read()
if not iWbemServices:
iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL)
self.iWbemLevel1Login.RemRelease()
tag = f"windows-object-{str(uuid.uuid4())}"
# Copy from wmipersist.py
# Install ActiveScriptEventConsumer
activeScript, _ = iWbemServices.GetObject("ActiveScriptEventConsumer")
activeScript = activeScript.SpawnInstance()
activeScript.Name = tag
activeScript.ScriptingEngine = script_lang
activeScript.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0]
activeScript.ScriptText = script_content
# Don't output verbose
current=sys.stdout
sys.stdout = StringIO()
marshalled = activeScript.marshalMe()
sys.stdout = current
iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding ActiveScriptEventConsumer: {tag}", iWbemServices.PutInstance(marshalled))
if filer_Query:
eventFilter, _ = iWbemServices.GetObject("__EventFilter")
eventFilter = eventFilter.SpawnInstance()
eventFilter.Name = tag
eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0]
eventFilter.Query = filer_Query
eventFilter.QueryLanguage = "WQL"
eventFilter.EventNamespace = "root\\cimv2"
# Don't output verbose
current=sys.stdout
sys.stdout = StringIO()
marshalled = eventFilter.marshalMe()
sys.stdout = current
iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding EventFilter: {tag}", iWbemServices.PutInstance(marshalled))
else:
# Timer
wmiTimer, _ = iWbemServices.GetObject("__IntervalTimerInstruction")
wmiTimer = wmiTimer.SpawnInstance()
wmiTimer.TimerId = tag
wmiTimer.IntervalBetweenEvents = int(timer)
#wmiTimer.SkipIfPassed = False
# Don't output verbose
current=sys.stdout
sys.stdout = StringIO()
marshalled = wmiTimer.marshalMe()
sys.stdout = current
iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding IntervalTimerInstruction: {tag}", iWbemServices.PutInstance(marshalled))
# EventFilter
eventFilter,_ = iWbemServices.GetObject("__EventFilter")
eventFilter = eventFilter.SpawnInstance()
eventFilter.Name = tag
eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0]
eventFilter.Query = f'select * from __TimerEvent where TimerID = "{tag}"'
eventFilter.QueryLanguage = "WQL"
eventFilter.EventNamespace = "root\\subscription"
# Don't output verbose
current=sys.stdout
sys.stdout = StringIO()
marshalled = eventFilter.marshalMe()
sys.stdout = current
iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding EventFilter: {tag}", iWbemServices.PutInstance(marshalled))
# Binding EventFilter & EventConsumer
filterBinding, _ = iWbemServices.GetObject('__FilterToConsumerBinding')
filterBinding = filterBinding.SpawnInstance()
filterBinding.Filter = f'__EventFilter.Name="{tag}"'
filterBinding.Consumer = f'ActiveScriptEventConsumer.Name="{tag}"'
filterBinding.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0]
# Don't output verbose
current=sys.stdout
sys.stdout = StringIO()
marshalled = filterBinding.marshalMe()
sys.stdout = current
iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError("Adding FilterToConsumerBinding", iWbemServices.PutInstance(marshalled))
if returnTag:
if return_iWbemServices:
return tag, iWbemServices
else:
return tag
def remove_Event(self, tag, BlockVerbose=False, iWbemServices=None):
if not iWbemServices:
iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL)
self.iWbemLevel1Login.RemRelease()
if BlockVerbose:
iWbemServices.DeleteInstance(f'ActiveScriptEventConsumer.Name="{tag}"')
iWbemServices.DeleteInstance(f'__EventFilter.Name="{tag}"')
iWbemServices.DeleteInstance(f'__IntervalTimerInstruction.TimerId="{tag}"')
iWbemServices.DeleteInstance(rf'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"{tag}\"",Filter="__EventFilter.Name=\"{tag}\""')
else:
checkError('Removing ActiveScriptEventConsumer: %s' % tag, iWbemServices.DeleteInstance(f'ActiveScriptEventConsumer.Name="{tag}"'))
checkError('Removing EventFilter: %s' % tag, iWbemServices.DeleteInstance(f'__EventFilter.Name="{tag}"'))
checkError('Removing IntervalTimerInstruction: %s' % tag, iWbemServices.DeleteInstance(f'__IntervalTimerInstruction.TimerId="{tag}"'))
checkError('Removing FilterToConsumerBinding', iWbemServices.DeleteInstance(rf'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"{tag}\"",Filter="__EventFilter.Name=\"{tag}\""'))
def deep_RemoveEvent(self, iWbemServices=None):
if not iWbemServices:
iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL)
self.iWbemLevel1Login.RemRelease()
for i in ["ActiveScriptEventConsumer", "__EventFilter", "__IntervalTimerInstruction", "__FilterToConsumerBinding"]:
while True:
try:
iEnumWbemClassObject = iWbemServices.ExecQuery(f"select * from {i}")
class_ = iEnumWbemClassObject.Next(0xffffffff,1)[0]
if i == "__IntervalTimerInstruction":
checkError(f"Removing {i}: {class_.TimerId}", iWbemServices.DeleteInstance(f'{i}.Name="{class_.TimerId}"'))
elif i == "__FilterToConsumerBinding":
checkError(f"Removing {i}", iWbemServices.DeleteInstance(rf'__FilterToConsumerBinding.Consumer="{class_.Consumer.replace('"','\\"')}",Filter="{class_.Filter.replace('"','\\"')}"'))
else:
checkError(f"Removing {i}: {class_.Name}", iWbemServices.DeleteInstance(f'{i}.Name="{class_.Name}"'))
except Exception as e:
if str(e).find("S_FALSE") < 0:
pass
else:
self.logger.info(f"{i} has been cleaned!")
break