[smb] Move firewall_checker to built-in function & bugs fix

Signed-off-by: XiaoliChan <2209553467@qq.com>
main
XiaoliChan 2023-08-19 21:35:55 +08:00
parent 5d8fa3c1e3
commit be5b543338
7 changed files with 63 additions and 42 deletions

View File

@ -15,6 +15,8 @@ from cme.helpers.logger import highlight
from cme.logger import cme_logger, CMEAdapter
from cme.context import Context
from impacket.dcerpc.v5 import transport
sem = BoundedSemaphore(1)
global_failed_logins = 0
user_failed_logins = {}
@ -31,7 +33,6 @@ def gethost_addrinfo(hostname):
return sa[0]
return canonname
def requires_admin(func):
def _decorator(self, *args, **kwargs):
if self.admin_privs is False:
@ -40,6 +41,31 @@ def requires_admin(func):
return wraps(func)(_decorator)
def dcom_FirewallChecker(iInterface, timeout):
stringBindings = iInterface.get_cinstance().get_string_bindings()
for strBinding in stringBindings:
if strBinding['wTowerId'] == 7:
if strBinding['aNetworkAddr'].find('[') >= 0:
binding, _, bindingPort = strBinding['aNetworkAddr'].partition('[')
bindingPort = '[' + bindingPort
else:
binding = strBinding['aNetworkAddr']
bindingPort = ''
if binding.upper().find(iInterface.get_target().upper()) >= 0:
stringBinding = 'ncacn_ip_tcp:' + strBinding['aNetworkAddr'][:-1]
break
elif iInterface.is_fqdn() and binding.upper().find(iInterface.get_target().upper().partition('.')[0]) >= 0:
stringBinding = 'ncacn_ip_tcp:%s%s' % (iInterface.get_target(), bindingPort)
try:
rpctransport = transport.DCERPCTransportFactory(stringBinding)
rpctransport.set_connect_timeout(timeout)
rpctransport.connect()
rpctransport.disconnect()
except:
return False, stringBinding
else:
return True, stringBinding
class connection(object):
def __init__(self, args, db, host):

View File

@ -690,7 +690,7 @@ class smb(connection):
self.hash,
self.args.share,
logger=self.logger,
timeout=self.args.wmiexec_timeout,
timeout=self.args.dcom_timeout,
tries=self.args.get_output_tries
)
self.logger.info("Executed command via wmiexec")
@ -711,7 +711,8 @@ class smb(connection):
self.args.share,
self.hash,
self.logger,
self.args.get_output_tries
self.args.get_output_tries,
self.args.dcom_timeout
)
self.logger.info("Executed command via mmcexec")
break

View File

@ -141,8 +141,7 @@ class TSCH_EXEC:
dce.set_credentials(*self.__rpctransport.get_credentials())
dce.connect()
# dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY)
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
dce.bind(tsch.MSRPC_UUID_TSCHS)
tmpName = gen_random_string(8)
tmpFileName = tmpName + ".tmp"
@ -152,11 +151,18 @@ class TSCH_EXEC:
taskCreated = False
self.logger.info(f"Creating task \\{tmpName}")
try:
# windows server 2003 has no MSRPC_UUID_TSCHS, if it bind, it will return abstract_syntax_not_supported
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
dce.bind(tsch.MSRPC_UUID_TSCHS)
tsch.hSchRpcRegisterTask(dce, f"\\{tmpName}", xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
except Exception as e:
self.logger.fail(str(e))
if hex(e.error_code) == "0x80070005":
self.logger.fail("ATEXEC: Create schedule task got blocked.")
else:
self.logger.fail(str(e))
return
taskCreated = True
else:
taskCreated = True
self.logger.info(f"Running task \\{tmpName}")
tsch.hSchRpcRun(dce, f"\\{tmpName}")

View File

@ -29,6 +29,7 @@
from os.path import join as path_join
from time import sleep
from cme.connection import dcom_FirewallChecker
from cme.helpers.misc import gen_random_string
from impacket.dcerpc.v5.dcom.oaut import (
@ -59,7 +60,7 @@ from impacket.dcerpc.v5.dtypes import NULL
class MMCEXEC:
def __init__(self, host, share_name, username, password, domain, smbconnection, share, hashes=None, logger=None, tries=None):
def __init__(self, host, share_name, username, password, domain, smbconnection, share, hashes=None, logger=None, tries=None, timeout=None):
self.__host = host
self.__username = username
self.__password = password
@ -78,6 +79,7 @@ class MMCEXEC:
self.__share = share
self.__dcom = None
self.__tries = tries
self.__timeout = timeout
self.logger = logger
if hashes is not None:
@ -98,6 +100,11 @@ class MMCEXEC:
)
try:
iInterface = self.__dcom.CoCreateInstanceEx(string_to_bin("49B2791A-B1AE-4C90-9B8E-E860BA07F889"), IID_IDispatch)
flag, self.__stringBinding = dcom_FirewallChecker(iInterface, self.__timeout)
if flag is False:
self.logger.fail(f'MMCEXEC: Dcom initialization failed on connection with stringbinding: "{self.__stringBinding}", please increase the timeout with the option "--dcom-timeout". If it\'s still failing maybe something is blocking the RPC connection, try another exec method')
# Make it force break function
self.__dcom.disconnect()
iMMC = IDispatch(iInterface)
resp = iMMC.GetIDsOfNames(("Document",))

View File

@ -79,7 +79,7 @@ def proto_args(parser, std_parser, module_parser):
cgroup = smb_parser.add_argument_group("Command Execution", "Options for executing commands")
cgroup.add_argument("--exec-method", choices={"wmiexec", "mmcexec", "smbexec", "atexec"}, default=None,
help="method to execute the command. Ignored if in MSSQL mode (default: wmiexec)")
cgroup.add_argument("--wmiexec-timeout", help="WMIEXEC connection timeout, default is 5 secondes", type=int, default=5)
cgroup.add_argument("--dcom-timeout", help="DCOM connection timeout, default is 5 secondes", type=int, default=5)
cgroup.add_argument("--get-output-tries", help="Number of times atexec/smbexec/mmcexec tries to get results, default is 5", type=int, default=5)
cgroup.add_argument("--codec", default="utf-8",
help="Set encoding used (codec) from the target's output (default "

View File

@ -141,18 +141,21 @@ class SMBEXEC:
except Exception as e:
if "rpc_s_access_denied" in str(e):
self.logger.fail("SMBEXEC: Create services got blocked.")
return self.__outputBuffer
else:
pass
self.logger.fail(str(e))
return self.__outputBuffer
try:
self.logger.debug(f"Remote service {self.__serviceName} started.")
scmr.hRStartServiceW(self.__scmr, service)
except:
self.logger.debug(f"Remote service {self.__serviceName} deleted.")
scmr.hRDeleteService(self.__scmr, service)
scmr.hRCloseServiceHandle(self.__scmr, service)
except Exception as e:
pass
self.logger.debug(f"Remote service {self.__serviceName} deleted.")
scmr.hRDeleteService(self.__scmr, service)
scmr.hRCloseServiceHandle(self.__scmr, service)
self.get_output_remote()
def get_output_remote(self):

View File

@ -4,6 +4,7 @@
import ntpath
import os
from time import sleep
from cme.connection import dcom_FirewallChecker
from cme.helpers.misc import gen_random_string
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.dcomrt import DCOMConnection
@ -73,39 +74,16 @@ class WMIEXEC:
kdcHost=self.__kdcHost,
)
iInterface = self.__dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
try:
self.firewall_check(iInterface, self.__timeout)
except:
self.logger.fail(f'WMIEXEC: Dcom initialization failed on connection with stringbinding: "{self.__stringBinding}", please increase the timeout with the option "--wmiexec-timeout". If it\'s still failing maybe something is blocking the RPC connection, try another exec method')
flag, self.__stringBinding = dcom_FirewallChecker(iInterface, self.__timeout)
if flag is False:
self.logger.fail(f'WMIEXEC: Dcom initialization failed on connection with stringbinding: "{self.__stringBinding}", please increase the timeout with the option "--dcom-timeout". If it\'s still failing maybe something is blocking the RPC connection, try another exec method')
# Make it force break function
self.__dcom.disconnect()
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
iWbemServices = iWbemLevel1Login.NTLMLogin("//./root/cimv2", NULL, NULL)
iWbemLevel1Login.RemRelease()
self.__win32Process, _ = iWbemServices.GetObject("Win32_Process")
def firewall_check(self, iInterface ,timeout):
stringBindings = iInterface.get_cinstance().get_string_bindings()
for strBinding in stringBindings:
if strBinding['wTowerId'] == 7:
if strBinding['aNetworkAddr'].find('[') >= 0:
binding, _, bindingPort = strBinding['aNetworkAddr'].partition('[')
bindingPort = '[' + bindingPort
else:
binding = strBinding['aNetworkAddr']
bindingPort = ''
if binding.upper().find(iInterface.get_target().upper()) >= 0:
stringBinding = 'ncacn_ip_tcp:' + strBinding['aNetworkAddr'][:-1]
break
elif iInterface.is_fqdn() and binding.upper().find(iInterface.get_target().upper().partition('.')[0]) >= 0:
stringBinding = 'ncacn_ip_tcp:%s%s' % (iInterface.get_target(), bindingPort)
self.__stringBinding = stringBinding
rpctransport = transport.DCERPCTransportFactory(stringBinding)
rpctransport.set_connect_timeout(timeout)
rpctransport.connect()
rpctransport.disconnect()
def execute(self, command, output=False):
self.__retOutput = output
if self.__retOutput: