diff --git a/compose.yaml b/compose.yaml index c976533..36aed34 100644 --- a/compose.yaml +++ b/compose.yaml @@ -718,11 +718,14 @@ services: depends_on: [jaeger] jaeger: - profiles: ["monitoring"] - image: jaegertracing/all-in-one - environment: { QUERY_BASE_PATH: /jaeger } + image: jaegertracing/jaeger:latest # v2.x image + user: "0:0" + environment: + - QUERY_BASE_PATH=/jaeger volumes: - - jaeger_data:/badger + - jaeger_data:/badger # Persist trace data + - ./infra/jaeger/jaeger-config.yaml:/etc/jaeger/config.yaml + command: ["--config", "/etc/jaeger/config.yaml"] labels: - "traefik.enable=true" - "traefik.http.routers.jaeger.rule=PathPrefix(`/jaeger`)" @@ -730,6 +733,12 @@ services: - "traefik.http.routers.jaeger.entrypoints=websecure" - "traefik.http.routers.jaeger.tls=true" - "traefik.http.routers.jaeger.middlewares=auth" + healthcheck: + test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:13133/status || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s loki: profiles: ["monitoring"] diff --git a/infra/jaeger/jaeger-config.yaml b/infra/jaeger/jaeger-config.yaml new file mode 100644 index 0000000..49fa5d9 --- /dev/null +++ b/infra/jaeger/jaeger-config.yaml @@ -0,0 +1,61 @@ +# Service configuration +service: + extensions: [jaeger_storage, jaeger_query, healthcheckv2] + pipelines: + traces: + receivers: [otlp, jaeger, zipkin] + processors: [batch] + exporters: [jaeger_storage_exporter] + +# Extensions +extensions: + healthcheckv2: + use_v2: true + http: + endpoint: "0.0.0.0:13133" + jaeger_query: + storage: + traces: badger_store + base_path: /jaeger + jaeger_storage: + backends: + badger_store: + badger: + directories: + keys: "/badger/keys" + values: "/badger/values" + ephemeral: false + consistency: true + maintenance_interval: 1m0s + +# Receivers +receivers: + otlp: + protocols: + grpc: + endpoint: "0.0.0.0:4317" + http: + endpoint: "0.0.0.0:4318" + + jaeger: + protocols: + grpc: + endpoint: "0.0.0.0:14250" + thrift_http: + endpoint: "0.0.0.0:14268" + thrift_compact: + endpoint: "0.0.0.0:6831" + thrift_binary: + endpoint: "0.0.0.0:6832" + + zipkin: + endpoint: "0.0.0.0:9411" + +# Processors +processors: + batch: + +# Exporters +exporters: + jaeger_storage_exporter: + trace_storage: badger_store \ No newline at end of file diff --git a/libs/file_enrichment_modules/file_enrichment_modules/lnk/analyzer.py b/libs/file_enrichment_modules/file_enrichment_modules/lnk/analyzer.py index c8bde7b..44dfee1 100644 --- a/libs/file_enrichment_modules/file_enrichment_modules/lnk/analyzer.py +++ b/libs/file_enrichment_modules/file_enrichment_modules/lnk/analyzer.py @@ -102,8 +102,6 @@ class LnkParser(EnrichmentModule): enrichment_result.results = convert_datetime(lnk.get_json()) - logger.info(f"lnk 3: {enrichment_result.results}") - with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as tmp_display_file: display = get_lnk_file_display(lnk) tmp_display_file.write(display) diff --git a/libs/file_enrichment_modules/file_enrichment_modules/lsass_dump/analyzer.py b/libs/file_enrichment_modules/file_enrichment_modules/lsass_dump/analyzer.py new file mode 100644 index 0000000..9711ba7 --- /dev/null +++ b/libs/file_enrichment_modules/file_enrichment_modules/lsass_dump/analyzer.py @@ -0,0 +1,479 @@ +# enrichment_modules/lsass_dump/analyzer.py +import tempfile +import textwrap +from pathlib import Path +from datetime import datetime +import structlog +from common.models import EnrichmentResult, Transform, Finding, FindingCategory, FindingOrigin, FileObject +from common.state_helpers import get_file_enriched +from common.storage import StorageMinio +from file_enrichment_modules.module_loader import EnrichmentModule + +from pypykatz.pypykatz import pypykatz + +logger = structlog.get_logger(module=__name__) + + +class Credential: + """Simple credential class to match the original structure""" + def __init__(self, hostname=None, ssp=None, domain=None, username=None, + password=None, lmhash=None, nthash=None, sha1=None, + masterkey=None, ticket=None): + self.hostname = hostname + self.ssp = ssp + self.domain = domain + self.username = username + self.password = password + self.lmhash = lmhash + self.nthash = nthash + self.sha1 = sha1 + self.masterkey = masterkey + self.ticket = ticket + +# adapted from/inspired by https://github.com/login-securite/lsassy/blob/9682127364f6f64ce190e8b7f03cdfa1dd457066/lsassy/parser.py (MIT License) +class LsassDumpParser(EnrichmentModule): + def __init__(self): + super().__init__("lsass_dump") + self.storage = StorageMinio() + # the workflows this module should automatically run in + self.workflows = ["default"] + + def should_process(self, object_id: str) -> bool: + """Determine if this module should run based on file type.""" + file_enriched = get_file_enriched(object_id) + should_run = "mini dump crash report" in file_enriched.magic_type.lower() + logger.debug( + f"LsassDumpParser should_run: {should_run}, file_name: {file_enriched.file_name}" + ) + return should_run + + def _convert_bytes_to_string(self, value): + """Convert bytes objects and datetime objects to strings for JSON serialization""" + if isinstance(value, bytes): + return value.decode('utf-8', errors='replace') + elif isinstance(value, datetime): + return str(value) + elif hasattr(value, 'strftime'): # Handle other datetime-like objects + return str(value) + elif isinstance(value, dict): + return {k: self._convert_bytes_to_string(v) for k, v in value.items()} + elif isinstance(value, list): + return [self._convert_bytes_to_string(item) for item in value] + else: + return value + + def _parse_lsass_dump(self, dump_file_path: str, target_hostname: str = "unknown") -> tuple[list, list, list, list]: + """ + Parse LSASS dump file using pypykatz + :param dump_file_path: Path to the dump file + :param target_hostname: Target hostname for credential tracking + :return: Tuple of (logon_sessions, credentials, tickets, masterkeys) + """ + logon_sessions = [] + credentials = [] + tickets = [] + masterkeys = [] + + try: + pypy_parse = pypykatz.parse_minidump_file(dump_file_path) + except Exception as e: + logger.error(f"An error occurred while parsing lsass dump: {e}", exc_info=True) + return None, None, None, None + + ssps = [ + "msv_creds", + "wdigest_creds", + "ssp_creds", + "livessp_creds", + "kerberos_creds", + "credman_creds", + "tspkg_creds", + "dpapi_creds", + ] + + for luid in pypy_parse.logon_sessions: + session = pypy_parse.logon_sessions[luid] + + # Extract session metadata + session_data = { + 'authentication_id': getattr(session, 'authentication_id', luid), + 'session_id': getattr(session, 'session_id', None), + 'username': getattr(session, 'username', None), + 'domainname': getattr(session, 'domainname', None), + 'logon_server': getattr(session, 'logon_server', None), + 'logon_time': getattr(session, 'logon_time', None), + 'sid': getattr(session, 'sid', None), + 'luid': luid, + 'credentials_by_ssp': {} + } + + # Convert logon_time to string if it exists + if session_data['logon_time']: + session_data['logon_time'] = str(session_data['logon_time']) + if session_data['sid']: + session_data['sid'] = str(session_data['sid']) + + # Process each SSP type for session data AND create original credentials + for ssp in ssps: + ssp_creds = [] + creds = getattr(session, ssp, []) + + for cred in creds: + cred_data = {} + + # Common fields + if hasattr(cred, 'username'): + cred_data['username'] = cred.username + if hasattr(cred, 'domainname'): + cred_data['domainname'] = cred.domainname + if hasattr(cred, 'password'): + cred_data['password'] = cred.password + if hasattr(cred, 'credtype'): + cred_data['credtype'] = cred.credtype + if hasattr(cred, 'luid'): + cred_data['luid'] = cred.luid + + # Extract credential info for original credential objects (for ALL SSP types) + domain = getattr(cred, "domainname", None) + username = getattr(cred, "username", None) + password = getattr(cred, "password", None) + LMHash = getattr(cred, "LMHash", None) + NThash = getattr(cred, "NThash", None) + SHA1 = getattr(cred, "SHAHash", None) + + if LMHash is not None: + LMHash = LMHash.hex() if hasattr(LMHash, 'hex') else str(LMHash) + if NThash is not None: + NThash = NThash.hex() if hasattr(NThash, 'hex') else str(NThash) + if SHA1 is not None: + SHA1 = SHA1.hex() if hasattr(SHA1, 'hex') else str(SHA1) + + # Create credential object for all SSP types that have valid credentials + if username and ( + password + or (NThash and NThash != "00000000000000000000000000000000") + or (LMHash and LMHash != "00000000000000000000000000000000") + ): + credentials.append( + Credential( + hostname=target_hostname, + ssp=ssp, + domain=domain, + username=username, + password=password, + lmhash=LMHash, + nthash=NThash, + sha1=SHA1, + ) + ) + + # MSV specific fields for session data + if ssp == "msv_creds": + if hasattr(cred, 'LMHash') and cred.LMHash: + cred_data['LMHash'] = cred.LMHash.hex() if hasattr(cred.LMHash, 'hex') else str(cred.LMHash) + if hasattr(cred, 'NThash') and cred.NThash: + cred_data['NThash'] = cred.NThash.hex() if hasattr(cred.NThash, 'hex') else str(cred.NThash) + if hasattr(cred, 'SHAHash') and cred.SHAHash: + cred_data['SHAHash'] = cred.SHAHash.hex() if hasattr(cred.SHAHash, 'hex') else str(cred.SHAHash) + if hasattr(cred, 'DPAPI') and cred.DPAPI: + cred_data['DPAPI'] = cred.DPAPI.hex() if hasattr(cred.DPAPI, 'hex') else str(cred.DPAPI) + + # Kerberos specific fields + elif ssp == "kerberos_creds": + ticket_list = [] + if hasattr(cred, 'tickets'): + for ticket in cred.tickets: + tickets.append(ticket) + # Add ticket info to the session data + ticket_info = { + 'service_name': getattr(ticket, 'ServiceName', [None])[0] if hasattr(ticket, 'ServiceName') and ticket.ServiceName else None, + 'client_name': getattr(ticket, 'EClientName', [None])[0] if hasattr(ticket, 'EClientName') and ticket.EClientName else None, + 'domain_name': getattr(ticket, 'DomainName', None), + 'end_time': str(getattr(ticket, 'EndTime', None)) if hasattr(ticket, 'EndTime') else None + } + ticket_list.append(ticket_info) + cred_data['tickets'] = ticket_list + else: + cred_data['tickets'] = [] + if hasattr(cred, 'aes128') and cred.aes128: + cred_data['aes128'] = cred.aes128.hex() if hasattr(cred.aes128, 'hex') else str(cred.aes128) + if hasattr(cred, 'aes256') and cred.aes256: + cred_data['aes256'] = cred.aes256.hex() if hasattr(cred.aes256, 'hex') else str(cred.aes256) + + # DPAPI specific fields + elif ssp == "dpapi_creds": + if hasattr(cred, 'key_guid'): + cred_data['key_guid'] = str(cred.key_guid) + if hasattr(cred, 'masterkey') and cred.masterkey: + cred_data['masterkey'] = cred.masterkey.hex() if hasattr(cred.masterkey, 'hex') else str(cred.masterkey) + if hasattr(cred, 'sha1_masterkey') and cred.sha1_masterkey: + sha1_hex = cred.sha1_masterkey.hex() if hasattr(cred.sha1_masterkey, 'hex') else str(cred.sha1_masterkey) + cred_data['sha1_masterkey'] = sha1_hex + + # Add to masterkeys list + m = "{%s}:%s" % (cred.key_guid, sha1_hex) + if m not in masterkeys: + masterkeys.append(m) + credentials.append( + Credential( + hostname=target_hostname, + ssp="dpapi", + domain="", + username="", + masterkey=m, + ) + ) + + # WDIGEST specific fields + elif ssp == "wdigest_creds": + if hasattr(cred, 'password_raw'): + # Convert bytes to string for JSON serialization + if isinstance(cred.password_raw, bytes): + cred_data['password_raw'] = cred.password_raw.decode('utf-8', errors='replace') + else: + cred_data['password_raw'] = str(cred.password_raw) if cred.password_raw is not None else "" + + if cred_data: # Only add if we have some data + # Convert any bytes objects to strings for JSON serialization + cred_data = self._convert_bytes_to_string(cred_data) + ssp_creds.append(cred_data) + + if ssp_creds: # Only add SSP if it has credentials + session_data['credentials_by_ssp'][ssp] = ssp_creds + + # Clean session data of any remaining bytes objects + session_data = self._convert_bytes_to_string(session_data) + logon_sessions.append(session_data) + + # Process orphaned credentials + for cred in pypy_parse.orphaned_creds: + if cred.credtype == "kerberos": + for ticket in cred.tickets: + tickets.append(ticket) + + # Process tickets for TGT detection + for ticket in tickets: + if ticket.ServiceName is not None and ticket.ServiceName[0] == "krbtgt": + if ticket.EClientName is not None and ticket.DomainName is not None: + if ( + ticket.TargetDomainName is not None + and ticket.TargetDomainName != ticket.DomainName + ): + target_domain = ticket.TargetDomainName + else: + target_domain = ticket.DomainName + # Keep only valid tickets + if ticket.EndTime > datetime.now(ticket.EndTime.tzinfo): + credentials.append( + Credential( + hostname=target_hostname, + ssp="kerberos", + domain=ticket.DomainName, + username=ticket.EClientName[0], + ticket={ + "file": list(ticket.kirbi_data)[0].split(".kirbi")[0] + + "_" + + ticket.EndTime.strftime("%Y%m%d%H%M%S") + + ".kirbi", + "domain": target_domain, + "endtime": str(ticket.EndTime), # Convert datetime to string + }, + ) + ) + + return logon_sessions, credentials, tickets, masterkeys + + def _create_finding_summary(self, logon_sessions: list, credentials: list, tickets: list, masterkeys: list) -> str: + """Creates a markdown summary for the LSASS dump findings.""" + summary = "# LSASS Dump Analysis Results\n\n" + + # Summary statistics + summary += f"**Total Logon Sessions**: {len(logon_sessions)}\n" + summary += f"**Total Credentials Found**: {len(credentials)}\n" + summary += f"**Total Tickets Found**: {len(tickets)}\n" + summary += f"**Total DPAPI Masterkeys**: {len(masterkeys)}\n\n" + + # Process each logon session + for i, session in enumerate(logon_sessions, 1): + summary += f"## Logon Session {i}\n\n" + + # Session metadata + summary += f"* **Authentication ID**: `{session.get('authentication_id', 'N/A')}`\n" + summary += f"* **Session ID**: `{session.get('session_id', 'N/A')}`\n" + summary += f"* **Username**: `{session.get('username', 'N/A')}`\n" + summary += f"* **Domain**: `{session.get('domainname', 'N/A')}`\n" + summary += f"* **Logon Server**: `{session.get('logon_server', 'N/A')}`\n" + summary += f"* **Logon Time**: `{session.get('logon_time', 'N/A')}`\n" + summary += f"* **SID**: `{session.get('sid', 'N/A')}`\n" + summary += f"* **LUID**: `{session.get('luid', 'N/A')}`\n\n" + + # Credentials by SSP + creds_by_ssp = session.get('credentials_by_ssp', {}) + if creds_by_ssp: + for ssp, creds in creds_by_ssp.items(): + if creds: + summary += f"### {ssp.upper().replace('_', ' ')}\n\n" + + for j, cred in enumerate(creds, 1): + summary += f"**Credential {j}:**\n" + + for key, value in cred.items(): + if value is not None and value != "": + if key in ['NThash', 'LMHash', 'SHAHash', 'DPAPI', 'aes128', 'aes256', 'masterkey', 'sha1_masterkey']: + summary += f"* **{key}**: `{value}`\n" + elif key == 'tickets' and isinstance(value, list) and value: + summary += f"* **Tickets**: {len(value)} found\n" + for i, ticket in enumerate(value, 1): + summary += f" * **Ticket {i}**: Service=`{ticket.get('service_name', 'N/A')}`, Client=`{ticket.get('client_name', 'N/A')}`, Domain=`{ticket.get('domain_name', 'N/A')}`, EndTime=`{ticket.get('end_time', 'N/A')}`\n" + else: + summary += f"* **{key.title()}**: `{value}`\n" + summary += "\n" + else: + summary += "*No credentials found for this session.*\n\n" + + summary += "---\n\n" + + return summary + + def process(self, object_id: str) -> EnrichmentResult | None: + """Process LSASS dump file and extract credentials.""" + try: + file_enriched = get_file_enriched(object_id) + enrichment_result = EnrichmentResult( + module_name=self.name, + dependencies=self.dependencies + ) + + # Download the file to a temporary location + with self.storage.download(file_enriched.object_id) as temp_file: + # Parse the LSASS dump + logon_sessions, credentials, tickets, masterkeys = self._parse_lsass_dump( + temp_file.name, + file_enriched.file_name + ) + + if logon_sessions is None: + logger.error("Failed to parse LSASS dump file") + return None + + if logon_sessions or credentials or tickets or masterkeys: + # Create finding summary + summary_markdown = self._create_finding_summary(logon_sessions, credentials, tickets, masterkeys) + + # Prepare credentials data for serialization (convert objects to dicts) + credentials_data = [] + for cred in credentials: + cred_dict = { + 'hostname': cred.hostname, + 'ssp': cred.ssp, + 'domain': cred.domain, + 'username': cred.username, + 'password': cred.password, + 'lmhash': cred.lmhash, + 'nthash': cred.nthash, + 'sha1': cred.sha1, + 'masterkey': cred.masterkey, + 'ticket': cred.ticket + } + credentials_data.append(cred_dict) + + # Create display data + display_data = FileObject( + type="finding_summary", + metadata={ + "summary": summary_markdown + } + ) + + # Create finding + finding = Finding( + category=FindingCategory.CREDENTIAL, + finding_name="lsass_credentials_detected", + origin_type=FindingOrigin.ENRICHMENT_MODULE, + origin_name=self.name, + object_id=file_enriched.object_id, + severity=9, # High severity for credential extraction + raw_data={ + "logon_sessions": logon_sessions, + "credentials": credentials_data, + "ticket_count": len(tickets), + "masterkey_count": len(masterkeys) + }, + data=[display_data] + ) + + # Add finding to enrichment result + enrichment_result.findings = [finding] + enrichment_result.results = { + "logon_sessions": logon_sessions, + "credentials": credentials_data, + "ticket_count": len(tickets), + "masterkey_count": len(masterkeys) + } + + # Create a displayable version of the results + with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8') as tmp_display_file: + yaml_output = [] + yaml_output.append("LSASS Dump Analysis Results") + yaml_output.append("===========================\n") + + yaml_output.append(f"Total Logon Sessions: {len(logon_sessions)}") + yaml_output.append(f"Total Credentials: {len(credentials)}") + yaml_output.append(f"Total Tickets: {len(tickets)}") + yaml_output.append(f"Total Masterkeys: {len(masterkeys)}\n") + + for i, session in enumerate(logon_sessions, 1): + yaml_output.append(f"Logon Session {i}:") + yaml_output.append(f" Authentication ID: {session.get('authentication_id', 'N/A')}") + yaml_output.append(f" Username: {session.get('username', 'N/A')}") + yaml_output.append(f" Domain: {session.get('domainname', 'N/A')}") + yaml_output.append(f" Logon Server: {session.get('logon_server', 'N/A')}") + yaml_output.append(f" Logon Time: {session.get('logon_time', 'N/A')}") + yaml_output.append(f" SID: {session.get('sid', 'N/A')}") + yaml_output.append(f" LUID: {session.get('luid', 'N/A')}") + + creds_by_ssp = session.get('credentials_by_ssp', {}) + if creds_by_ssp: + for ssp, creds in creds_by_ssp.items(): + yaml_output.append(f" {ssp.upper()}:") + for j, cred in enumerate(creds, 1): + yaml_output.append(f" Credential {j}:") + for key, value in cred.items(): + if value is not None and value != "": + if key == 'tickets' and isinstance(value, list) and value: + yaml_output.append(f" {key}: {len(value)} tickets found") + for k, ticket in enumerate(value, 1): + yaml_output.append(f" Ticket {k}: Service={ticket.get('service_name', 'N/A')}, Client={ticket.get('client_name', 'N/A')}, Domain={ticket.get('domain_name', 'N/A')}, EndTime={ticket.get('end_time', 'N/A')}") + else: + yaml_output.append(f" {key}: {value}") + yaml_output.append("") # Add empty line between sessions + + display = textwrap.indent( + "\n".join(yaml_output), + " " + ) + tmp_display_file.write(display) + tmp_display_file.flush() + + object_id = self.storage.upload_file(tmp_display_file.name) + + displayable_parsed = Transform( + type="displayable_parsed", + object_id=f"{object_id}", + metadata={ + "file_name": f"{file_enriched.file_name}_lsass_analysis.txt", + "display_type_in_dashboard": "monaco", + "default_display": True + }, + ) + enrichment_result.transforms = [displayable_parsed] + + return enrichment_result + + except Exception as e: + logger.exception(e, message="Error processing LSASS dump file") + return None + + +def create_enrichment_module() -> EnrichmentModule: + return LsassDumpParser() \ No newline at end of file diff --git a/projects/file_enrichment/poetry.lock b/projects/file_enrichment/poetry.lock index 58245c0..5e89a86 100644 --- a/projects/file_enrichment/poetry.lock +++ b/projects/file_enrichment/poetry.lock @@ -1,5 +1,22 @@ # This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +[[package]] +name = "aesedb" +version = "0.1.6" +description = "NTDS parser toolkit" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "aesedb-0.1.6-py3-none-any.whl", hash = "sha256:9dad54792b7d792715fd95379516b27e3a31de318199ba7cff51e5d0c8739228"}, +] + +[package.dependencies] +aiowinreg = ">=0.0.7" +colorama = "*" +tqdm = "*" +unicrypto = ">=0.0.9" + [[package]] name = "aiohappyeyeballs" version = "2.6.1" @@ -135,6 +152,46 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "aiosmb" +version = "0.4.11" +description = "Asynchronous SMB protocol implementation" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "aiosmb-0.4.11-py3-none-any.whl", hash = "sha256:a3b84893cded7aa1ebf048c0f5267024f2c030e5d918e4d8d8b86f8974a4011a"}, + {file = "aiosmb-0.4.11.tar.gz", hash = "sha256:6d66f51ed2354f76f206613eac0d63f37cfd9ed44be9f8a06594d410244273d7"}, +] + +[package.dependencies] +asn1crypto = "*" +asyauth = ">=0.0.16" +asysocks = ">=0.2.9" +colorama = "*" +cryptography = "*" +prompt-toolkit = ">=3.0.2" +six = "*" +tqdm = "*" +unicrypto = ">=0.0.10" +wcwidth = "*" +winacl = ">=0.1.8" + +[[package]] +name = "aiowinreg" +version = "0.0.12" +description = "Windows registry file reader" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "aiowinreg-0.0.12-py3-none-any.whl", hash = "sha256:a67be904045d8ecb4798fa691dd7688b20a6e47a524d093528f7e77d9eaf00e9"}, +] + +[package.dependencies] +prompt-toolkit = ">=3.0.2" +winacl = ">=0.1.7" + [[package]] name = "annotated-types" version = "0.7.0" @@ -237,6 +294,36 @@ files = [ [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] +[[package]] +name = "asn1crypto" +version = "1.5.1" +description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, + {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, +] + +[[package]] +name = "asyauth" +version = "0.0.21" +description = "Unified authentication library" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "asyauth-0.0.21-py3-none-any.whl", hash = "sha256:1098ced8f4dfda74db535bc961e7667714154a440761821e26c8b637c95a2775"}, + {file = "asyauth-0.0.21.tar.gz", hash = "sha256:34cc10c5f8628ff2e25b5116dc98efc5ca45532f163ccd3f9147a3e02dd810eb"}, +] + +[package.dependencies] +asn1crypto = ">=1.3.0" +asysocks = ">=0.2.11" +minikerberos = ">=0.4.4" +unicrypto = ">=0.0.10" + [[package]] name = "asyncpg" version = "0.30.0" @@ -301,6 +388,23 @@ docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"] gssauth = ["gssapi", "sspilib"] test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi", "k5test", "mypy (>=1.8.0,<1.9.0)", "sspilib", "uvloop (>=0.15.3)"] +[[package]] +name = "asysocks" +version = "0.2.13" +description = "" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "asysocks-0.2.13-py3-none-any.whl", hash = "sha256:e32f478eac58566162d3e5af02ed6b6625317d9ddf83af22109bd13a24ef721a"}, + {file = "asysocks-0.2.13.tar.gz", hash = "sha256:44185b2c471e63b7293173967eef3b0f5e60ed5cc1b7650a30a9569e49ff25f8"}, +] + +[package.dependencies] +asn1crypto = "*" +cryptography = "*" +h11 = ">=0.14.0" + [[package]] name = "attrs" version = "25.3.0" @@ -852,10 +956,6 @@ files = [ {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d"}, {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0"}, {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e"}, - {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c"}, - {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1"}, - {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2"}, - {file = "Brotli-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec"}, {file = "Brotli-1.1.0-cp310-cp310-win32.whl", hash = "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2"}, {file = "Brotli-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128"}, {file = "Brotli-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc"}, @@ -868,14 +968,8 @@ files = [ {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9"}, {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265"}, {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8"}, - {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f"}, - {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757"}, - {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0"}, - {file = "Brotli-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b"}, {file = "Brotli-1.1.0-cp311-cp311-win32.whl", hash = "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50"}, {file = "Brotli-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1"}, - {file = "Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28"}, - {file = "Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f"}, {file = "Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409"}, {file = "Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2"}, {file = "Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451"}, @@ -886,24 +980,8 @@ files = [ {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180"}, {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248"}, {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966"}, - {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9"}, - {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb"}, - {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111"}, - {file = "Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839"}, {file = "Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0"}, {file = "Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951"}, - {file = "Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5"}, - {file = "Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8"}, - {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f"}, - {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648"}, - {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0"}, - {file = "Brotli-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089"}, - {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368"}, - {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c"}, - {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284"}, - {file = "Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7"}, - {file = "Brotli-1.1.0-cp313-cp313-win32.whl", hash = "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0"}, - {file = "Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b"}, {file = "Brotli-1.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1"}, {file = "Brotli-1.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d"}, {file = "Brotli-1.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b"}, @@ -913,10 +991,6 @@ files = [ {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2"}, {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354"}, {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2"}, - {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75"}, - {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c"}, - {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2"}, - {file = "Brotli-1.1.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52"}, {file = "Brotli-1.1.0-cp36-cp36m-win32.whl", hash = "sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460"}, {file = "Brotli-1.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579"}, {file = "Brotli-1.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c"}, @@ -928,10 +1002,6 @@ files = [ {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74"}, {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b"}, {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438"}, - {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01"}, - {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547"}, - {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38"}, - {file = "Brotli-1.1.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c"}, {file = "Brotli-1.1.0-cp37-cp37m-win32.whl", hash = "sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95"}, {file = "Brotli-1.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68"}, {file = "Brotli-1.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3"}, @@ -944,10 +1014,6 @@ files = [ {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a"}, {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:141bd4d93984070e097521ed07e2575b46f817d08f9fa42b16b9b5f27b5ac088"}, {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596"}, - {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7"}, - {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5"}, - {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943"}, - {file = "Brotli-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a"}, {file = "Brotli-1.1.0-cp38-cp38-win32.whl", hash = "sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b"}, {file = "Brotli-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0"}, {file = "Brotli-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a"}, @@ -960,10 +1026,6 @@ files = [ {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c"}, {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d"}, {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59"}, - {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419"}, - {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2"}, - {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f"}, - {file = "Brotli-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb"}, {file = "Brotli-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64"}, {file = "Brotli-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467"}, {file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"}, @@ -2575,6 +2637,38 @@ files = [ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] +[[package]] +name = "minidump" +version = "0.0.24" +description = "Python library to parse Windows minidump file format" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "minidump-0.0.24-py3-none-any.whl", hash = "sha256:9c016e35c8fe37c82a01b0a266f5416a0b0138934d92affb436ac2e72372bec6"}, + {file = "minidump-0.0.24.tar.gz", hash = "sha256:f7ae09b944f3b17ccf5cecc66f9ff5a7a45b053474a13aeb012f4c9204470437"}, +] + +[[package]] +name = "minikerberos" +version = "0.4.6" +description = "Kerberos manipulation library in pure Python" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "minikerberos-0.4.6-py3-none-any.whl", hash = "sha256:9bb7160e0ccbf742746f9777c54311187113ce813d2cc75d470e37602a908a12"}, + {file = "minikerberos-0.4.6.tar.gz", hash = "sha256:56fd389e06197043b7d89eee713e9a5f2bb546020db6a064e1921d740f957290"}, +] + +[package.dependencies] +asn1crypto = ">=1.5.1" +asysocks = ">=0.2.8" +oscrypto = ">=1.3.0" +six = "*" +tqdm = "*" +unicrypto = ">=0.0.10" + [[package]] name = "minio" version = "7.2.15" @@ -2594,6 +2688,29 @@ pycryptodome = "*" typing-extensions = "*" urllib3 = "*" +[[package]] +name = "msldap" +version = "0.5.15" +description = "Python library to play with MS LDAP" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "msldap-0.5.15-py3-none-any.whl", hash = "sha256:ee4224cf3964c386a52424a4b6d763a866b4d7ae6d5597a0af58611588668531"}, + {file = "msldap-0.5.15.tar.gz", hash = "sha256:b8024a2c0559158ec407cb6317201ecc83627248baaeecee5dfd4419ca773e3d"}, +] + +[package.dependencies] +asn1crypto = ">=1.3.0" +asyauth = ">=0.0.18" +asysocks = ">=0.2.11" +prompt-toolkit = ">=3.0.2" +tabulate = "*" +tqdm = "*" +unicrypto = ">=0.0.10" +wcwidth = "*" +winacl = ">=0.1.8" + [[package]] name = "msoffcrypto-tool" version = "5.4.2" @@ -3070,6 +3187,21 @@ files = [ {file = "opentelemetry_util_http-0.51b0.tar.gz", hash = "sha256:05edd19ca1cc3be3968b1e502fd94816901a365adbeaab6b6ddb974384d3a0b9"}, ] +[[package]] +name = "oscrypto" +version = "1.3.0" +description = "TLS (SSL) sockets, key generation, encryption, decryption, signing, verification and KDFs using the OS crypto libraries. Does not require a compiler, and relies on the OS for patching. Works on Windows, OS X and Linux/BSD." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "oscrypto-1.3.0-py2.py3-none-any.whl", hash = "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085"}, + {file = "oscrypto-1.3.0.tar.gz", hash = "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4"}, +] + +[package.dependencies] +asn1crypto = ">=1.5.1" + [[package]] name = "packaging" version = "25.0" @@ -3220,6 +3352,21 @@ files = [ [package.extras] tests = ["coverage", "pycodestyle", "pydocstyle", "pyflakes"] +[[package]] +name = "prompt-toolkit" +version = "3.0.51" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, + {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, +] + +[package.dependencies] +wcwidth = "*" + [[package]] name = "propcache" version = "0.3.2" @@ -3980,6 +4127,29 @@ docs = ["sphinx", "sphinx_rtd_theme"] fuzzer = ["atheris", "hypothesis"] test = ["coverage[toml] (>=5.2)", "hypothesis", "pytest (>=6.0)", "pytest-benchmark", "pytest-cov", "pytest-timeout"] +[[package]] +name = "pypykatz" +version = "0.6.11" +description = "Python implementation of Mimikatz" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "pypykatz-0.6.11-py3-none-any.whl", hash = "sha256:212e577e4333c6ce326118cc62bd1cc4fe515c05f97e260664616d758b754f3a"}, + {file = "pypykatz-0.6.11.tar.gz", hash = "sha256:c8dc3fa3443dec76fc48d9803d7ebf29f4f5fd8ad04682592765d0870f704518"}, +] + +[package.dependencies] +aesedb = ">=0.1.4,<=0.2.0" +aiosmb = ">=0.4.8,<=0.5.0" +aiowinreg = ">=0.0.11,<=0.1.0" +minidump = ">=0.0.21,<=0.1.0" +minikerberos = ">=0.4.1,<=0.5.0" +msldap = ">=0.5.7,<=0.6.0" +tqdm = "*" +unicrypto = ">=0.0.10,<=0.1.0" +winacl = ">=0.1.9,<=0.2.0" + [[package]] name = "pyreadline3" version = "3.5.4" @@ -4732,6 +4902,21 @@ files = [ {file = "structlog-25.4.0.tar.gz", hash = "sha256:186cd1b0a8ae762e29417095664adf1d6a31702160a46dacb7796ea82f7409e4"}, ] +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + [[package]] name = "texttable" version = "1.7.0" @@ -4910,6 +5095,20 @@ files = [ {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, ] +[[package]] +name = "unicrypto" +version = "0.0.10" +description = "Unified interface for cryptographic libraries" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "unicrypto-0.0.10-py3-none-any.whl", hash = "sha256:77322c68cb6a7ef8ee762dcb0a824a491429f8939793e8a9d64f615baaf595b9"}, +] + +[package.dependencies] +pycryptodomex = "*" + [[package]] name = "urllib3" version = "2.4.0" @@ -4947,6 +5146,18 @@ h11 = ">=0.8" [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [[package]] name = "werkzeug" version = "3.1.3" @@ -4993,6 +5204,21 @@ files = [ [package.extras] dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] +[[package]] +name = "winacl" +version = "0.1.9" +description = "ACL/ACE/Security Descriptor manipulation library in pure Python" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "winacl-0.1.9-py3-none-any.whl", hash = "sha256:31ba781a35f3b1bd3c2ece994816c0a5fe113c73018689ab6118010ac0d15099"}, + {file = "winacl-0.1.9.tar.gz", hash = "sha256:af70c2ec30178bf9e3c8a1c48c25e8781235fe2c1b321adb46e2f2ae1f8d4aab"}, +] + +[package.dependencies] +cryptography = ">=38.0.1" + [[package]] name = "wrapt" version = "1.17.2" @@ -5256,4 +5482,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "53080891854c995202f164a59212643fe1b748a7fa8da3dfe64f29b013dd1e04" +content-hash = "3ebf19a118a8cfdf86f87b676e064b22892c92f010cb3ff36a9e2df706c0bda6" diff --git a/projects/file_enrichment/pyproject.toml b/projects/file_enrichment/pyproject.toml index 26b6d36..147afe8 100644 --- a/projects/file_enrichment/pyproject.toml +++ b/projects/file_enrichment/pyproject.toml @@ -38,6 +38,7 @@ pyarrow = "^19.0.1" impacket = "^0.12.0" msoffcrypto-tool = "^5.4.2" oletools = "^0.60.2" +pypykatz = "^0.6.11" [tool.poetry.group.dev.dependencies]