mirror of
https://github.com/Pennyw0rth/NetExec.git
synced 2026-11-07 09:26:01 -10:00
Merge pull request #1494 from gzzcoo/fix/ldap-lapsv2-kerberos-rpc
This commit is contained in:
2 files changed
+23
-13
No files matched your search
+4
-1
@@ -45,12 +45,15 @@ class NXCModule:
|
||||
values = {str(attr["type"]).lower(): attr["vals"][0] for attr in computer["attributes"]}
|
||||
if "mslaps-encryptedpassword" in values:
|
||||
msMCSAdmPwd = values["mslaps-encryptedpassword"]
|
||||
d = LAPSv2Extract(bytes(msMCSAdmPwd), connection.username if connection.username else "", connection.password if connection.password else "", connection.domain, connection.nthash if connection.nthash else "", connection.kerberos, connection.kdcHost, 339, connection.dns_server)
|
||||
d = LAPSv2Extract(bytes(msMCSAdmPwd), connection.username if connection.username else "", connection.password if connection.password else "", connection.domain, connection.nthash if connection.nthash else "", connection.kerberos, connection.kdcHost, 339, connection.dns_server, connection.host, connection.remoteName, connection.aesKey)
|
||||
try:
|
||||
data = d.run()
|
||||
except Exception as e:
|
||||
context.log.fail(str(e))
|
||||
continue
|
||||
if not data:
|
||||
context.log.fail(f"Failed to decrypt msLAPS-EncryptedPassword for {values['samaccountname']}")
|
||||
continue
|
||||
r = json.loads(data)
|
||||
laps_computers.append((str(values["samaccountname"]), r["n"], str(r["p"])))
|
||||
elif "mslaps-password" in values:
|
||||
|
||||
+19
-12
@@ -7,7 +7,7 @@ from impacket.krb5.kerberosv5 import KerberosError
|
||||
from impacket.dcerpc.v5 import transport
|
||||
from impacket.dcerpc.v5.epm import hept_map
|
||||
from impacket.dcerpc.v5.gkdi import MSRPC_UUID_GKDI, GkdiGetKey, GroupKeyEnvelope
|
||||
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
||||
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
||||
from impacket.dpapi_ng import EncryptedPasswordBlob, KeyIdentifier, compute_kek, create_sd, decrypt_plaintext, unwrap_cek
|
||||
|
||||
from nxc.logger import NXCAdapter
|
||||
@@ -169,7 +169,7 @@ class LDAPConnect:
|
||||
|
||||
|
||||
class LAPSv2Extract:
|
||||
def __init__(self, data, username, password, domain, ntlm_hash, do_kerberos, kdcHost, port, dns_server):
|
||||
def __init__(self, data, username, password, domain, ntlm_hash, do_kerberos, kdcHost, port, dns_server, rpc_host=None, rpc_name=None, aesKey=""):
|
||||
if ntlm_hash.find(":") != -1:
|
||||
self.lmhash, self.nthash = ntlm_hash.split(":")
|
||||
else:
|
||||
@@ -182,8 +182,11 @@ class LAPSv2Extract:
|
||||
self.domain = domain
|
||||
self.do_kerberos = do_kerberos
|
||||
self.kdcHost = kdcHost
|
||||
self.aesKey = aesKey
|
||||
self.logger = None
|
||||
self.dns_server = dns_server
|
||||
self.rpc_host = rpc_host or (dns_server if dns_server else domain)
|
||||
self.rpc_name = rpc_name or domain
|
||||
self.proto_logger(self.domain, port, self.domain)
|
||||
|
||||
def proto_logger(self, host, port, hostname):
|
||||
@@ -215,29 +218,30 @@ class LAPSv2Extract:
|
||||
gke = kds_cache[key_id["RootKeyId"]]
|
||||
else:
|
||||
# Connect on RPC over TCP to MS-GKDI to call opnum 0 GetKey
|
||||
string_binding = hept_map(destHost=self.domain if not self.dns_server else self.dns_server, remoteIf=MSRPC_UUID_GKDI, protocol="ncacn_ip_tcp")
|
||||
string_binding = hept_map(destHost=self.rpc_host, remoteIf=MSRPC_UUID_GKDI, protocol="ncacn_ip_tcp")
|
||||
rpc_transport = transport.DCERPCTransportFactory(string_binding)
|
||||
if hasattr(rpc_transport, "set_credentials"):
|
||||
rpc_transport.set_credentials(username=self.username, password=self.password, domain=self.domain, lmhash=self.lmhash, nthash=self.nthash)
|
||||
rpc_transport.setRemoteName(self.rpc_name)
|
||||
rpc_transport.set_credentials(username=self.username, password=self.password, domain=self.domain, lmhash=self.lmhash, nthash=self.nthash, aesKey=self.aesKey)
|
||||
if self.do_kerberos:
|
||||
self.logger.info("Connecting using kerberos")
|
||||
rpc_transport.set_kerberos(self.do_kerberos, kdcHost=self.kdcHost)
|
||||
|
||||
dce = rpc_transport.get_dce_rpc()
|
||||
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||||
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
if self.do_kerberos:
|
||||
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
|
||||
self.logger.info(f"Connecting to {string_binding}")
|
||||
try:
|
||||
dce.connect()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Something went wrong, check error status => {e}")
|
||||
return False
|
||||
return None
|
||||
self.logger.info("Connected")
|
||||
try:
|
||||
dce.bind(MSRPC_UUID_GKDI)
|
||||
except Exception as e:
|
||||
self.logger.error(f"Something went wrong, check error status => {e!s}")
|
||||
return False
|
||||
return None
|
||||
self.logger.info("Successfully bound")
|
||||
self.logger.info("Calling MS-GKDI GetKey")
|
||||
|
||||
@@ -248,15 +252,12 @@ class LAPSv2Extract:
|
||||
kds_cache[gke["RootKeyId"]] = gke
|
||||
|
||||
kek = compute_kek(gke, key_id)
|
||||
self.logger.info(f"KEK:\t{kek}")
|
||||
enc_content_parameter = bytes(parsed_enveloped_data["encryptedContentInfo"]["contentEncryptionAlgorithm"]["parameters"])
|
||||
iv, _ = decoder.decode(enc_content_parameter)
|
||||
iv = bytes(iv[0])
|
||||
|
||||
cek = unwrap_cek(kek, bytes(kek_recipient_info["encryptedKey"]))
|
||||
self.logger.info(f"CEK:\t{cek}")
|
||||
plaintext = decrypt_plaintext(cek, iv, remaining)
|
||||
self.logger.info(plaintext[:-18].decode("utf-16le"))
|
||||
return plaintext[:-18].decode("utf-16le")
|
||||
|
||||
|
||||
@@ -325,13 +326,19 @@ def laps_search(self, username, password, cred_type, domain, dns_server):
|
||||
self.kerberos,
|
||||
self.kdcHost,
|
||||
339,
|
||||
dns_server
|
||||
dns_server,
|
||||
self.kdcHost,
|
||||
self.kdcHost,
|
||||
self.aesKey,
|
||||
)
|
||||
try:
|
||||
data = d.run()
|
||||
except Exception as e:
|
||||
self.logger.fail(str(e))
|
||||
return None, None, None
|
||||
if not data:
|
||||
self.logger.fail(f"Failed to decrypt msLAPS-EncryptedPassword for {self.hostname}")
|
||||
return None, None, None
|
||||
r = loads(data)
|
||||
msMCSAdmPwd = r["p"]
|
||||
username_laps = r["n"]
|
||||
|
||||
Reference in new issue
Block a user