mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
Merge remote-tracking branch 'upstream/master' into wmi
This commit is contained in:
+27
-1
@@ -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):
|
||||
|
||||
+29
-1
@@ -518,8 +518,36 @@ conf = {
|
||||
{
|
||||
"name": "exploitProtectionIPC",
|
||||
"processes": ["AVKWCtlx64.exe"],
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Panda Adaptive Defense 360",
|
||||
"services": [
|
||||
{
|
||||
"name": "PandaAetherAgent",
|
||||
"description": "Panda Endpoint Agent",
|
||||
},
|
||||
{
|
||||
"name": "PSUAService",
|
||||
"description": "Panda Product Service"
|
||||
},
|
||||
{
|
||||
"name": "NanoServiceMain",
|
||||
"description": "Panda Cloud Antivirus Service",
|
||||
},
|
||||
],
|
||||
"pipes": [
|
||||
{
|
||||
"name": "NNS_API_IPC_SRV_ENDPOINT",
|
||||
"processes": ["PSANHost.exe"],
|
||||
},
|
||||
{
|
||||
"name": "PSANMSrvcPpal",
|
||||
"processes": ["PSUAService.exe"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
@@ -28,11 +28,12 @@ class CMEModule:
|
||||
def on_admin_login(self, context, connection):
|
||||
data = []
|
||||
cards = connection.wmi(f"select DNSDomainSuffixSearchOrder, IPAddress from win32_networkadapterconfiguration")
|
||||
for c in cards:
|
||||
if c["IPAddress"].get("value"):
|
||||
context.log.success(f"IP Address: {c['IPAddress']['value']}\tSearch Domain: {c['DNSDomainSuffixSearchOrder']['value']}")
|
||||
if cards:
|
||||
for c in cards:
|
||||
if c["IPAddress"].get("value"):
|
||||
context.log.success(f"IP Address: {c['IPAddress']['value']}\tSearch Domain: {c['DNSDomainSuffixSearchOrder']['value']}")
|
||||
|
||||
data.append(cards)
|
||||
data.append(cards)
|
||||
|
||||
log_name = "network-connections-{}-{}.log".format(connection.args.target[0], datetime.now().strftime("%Y-%m-%d_%H%M%S"))
|
||||
write_log(json.dumps(data), log_name)
|
||||
|
||||
+254
-22
@@ -3,14 +3,21 @@
|
||||
|
||||
from sys import exit
|
||||
|
||||
from cme.connection import dcom_FirewallChecker
|
||||
|
||||
from impacket.dcerpc.v5 import rrp
|
||||
from impacket.examples.secretsdump import RemoteOperations
|
||||
from impacket.dcerpc.v5.dcomrt import DCOMConnection
|
||||
from impacket.dcerpc.v5.dcom import wmi
|
||||
from impacket.dcerpc.v5.dtypes import NULL
|
||||
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
||||
|
||||
|
||||
class CMEModule:
|
||||
name = "rdp"
|
||||
description = "Enables/Disables RDP"
|
||||
supported_protocols = ["smb"]
|
||||
#supported_protocols = ["smb"]
|
||||
supported_protocols = ["smb" ,"wmi"]
|
||||
opsec_safe = True
|
||||
multiple_hosts = True
|
||||
|
||||
@@ -21,26 +28,99 @@ class CMEModule:
|
||||
|
||||
def options(self, context, module_options):
|
||||
"""
|
||||
ACTION Enable/Disable RDP (choices: enable, disable)
|
||||
ACTION Enable/Disable RDP (choices: enable, disable, enable-ram, disable-ram)
|
||||
METHOD wmi(ncacn_ip_tcp)/smb(ncacn_np) (choices: wmi, smb, default is wmi)
|
||||
OLD For old version system (under NT6, like: server 2003)
|
||||
DCOM-TIMEOUT Set the Dcom connection timeout for WMI method (Default is 10 seconds)
|
||||
cme smb 192.168.1.1 -u {user} -p {password} -M rdp -o ACTION={enable, disable, enable-ram, disable-ram} {OLD=true} {DCOM-TIMEOUT=5}
|
||||
cme smb 192.168.1.1 -u {user} -p {password} -M rdp -o METHOD=smb ACTION={enable, disable, enable-ram, disable-ram}
|
||||
cme smb 192.168.1.1 -u {user} -p {password} -M rdp -o METHOD=wmi ACTION={enable, disable, enable-ram, disable-ram} {OLD=true} {DCOM-TIMEOUT=5}
|
||||
"""
|
||||
if not "ACTION" in module_options:
|
||||
context.log.fail("ACTION option not specified!")
|
||||
exit(1)
|
||||
|
||||
if module_options["ACTION"].lower() not in ["enable", "disable"]:
|
||||
if module_options["ACTION"].lower() not in ["enable", "disable", "enable-ram", "disable-ram"]:
|
||||
context.log.fail("Invalid value for ACTION option!")
|
||||
exit(1)
|
||||
|
||||
self.action = module_options["ACTION"].lower()
|
||||
|
||||
if not "METHOD" in module_options:
|
||||
self.method = "wmi"
|
||||
else:
|
||||
self.method = module_options['METHOD'].lower()
|
||||
|
||||
if context.protocol != "smb" and self.method == "smb":
|
||||
context.log.fail(f"Protocol: {context.protocol} not support this method")
|
||||
exit(1)
|
||||
|
||||
if not "DCOM-TIMEOUT" in module_options:
|
||||
self.dcom_timeout = 10
|
||||
else:
|
||||
try:
|
||||
self.dcom_timeout = int(module_options['DCOM-TIMEOUT'])
|
||||
except:
|
||||
context.log.fail("Wrong DCOM timeout value!")
|
||||
exit(1)
|
||||
|
||||
if not "OLD" in module_options:
|
||||
self.oldSystem = False
|
||||
else:
|
||||
self.oldSystem = True
|
||||
|
||||
def on_admin_login(self, context, connection):
|
||||
if self.action == "enable":
|
||||
self.rdp_enable(context, connection.conn)
|
||||
elif self.action == "disable":
|
||||
self.rdp_disable(context, connection.conn)
|
||||
# Preparation for wmi protocol
|
||||
if self.method == "smb":
|
||||
context.log.info("Executing over SMB(ncacn_np)")
|
||||
try:
|
||||
smb_rdp = rdp_SMB(context, connection)
|
||||
if "ram" in self.action:
|
||||
smb_rdp.rdp_RAMWrapper(self.action)
|
||||
else:
|
||||
smb_rdp.rdp_Wrapper(self.action)
|
||||
except Exception as e:
|
||||
context.log.fail(f"Enable RDP via smb error: {str(e)}")
|
||||
elif self.method == "wmi":
|
||||
context.log.info("Executing over WMI(ncacn_ip_tcp)")
|
||||
try:
|
||||
wmi_rdp = rdp_WMI(context, connection, self.dcom_timeout)
|
||||
except Exception as e:
|
||||
context.log.fail(f"Unexpected wmi error: {str(e)}")
|
||||
wmi_rdp._rdp_WMI__dcom.disconnect()
|
||||
|
||||
def rdp_enable(self, context, smbconnection):
|
||||
remoteOps = RemoteOperations(smbconnection, False)
|
||||
if hasattr(wmi_rdp, '_rdp_WMI__iWbemLevel1Login'):
|
||||
if "ram" in self.action:
|
||||
# Nt version under 6 not support RAM.
|
||||
try:
|
||||
wmi_rdp.rdp_RAMWrapper(self.action)
|
||||
except Exception as e:
|
||||
if "WBEM_E_NOT_FOUND" in str(e):
|
||||
context.log.fail("System version under NT6 not support restricted admin mode")
|
||||
else:
|
||||
context.log.fail(str(e))
|
||||
pass
|
||||
wmi_rdp._rdp_WMI__dcom.disconnect()
|
||||
else:
|
||||
try:
|
||||
wmi_rdp.rdp_Wrapper(self.action, self.oldSystem)
|
||||
except Exception as e:
|
||||
if "WBEM_E_INVALID_NAMESPACE" in str(e):
|
||||
context.log.fail('Looks like target system version is under NT6, please add "OLD=true" in module options.')
|
||||
else:
|
||||
context.log.fail(str(e))
|
||||
pass
|
||||
wmi_rdp._rdp_WMI__dcom.disconnect()
|
||||
|
||||
class rdp_SMB:
|
||||
def __init__(self, context, connection):
|
||||
self.context = context
|
||||
self.__smbconnection = connection.conn
|
||||
self.__execute = connection.execute
|
||||
self.logger = context.log
|
||||
|
||||
def rdp_Wrapper(self, action):
|
||||
remoteOps = RemoteOperations(self.__smbconnection, False)
|
||||
remoteOps.enableRegistry()
|
||||
|
||||
if remoteOps._RemoteOperations__rrp:
|
||||
@@ -54,26 +134,32 @@ class CMEModule:
|
||||
)
|
||||
keyHandle = ans["phkResult"]
|
||||
|
||||
rrp.hBaseRegSetValue(
|
||||
ans = rrp.hBaseRegSetValue(
|
||||
remoteOps._RemoteOperations__rrp,
|
||||
keyHandle,
|
||||
"fDenyTSConnections\x00",
|
||||
"fDenyTSConnections",
|
||||
rrp.REG_DWORD,
|
||||
0,
|
||||
0 if action == "enable" else 1,
|
||||
)
|
||||
|
||||
rtype, data = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "fDenyTSConnections\x00")
|
||||
rtype, data = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "fDenyTSConnections")
|
||||
|
||||
if int(data) == 0:
|
||||
context.log.success("RDP enabled successfully")
|
||||
self.logger.success("Enable RDP via SMB(ncacn_np) successfully")
|
||||
elif int(data) == 1:
|
||||
self.logger.success("Disable RDP via SMB(ncacn_np) successfully")
|
||||
|
||||
self.firewall_CMD(action)
|
||||
|
||||
if action == "enable":
|
||||
self.query_RDPPort(remoteOps, regHandle)
|
||||
try:
|
||||
remoteOps.finish()
|
||||
except:
|
||||
pass
|
||||
|
||||
def rdp_disable(self, context, smbconnection):
|
||||
remoteOps = RemoteOperations(smbconnection, False)
|
||||
def rdp_RAMWrapper(self, action):
|
||||
remoteOps = RemoteOperations(self.__smbconnection, False)
|
||||
remoteOps.enableRegistry()
|
||||
|
||||
if remoteOps._RemoteOperations__rrp:
|
||||
@@ -83,24 +169,170 @@ class CMEModule:
|
||||
ans = rrp.hBaseRegOpenKey(
|
||||
remoteOps._RemoteOperations__rrp,
|
||||
regHandle,
|
||||
"SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
|
||||
"System\\CurrentControlSet\\Control\\Lsa",
|
||||
)
|
||||
keyHandle = ans["phkResult"]
|
||||
|
||||
rrp.hBaseRegSetValue(
|
||||
remoteOps._RemoteOperations__rrp,
|
||||
keyHandle,
|
||||
"fDenyTSConnections\x00",
|
||||
"DisableRestrictedAdmin",
|
||||
rrp.REG_DWORD,
|
||||
1,
|
||||
0 if action == "enable-ram" else 1,
|
||||
)
|
||||
|
||||
rtype, data = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "fDenyTSConnections\x00")
|
||||
rtype, data = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "DisableRestrictedAdmin")
|
||||
|
||||
if int(data) == 1:
|
||||
context.log.success("RDP disabled successfully")
|
||||
if int(data) == 0:
|
||||
self.logger.success("Enable RDP Restricted Admin Mode via SMB(ncacn_np) succeed")
|
||||
elif int(data) == 1:
|
||||
self.logger.success("Disable RDP Restricted Admin Mode via SMB(ncacn_np) succeed")
|
||||
|
||||
try:
|
||||
remoteOps.finish()
|
||||
except:
|
||||
pass
|
||||
|
||||
def query_RDPPort(self, remoteOps, regHandle):
|
||||
if remoteOps:
|
||||
ans = rrp.hBaseRegOpenKey(
|
||||
remoteOps._RemoteOperations__rrp,
|
||||
regHandle,
|
||||
"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp",
|
||||
)
|
||||
keyHandle = ans["phkResult"]
|
||||
|
||||
rtype, data = rrp.hBaseRegQueryValue(remoteOps._RemoteOperations__rrp, keyHandle, "PortNumber")
|
||||
|
||||
self.logger.success(f"RDP Port: {str(data)}")
|
||||
|
||||
# https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/manage/enable_rdp.rb
|
||||
def firewall_CMD(self, action):
|
||||
cmd = f"netsh firewall set service type = remotedesktop mode = {action}"
|
||||
self.logger.info("Configure firewall via execute command.")
|
||||
output = self.__execute(cmd, True)
|
||||
if output:
|
||||
self.logger.success(f"{action.capitalize()} RDP firewall rules via cmd succeed")
|
||||
else:
|
||||
self.logger.fail(f"{action.capitalize()} RDP firewall rules via cmd failed, maybe got detected by AV software.")
|
||||
|
||||
class rdp_WMI:
|
||||
def __init__(self, context, connection, timeout):
|
||||
self.logger = context.log
|
||||
self.__currentprotocol = context.protocol
|
||||
# From dfscoerce.py
|
||||
self.__username=connection.username
|
||||
self.__password=connection.password
|
||||
self.__domain=connection.domain
|
||||
self.__lmhash=connection.lmhash
|
||||
self.__nthash=connection.nthash
|
||||
self.__target=connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
||||
self.__doKerberos=connection.kerberos
|
||||
self.__kdcHost=connection.kdcHost
|
||||
self.__aesKey=connection.aesKey
|
||||
self.__timeout = timeout
|
||||
|
||||
self.__dcom = DCOMConnection(
|
||||
self.__target,
|
||||
self.__username,
|
||||
self.__password,
|
||||
self.__domain,
|
||||
self.__lmhash,
|
||||
self.__nthash,
|
||||
self.__aesKey,
|
||||
oxidResolver=True,
|
||||
doKerberos=self.__doKerberos,
|
||||
kdcHost=self.__kdcHost,
|
||||
)
|
||||
|
||||
iInterface = self.__dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
|
||||
if self.__currentprotocol == "smb":
|
||||
flag, self.__stringBinding = dcom_FirewallChecker(iInterface, self.__timeout)
|
||||
if not flag:
|
||||
self.logger.fail(f'WMIEXEC: Dcom initialization failed on connection with stringbinding: "{self.__stringBinding}", please increase the timeout with the module option "DCOM-TIMEOUT=10". If it\'s still failing maybe something is blocking the RPC connection, try "METHOD=smb"')
|
||||
# Make it force break function
|
||||
self.__dcom.disconnect()
|
||||
return
|
||||
self.__iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
|
||||
|
||||
def rdp_Wrapper(self, action, old=False):
|
||||
if old == False:
|
||||
# According to this document: https://learn.microsoft.com/en-us/windows/win32/termserv/win32-tslogonsetting
|
||||
# Authentication level must set to RPC_C_AUTHN_LEVEL_PKT_PRIVACY when accessing namespace "//./root/cimv2/TerminalServices"
|
||||
iWbemServices = self.__iWbemLevel1Login.NTLMLogin('//./root/cimv2/TerminalServices', NULL, NULL)
|
||||
iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
self.__iWbemLevel1Login.RemRelease()
|
||||
iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting")
|
||||
iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0]
|
||||
if action == 'enable':
|
||||
self.logger.info("Enabled RDP services and setting up firewall.")
|
||||
iWbemClassObject.SetAllowTSConnections(1,1)
|
||||
elif action == 'disable':
|
||||
self.logger.info("Disabled RDP services and setting up firewall.")
|
||||
iWbemClassObject.SetAllowTSConnections(0,0)
|
||||
else:
|
||||
iWbemServices = self.__iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
|
||||
self.__iWbemLevel1Login.RemRelease()
|
||||
iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting")
|
||||
iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0]
|
||||
if action == 'enable':
|
||||
self.logger.info("Enabling RDP services (old system not support setting up firewall)")
|
||||
iWbemClassObject.SetAllowTSConnections(1)
|
||||
elif action == 'disable':
|
||||
self.logger.info("Disabling RDP services (old system not support setting up firewall)")
|
||||
iWbemClassObject.SetAllowTSConnections(0)
|
||||
|
||||
self.query_RDPResult(old)
|
||||
|
||||
if action == 'enable':
|
||||
self.query_RDPPort()
|
||||
# Need to create new iWbemServices interface in order to flush results
|
||||
|
||||
def query_RDPResult(self, old=False):
|
||||
if old == False:
|
||||
iWbemServices = self.__iWbemLevel1Login.NTLMLogin('//./root/cimv2/TerminalServices', NULL, NULL)
|
||||
iWbemServices.get_dce_rpc().set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
self.__iWbemLevel1Login.RemRelease()
|
||||
iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting")
|
||||
iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0]
|
||||
result = dict(iWbemClassObject.getProperties())
|
||||
result = result['AllowTSConnections']['value']
|
||||
if result == 0:
|
||||
self.logger.success("Disable RDP via WMI(ncacn_ip_tcp) successfully")
|
||||
else:
|
||||
self.logger.success("Enable RDP via WMI(ncacn_ip_tcp) successfully")
|
||||
else:
|
||||
iWbemServices = self.__iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
|
||||
self.__iWbemLevel1Login.RemRelease()
|
||||
iEnumWbemClassObject = iWbemServices.ExecQuery("SELECT * FROM Win32_TerminalServiceSetting")
|
||||
iWbemClassObject = iEnumWbemClassObject.Next(0xffffffff,1)[0]
|
||||
result = dict(iWbemClassObject.getProperties())
|
||||
result = result['AllowTSConnections']['value']
|
||||
if result == 0:
|
||||
self.logger.success("Disable RDP via WMI(ncacn_ip_tcp) successfully (old system)")
|
||||
else:
|
||||
self.logger.success("Enable RDP via WMI(ncacn_ip_tcp) successfully (old system)")
|
||||
|
||||
def query_RDPPort(self):
|
||||
iWbemServices = self.__iWbemLevel1Login.NTLMLogin('//./root/DEFAULT', NULL, NULL)
|
||||
self.__iWbemLevel1Login.RemRelease()
|
||||
StdRegProv, resp = iWbemServices.GetObject("StdRegProv")
|
||||
out = StdRegProv.GetDWORDValue(2147483650, 'SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp', 'PortNumber')
|
||||
self.logger.success(f"RDP Port: {str(out.uValue)}")
|
||||
|
||||
# Nt version under 6 not support RAM.
|
||||
def rdp_RAMWrapper(self, action):
|
||||
iWbemServices = self.__iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
|
||||
self.__iWbemLevel1Login.RemRelease()
|
||||
StdRegProv, resp = iWbemServices.GetObject("StdRegProv")
|
||||
if action == 'enable-ram':
|
||||
self.logger.info("Enabling Restricted Admin Mode.")
|
||||
StdRegProv.SetDWORDValue(2147483650, 'System\\CurrentControlSet\\Control\\Lsa', 'DisableRestrictedAdmin', 0)
|
||||
elif action == 'disable-ram':
|
||||
self.logger.info("Disabling Restricted Admin Mode (Clear).")
|
||||
StdRegProv.DeleteValue(2147483650, 'System\\CurrentControlSet\\Control\\Lsa', 'DisableRestrictedAdmin')
|
||||
out = StdRegProv.GetDWORDValue(2147483650, 'System\\CurrentControlSet\\Control\\Lsa', 'DisableRestrictedAdmin')
|
||||
if out.uValue == 0:
|
||||
self.logger.success("Enable RDP Restricted Admin Mode via WMI(ncacn_ip_tcp) successfully")
|
||||
elif out.uValue == None:
|
||||
self.logger.success("Disable RDP Restricted Admin Mode via WMI(ncacn_ip_tcp) successfully")
|
||||
+1
-1
@@ -503,7 +503,7 @@ class HostChecker:
|
||||
|
||||
def check_last_successful_update(self):
|
||||
records = self.connection.wmi(wmi_query='Select TimeGenerated FROM Win32_ReliabilityRecords Where EventIdentifier=19', namespace='root\\cimv2')
|
||||
if len(records) == 0:
|
||||
if isinstance(records, bool) or len(records) == 0:
|
||||
return False, ['No update found']
|
||||
most_recent_update_date = records[0]['TimeGenerated']['value']
|
||||
most_recent_update_date = most_recent_update_date.split('.')[0]
|
||||
|
||||
+50
-29
@@ -21,11 +21,13 @@ from impacket.dcerpc.v5.rpcrt import DCERPCException
|
||||
from impacket.dcerpc.v5.transport import DCERPCTransportFactory, SMBTransport
|
||||
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
|
||||
from impacket.dcerpc.v5.epm import MSRPC_UUID_PORTMAP
|
||||
from impacket.dcerpc.v5.dcom.wmi import WBEM_FLAG_FORWARD_ONLY
|
||||
from impacket.dcerpc.v5.samr import SID_NAME_USE
|
||||
from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED
|
||||
from impacket.krb5.kerberosv5 import SessionKeyDecryptionError
|
||||
from impacket.krb5.types import KerberosException
|
||||
from impacket.dcerpc.v5.dtypes import NULL
|
||||
from impacket.dcerpc.v5.dcomrt import DCOMConnection
|
||||
from impacket.dcerpc.v5.dcom.wmi import CLSID_WbemLevel1Login, IID_IWbemLevel1Login, WBEM_FLAG_FORWARD_ONLY, IWbemLevel1Login
|
||||
|
||||
from cme.config import process_secret, host_info_colors
|
||||
from cme.connection import *
|
||||
@@ -56,7 +58,6 @@ from dploot.lib.target import Target
|
||||
from dploot.lib.smb import DPLootSMBConnection
|
||||
|
||||
from pywerview.cli.helpers import *
|
||||
from pywerview.requester import RPCRequester
|
||||
|
||||
from time import time
|
||||
from datetime import datetime
|
||||
@@ -690,7 +691,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 +712,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
|
||||
@@ -1207,45 +1209,64 @@ class smb(connection):
|
||||
def pass_pol(self):
|
||||
return PassPolDump(self).dump()
|
||||
|
||||
@requires_admin
|
||||
def wmi(self, wmi_query=None, namespace=None):
|
||||
records = []
|
||||
if not wmi_query:
|
||||
wmi_query = self.args.wmi.strip('\n')
|
||||
|
||||
if not namespace:
|
||||
namespace = self.args.wmi_namespace
|
||||
|
||||
try:
|
||||
rpc = RPCRequester(
|
||||
self.host,
|
||||
self.domain,
|
||||
dcom = DCOMConnection(
|
||||
self.host if not self.kerberos else self.hostname + "." + self.domain,
|
||||
self.username,
|
||||
self.password,
|
||||
self.domain,
|
||||
self.lmhash,
|
||||
self.nthash,
|
||||
oxidResolver=True,
|
||||
doKerberos=self.kerberos,
|
||||
kdcHost=self.kdcHost,
|
||||
aesKey=self.aesKey
|
||||
)
|
||||
rpc._create_wmi_connection(namespace=namespace)
|
||||
|
||||
if wmi_query:
|
||||
query = rpc._wmi_connection.ExecQuery(wmi_query, lFlags=WBEM_FLAG_FORWARD_ONLY)
|
||||
else:
|
||||
query = rpc._wmi_connection.ExecQuery(self.args.wmi, lFlags=WBEM_FLAG_FORWARD_ONLY)
|
||||
iInterface = dcom.CoCreateInstanceEx(CLSID_WbemLevel1Login,IID_IWbemLevel1Login)
|
||||
flag, stringBinding = dcom_FirewallChecker(iInterface, self.args.dcom_timeout)
|
||||
if not flag:
|
||||
self.logger.fail(f'WMI Query: Dcom initialization failed on connection with stringbinding: "{stringBinding}", please increase the timeout with the option "--dcom-timeout". If it\'s still failing maybe something is blocking the RPC connection')
|
||||
# Make it force break function
|
||||
dcom.disconnect()
|
||||
return False
|
||||
iWbemLevel1Login = IWbemLevel1Login(iInterface)
|
||||
iWbemServices= iWbemLevel1Login.NTLMLogin(namespace , NULL, NULL)
|
||||
iWbemLevel1Login.RemRelease()
|
||||
iEnumWbemClassObject = iWbemServices.ExecQuery(wmi_query)
|
||||
except Exception as e:
|
||||
self.logger.fail(f"Error creating WMI connection: {e}")
|
||||
return records
|
||||
|
||||
while True:
|
||||
self.logger.fail('Execute WQL error: {}'.format(e))
|
||||
dcom.disconnect()
|
||||
return False
|
||||
else:
|
||||
self.logger.info(f"Executing WQL syntax: {wmi_query}")
|
||||
while True:
|
||||
try:
|
||||
wmi_results = iEnumWbemClassObject.Next(0xffffffff, 1)[0]
|
||||
record = wmi_results.getProperties()
|
||||
records.append(record)
|
||||
for k,v in record.items():
|
||||
self.logger.highlight(f"{k} => {v['value']}")
|
||||
except Exception as e:
|
||||
if str(e).find('S_FALSE') < 0:
|
||||
raise e
|
||||
else:
|
||||
break
|
||||
try:
|
||||
wmi_results = query.Next(0xFFFFFFFF, 1)[0]
|
||||
record = wmi_results.getProperties()
|
||||
records.append(record)
|
||||
for k, v in record.items():
|
||||
self.logger.highlight(f"{k} => {v['value']}")
|
||||
self.logger.highlight("")
|
||||
except Exception as e:
|
||||
if str(e).find("S_FALSE") < 0:
|
||||
raise e
|
||||
else:
|
||||
break
|
||||
iEnumWbemClassObject.RemRelease()
|
||||
dcom.disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
return records
|
||||
return records
|
||||
|
||||
def spider(
|
||||
self,
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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",))
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Generated
+11
-7
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aardwolf"
|
||||
@@ -1517,18 +1517,22 @@ files = [
|
||||
[[package]]
|
||||
name = "oscrypto"
|
||||
version = "1.3.0"
|
||||
description = "TLS (SSL) sockets, key generation, encryption, decryption, signing, verification and KDFs using the OS crypto libraries. Does not require a compiler, and relies on the OS for patching. Works on Windows, OS X and Linux/BSD."
|
||||
description = ""
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "oscrypto-1.3.0-py2.py3-none-any.whl", hash = "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085"},
|
||||
{file = "oscrypto-1.3.0.tar.gz", hash = "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4"},
|
||||
]
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
asn1crypto = ">=1.5.1"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/NeffIsBack/oscrypto"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "d5f3437ed24257895ae1edd9e503cfb352e635a8"
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
@@ -2825,4 +2829,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.7.0"
|
||||
content-hash = "08ee44e127854163d05ae0473213bc2ce67f52fde734c7dde21f1c4a6535e124"
|
||||
content-hash = "9dc5181178139fe742c1b9d18de9613e544a11e221b30299aabc8ab04b68cc09"
|
||||
|
||||
@@ -54,6 +54,7 @@ pyasn1-modules = "^0.3.0"
|
||||
rich = "^13.3.5"
|
||||
python-libnmap = "^0.7.3"
|
||||
resource = "^0.2.1"
|
||||
oscrypto = { git = "https://github.com/NeffIsBack/oscrypto" }
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
flake8 = "*"
|
||||
|
||||
Reference in New Issue
Block a user