mirror of
https://github.com/SpecterOps/Nemesis
synced 2026-06-08 12:36:42 +00:00
Merge branch 'main' of github.com:SpecterOps/Nemesis into docker_compose
This commit is contained in:
+13
-4
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
Generated
+269
-43
@@ -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"
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user