2023-10-06 16:41:00 +00:00
import os
import struct
import logging
2023-08-06 13:51:21 +00:00
2023-08-08 07:22:20 +00:00
from io import StringIO
2023-08-06 13:51:21 +00:00
from six import indexbytes
from datetime import datetime
2023-09-14 21:07:15 +00:00
from nxc . config import process_secret
2023-10-06 16:41:00 +00:00
from nxc . connection import connection , dcom_FirewallChecker , requires_admin
2023-09-14 21:07:15 +00:00
from nxc . logger import NXCAdapter
from nxc . protocols . wmi import wmiexec , wmiexec_event
2023-08-06 13:51:21 +00:00
from impacket import ntlm
from impacket . uuid import uuidtup_to_bin
2023-08-07 08:13:13 +00:00
from impacket . krb5 . ccache import CCache
2023-08-06 13:51:21 +00:00
from impacket . dcerpc . v5 . dtypes import NULL
from impacket . dcerpc . v5 import transport , epm
from impacket . dcerpc . v5 . rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY , RPC_C_AUTHN_WINNT , RPC_C_AUTHN_GSS_NEGOTIATE , RPC_C_AUTHN_LEVEL_PKT_INTEGRITY , MSRPC_BIND , MSRPCBind , CtxItem , MSRPCHeader , SEC_TRAILER , MSRPCBindAck
from impacket . dcerpc . v5 . dcomrt import DCOMConnection
2023-09-20 15:59:16 +00:00
from impacket . dcerpc . v5 . dcom . wmi import CLSID_WbemLevel1Login , IID_IWbemLevel1Login , IWbemLevel1Login
2023-10-14 19:56:22 +00:00
import contextlib
2023-08-06 13:51:21 +00:00
2023-09-23 01:10:21 +00:00
MSRPC_UUID_PORTMAP = uuidtup_to_bin ( ( " E1AF8308-5D1F-11C9-91A4-08002B14A0FA " , " 3.0 " ) )
2023-08-06 13:51:21 +00:00
2023-09-23 01:10:21 +00:00
class wmi ( connection ) :
2023-08-06 13:51:21 +00:00
def __init__ ( self , args , db , host ) :
self . domain = None
2023-09-23 01:10:21 +00:00
self . hash = " "
self . lmhash = " "
self . nthash = " "
self . fqdn = " "
self . remoteName = " "
2023-08-06 13:51:21 +00:00
self . server_os = None
2023-08-07 08:13:13 +00:00
self . doKerberos = False
2023-08-15 05:42:12 +00:00
self . stringBinding = None
2023-10-06 16:43:34 +00:00
# from: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d
self . rpc_error_status = {
" 0000052F " : " STATUS_ACCOUNT_RESTRICTION " ,
" 00000533 " : " STATUS_ACCOUNT_DISABLED " ,
" 00000775 " : " STATUS_ACCOUNT_LOCKED_OUT " ,
" 00000701 " : " STATUS_ACCOUNT_EXPIRED " ,
" 00000532 " : " STATUS_PASSWORD_EXPIRED " ,
" 00000530 " : " STATUS_INVALID_LOGON_HOURS " ,
" 00000531 " : " STATUS_INVALID_WORKSTATION " ,
" 00000569 " : " STATUS_LOGON_TYPE_NOT_GRANTED " ,
" 00000773 " : " STATUS_PASSWORD_MUST_CHANGE " ,
" 00000005 " : " STATUS_ACCESS_DENIED " ,
" 0000052E " : " STATUS_LOGON_FAILURE " ,
" 0000052B " : " STATUS_WRONG_PASSWORD " ,
" 00000721 " : " RPC_S_SEC_PKG_ERROR "
}
2023-08-06 13:51:21 +00:00
connection . __init__ ( self , args , db , host )
def proto_logger ( self ) :
2023-10-06 16:43:34 +00:00
self . logger = NXCAdapter (
extra = {
" protocol " : " WMI " ,
" host " : self . host ,
" port " : self . args . port ,
" hostname " : self . hostname
}
)
2023-09-23 01:10:21 +00:00
2023-08-06 13:51:21 +00:00
def create_conn_obj ( self ) :
2023-09-23 01:10:21 +00:00
if self . remoteName == " " :
2023-08-07 08:13:13 +00:00
self . remoteName = self . host
2023-08-06 13:51:21 +00:00
try :
2023-10-12 21:06:04 +00:00
rpctansport = transport . DCERPCTransportFactory ( fr " ncacn_ip_tcp: { self . remoteName } [ { str ( self . args . port ) } ] " )
2023-08-07 08:13:13 +00:00
rpctansport . set_credentials ( username = " " , password = " " , domain = " " , lmhash = " " , nthash = " " , aesKey = " " )
rpctansport . setRemoteHost ( self . host )
2023-08-15 05:42:12 +00:00
rpctansport . set_connect_timeout ( self . args . rpc_timeout )
2023-08-06 13:51:21 +00:00
dce = rpctansport . get_dce_rpc ( )
dce . set_auth_type ( RPC_C_AUTHN_WINNT )
dce . connect ( )
dce . bind ( MSRPC_UUID_PORTMAP )
dce . disconnect ( )
except Exception as e :
2023-09-01 13:49:57 +00:00
self . logger . debug ( str ( e ) )
2023-08-06 13:51:21 +00:00
return False
else :
self . conn = rpctansport
return True
2023-09-23 01:10:21 +00:00
2023-08-06 13:51:21 +00:00
def enum_host_info ( self ) :
# All code pick from DumpNTLNInfo.py
2023-08-07 08:13:13 +00:00
# https://github.com/fortra/impacket/blob/master/examples/DumpNTLMInfo.py
2023-08-06 13:51:21 +00:00
ntlmChallenge = None
2023-09-23 01:10:21 +00:00
2023-08-06 13:51:21 +00:00
bind = MSRPCBind ( )
item = CtxItem ( )
2023-09-23 01:10:21 +00:00
item [ " AbstractSyntax " ] = epm . MSRPC_UUID_PORTMAP
item [ " TransferSyntax " ] = uuidtup_to_bin ( ( " 8a885d04-1ceb-11c9-9fe8-08002b104860 " , " 2.0 " ) )
item [ " ContextID " ] = 0
item [ " TransItems " ] = 1
2023-08-06 13:51:21 +00:00
bind . addCtxItem ( item )
packet = MSRPCHeader ( )
2023-09-23 01:10:21 +00:00
packet [ " type " ] = MSRPC_BIND
packet [ " pduData " ] = bind . getData ( )
packet [ " call_id " ] = 1
2023-08-06 13:51:21 +00:00
2023-09-23 01:10:21 +00:00
auth = ntlm . getNTLMSSPType1 ( " " , " " , signingRequired = True , use_ntlmv2 = True )
2023-08-06 13:51:21 +00:00
sec_trailer = SEC_TRAILER ( )
2023-09-23 01:10:21 +00:00
sec_trailer [ " auth_type " ] = RPC_C_AUTHN_WINNT
sec_trailer [ " auth_level " ] = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY
sec_trailer [ " auth_ctx_id " ] = 0 + 79231
2023-08-06 13:51:21 +00:00
pad = ( 4 - ( len ( packet . get_packet ( ) ) % 4 ) ) % 4
if pad != 0 :
2023-09-23 01:10:21 +00:00
packet [ " pduData " ] + = b " \xFF " * pad
sec_trailer [ " auth_pad_len " ] = pad
packet [ " sec_trailer " ] = sec_trailer
packet [ " auth_data " ] = auth
2023-08-06 13:51:21 +00:00
2023-08-08 07:22:20 +00:00
try :
self . conn . connect ( )
self . conn . send ( packet . get_packet ( ) )
buffer = self . conn . recv ( )
2023-10-06 16:47:49 +00:00
except Exception :
2023-08-08 07:22:20 +00:00
buffer = 0
2023-08-06 13:51:21 +00:00
if buffer != 0 :
response = MSRPCHeader ( buffer )
bindResp = MSRPCBindAck ( response . getData ( ) )
2023-09-23 01:10:21 +00:00
ntlmChallenge = ntlm . NTLMAuthChallenge ( bindResp [ " auth_data " ] )
2023-08-06 13:51:21 +00:00
2023-09-23 01:10:21 +00:00
if ntlmChallenge [ " TargetInfoFields_len " ] > 0 :
av_pairs = ntlm . AV_PAIRS ( ntlmChallenge [ " TargetInfoFields " ] [ : ntlmChallenge [ " TargetInfoFields_len " ] ] )
2023-08-06 13:51:21 +00:00
if av_pairs [ ntlm . NTLMSSP_AV_HOSTNAME ] [ 1 ] is not None :
try :
2023-09-23 01:10:21 +00:00
self . hostname = av_pairs [ ntlm . NTLMSSP_AV_HOSTNAME ] [ 1 ] . decode ( " utf-16le " )
2023-10-06 16:47:49 +00:00
except Exception :
2023-08-06 13:51:21 +00:00
self . hostname = self . host
if av_pairs [ ntlm . NTLMSSP_AV_DNS_DOMAINNAME ] [ 1 ] is not None :
try :
2023-09-23 01:10:21 +00:00
self . domain = av_pairs [ ntlm . NTLMSSP_AV_DNS_DOMAINNAME ] [ 1 ] . decode ( " utf-16le " )
2023-10-06 16:47:49 +00:00
except Exception :
2023-08-06 13:51:21 +00:00
self . domain = self . args . domain
2023-08-07 08:13:13 +00:00
if av_pairs [ ntlm . NTLMSSP_AV_DNS_HOSTNAME ] [ 1 ] is not None :
2023-10-14 19:56:22 +00:00
with contextlib . suppress ( Exception ) :
2023-09-23 01:10:21 +00:00
self . fqdn = av_pairs [ ntlm . NTLMSSP_AV_DNS_HOSTNAME ] [ 1 ] . decode ( " utf-16le " )
if " Version " in ntlmChallenge . fields :
version = ntlmChallenge [ " Version " ]
2023-08-06 13:51:21 +00:00
if len ( version ) > = 4 :
2023-09-23 01:10:21 +00:00
self . server_os = " Windows NT %d . %d Build %d " % ( indexbytes ( version , 0 ) , indexbytes ( version , 1 ) , struct . unpack ( " <H " , version [ 2 : 4 ] ) [ 0 ] )
2023-08-06 13:51:21 +00:00
else :
self . hostname = self . host
2023-08-08 07:22:20 +00:00
if self . args . local_auth :
self . domain = self . hostname
2023-08-30 01:23:12 +00:00
if self . args . domain :
self . domain = self . args . domain
self . fqdn = f " { self . hostname } . { self . domain } "
2023-08-06 13:51:21 +00:00
self . logger . extra [ " hostname " ] = self . hostname
2023-09-14 21:07:15 +00:00
self . output_filename = os . path . expanduser ( f " ~/.nxc/logs/ { self . hostname } _ { self . host } _ { datetime . now ( ) . strftime ( ' % Y- % m- %d _ % H % M % S ' ) } " . replace ( " : " , " - " ) )
2023-08-06 13:51:21 +00:00
def print_host_info ( self ) :
2023-09-23 01:10:21 +00:00
self . logger . extra [ " protocol " ] = " RPC "
self . logger . extra [ " port " ] = " 135 "
2023-09-24 04:06:51 +00:00
self . logger . display ( f " { self . server_os } (name: { self . hostname } ) (domain: { self . domain } ) " )
2023-08-06 13:51:21 +00:00
return True
def check_if_admin ( self ) :
try :
2023-09-23 01:10:21 +00:00
dcom = DCOMConnection ( self . conn . getRemoteName ( ) , self . username , self . password , self . domain , self . lmhash , self . nthash , oxidResolver = True , doKerberos = self . doKerberos , kdcHost = self . kdcHost , aesKey = self . aesKey )
2023-08-06 13:51:21 +00:00
iInterface = dcom . CoCreateInstanceEx ( CLSID_WbemLevel1Login , IID_IWbemLevel1Login )
2023-08-26 03:42:54 +00:00
flag , self . stringBinding = dcom_FirewallChecker ( iInterface , self . args . rpc_timeout )
2023-08-06 13:51:21 +00:00
except Exception as e :
2023-08-30 07:57:11 +00:00
if " dcom " in locals ( ) :
dcom . disconnect ( )
2023-08-06 13:51:21 +00:00
2023-09-14 08:32:31 +00:00
if " access_denied " not in str ( e ) . lower ( ) :
2023-08-15 05:42:12 +00:00
self . logger . fail ( str ( e ) )
2023-08-06 13:51:21 +00:00
else :
2023-08-28 10:06:06 +00:00
if not flag or not self . stringBinding :
2023-08-30 01:21:03 +00:00
dcom . disconnect ( )
2023-08-28 11:22:56 +00:00
error_msg = f ' Check admin error: dcom initialization failed with stringbinding: " { self . stringBinding } " , please try " --rpc-timeout " option. (probably is admin) '
2023-09-23 01:10:21 +00:00
2023-08-28 10:06:06 +00:00
if not self . stringBinding :
error_msg = " Check admin error: dcom initialization failed: can ' t get target stringbinding, maybe cause by IPv6 or any other issues, please check your target again "
2023-09-23 01:10:21 +00:00
2023-08-28 11:22:56 +00:00
self . logger . fail ( error_msg ) if not flag else self . logger . debug ( error_msg )
2023-08-15 05:42:12 +00:00
else :
2023-08-26 03:42:54 +00:00
try :
iWbemLevel1Login = IWbemLevel1Login ( iInterface )
2023-09-23 01:10:21 +00:00
iWbemServices = iWbemLevel1Login . NTLMLogin ( " //./root/cimv2 " , NULL , NULL )
2023-08-26 03:42:54 +00:00
except Exception as e :
2023-08-30 01:21:03 +00:00
dcom . disconnect ( )
2023-08-06 13:51:21 +00:00
2023-09-14 08:32:31 +00:00
if " access_denied " not in str ( e ) . lower ( ) :
2023-08-26 03:42:54 +00:00
self . logger . fail ( str ( e ) )
2023-08-15 05:42:12 +00:00
else :
2023-08-26 03:42:54 +00:00
dcom . disconnect ( )
2023-09-23 01:10:21 +00:00
self . logger . extra [ " protocol " ] = " WMI "
2023-08-26 03:42:54 +00:00
self . admin_privs = True
2023-08-15 05:42:12 +00:00
2023-08-06 13:51:21 +00:00
def kerberos_login ( self , domain , username , password = " " , ntlm_hash = " " , aesKey = " " , kdcHost = " " , useCache = False ) :
2023-08-07 08:13:13 +00:00
logging . getLogger ( " impacket " ) . disabled = True
2023-09-23 01:10:21 +00:00
lmhash = " "
nthash = " "
2023-08-06 13:51:21 +00:00
self . password = password
self . username = username
self . domain = domain
2023-08-07 08:13:13 +00:00
self . remoteName = self . fqdn
self . create_conn_obj ( )
2023-09-23 01:10:21 +00:00
2023-08-06 13:51:21 +00:00
if password == " " :
2023-09-23 01:10:21 +00:00
if ntlm_hash . find ( " : " ) != - 1 :
lmhash , nthash = ntlm_hash . split ( " : " )
2023-08-06 13:51:21 +00:00
else :
nthash = ntlm_hash
2023-08-07 08:13:13 +00:00
self . nthash = nthash
self . lmhash = lmhash
2023-09-23 01:10:21 +00:00
2023-10-14 19:56:22 +00:00
kerb_pass = next ( s for s in [ nthash , password , aesKey ] if s ) if not all ( s == " " for s in [ nthash , password , aesKey ] ) else " "
2023-09-23 01:10:21 +00:00
2023-10-14 19:56:22 +00:00
if useCache and kerb_pass == " " :
ccache = CCache . loadFile ( os . getenv ( " KRB5CCNAME " ) )
username = ccache . credentials [ 0 ] . header [ " client " ] . prettyPrint ( ) . decode ( ) . split ( " @ " ) [ 0 ]
self . username = username
2023-08-07 08:13:13 +00:00
used_ccache = " from ccache " if useCache else f " : { process_secret ( kerb_pass ) } "
2023-08-06 13:51:21 +00:00
try :
2023-08-07 08:13:13 +00:00
self . conn . set_credentials ( username = username , password = password , domain = domain , lmhash = lmhash , nthash = nthash , aesKey = self . aesKey )
2023-08-06 13:51:21 +00:00
self . conn . set_kerberos ( True , kdcHost )
dce = self . conn . get_dce_rpc ( )
dce . set_auth_type ( RPC_C_AUTHN_GSS_NEGOTIATE )
dce . set_auth_level ( RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
dce . connect ( )
dce . bind ( MSRPC_UUID_PORTMAP )
except Exception as e :
dce . disconnect ( )
2023-08-07 08:13:13 +00:00
error_msg = str ( e ) . lower ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( error_msg )
2023-08-07 08:13:13 +00:00
if " unpack requires a buffer of 4 bytes " in error_msg :
2023-08-27 07:06:22 +00:00
error_msg = " Kerberos authentication failure "
out = f " { self . domain } \\ { self . username } { used_ccache } { error_msg } "
self . logger . fail ( out )
2023-08-07 08:13:13 +00:00
elif " kerberos sessionerror " in str ( e ) . lower ( ) :
2023-08-27 07:06:22 +00:00
out = f " { self . domain } \\ { self . username } { used_ccache } { list ( e . getErrorString ( ) ) [ 0 ] } "
2023-08-07 08:13:13 +00:00
self . logger . fail ( out , color = " magenta " )
return False
else :
2023-08-27 07:06:22 +00:00
out = f " { self . domain } \\ { self . username } { used_ccache } { str ( e ) } "
2023-08-07 08:13:13 +00:00
self . logger . fail ( out , color = " red " )
return False
2023-08-06 13:51:21 +00:00
else :
try :
# Get data from rpc connection if got vaild creds
entry_handle = epm . ept_lookup_handle_t ( )
request = epm . ept_lookup ( )
2023-09-23 01:10:21 +00:00
request [ " inquiry_type " ] = 0x0
request [ " object " ] = NULL
request [ " Ifid " ] = NULL
request [ " vers_option " ] = 0x1
request [ " entry_handle " ] = entry_handle
request [ " max_ents " ] = 1
2023-09-20 15:59:16 +00:00
dce . request ( request )
2023-08-07 08:13:13 +00:00
except Exception as e :
2023-08-06 13:51:21 +00:00
dce . disconnect ( )
2023-08-07 08:13:13 +00:00
error_msg = str ( e ) . lower ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( error_msg )
2023-10-14 19:56:22 +00:00
for code in self . rpc_error_status :
2023-08-07 08:13:13 +00:00
if code in error_msg :
error_msg = self . rpc_error_status [ code ]
2023-08-27 07:06:22 +00:00
out = f " { self . domain } \\ { self . username } { used_ccache } { error_msg . upper ( ) } "
2023-08-07 08:13:13 +00:00
self . logger . fail ( out , color = ( " red " if " access_denied " in error_msg else " magenta " ) )
2023-08-06 13:51:21 +00:00
return False
else :
2023-08-07 08:13:13 +00:00
self . doKerberos = True
2023-08-06 13:51:21 +00:00
self . check_if_admin ( )
2023-08-08 07:22:20 +00:00
dce . disconnect ( )
2023-08-27 07:06:22 +00:00
out = f " { self . domain } \\ { self . username } { used_ccache } { self . mark_pwned ( ) } "
2023-08-06 13:51:21 +00:00
self . logger . success ( out )
return True
def plaintext_login ( self , domain , username , password ) :
self . password = password
self . username = username
self . domain = domain
try :
self . conn . set_credentials ( username = self . username , password = self . password , domain = self . domain , lmhash = self . lmhash , nthash = self . nthash )
dce = self . conn . get_dce_rpc ( )
dce . set_auth_type ( RPC_C_AUTHN_WINNT )
dce . set_auth_level ( RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
dce . connect ( )
dce . bind ( MSRPC_UUID_PORTMAP )
except Exception as e :
dce . disconnect ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( str ( e ) )
2023-08-27 07:06:22 +00:00
out = f " { self . domain } \\ { self . username } : { process_secret ( self . password ) } { str ( e ) } "
2023-08-07 08:13:13 +00:00
self . logger . fail ( out , color = " red " )
2023-08-06 13:51:21 +00:00
else :
try :
# Get data from rpc connection if got vaild creds
entry_handle = epm . ept_lookup_handle_t ( )
request = epm . ept_lookup ( )
2023-09-23 01:10:21 +00:00
request [ " inquiry_type " ] = 0x0
request [ " object " ] = NULL
request [ " Ifid " ] = NULL
request [ " vers_option " ] = 0x1
request [ " entry_handle " ] = entry_handle
request [ " max_ents " ] = 1
2023-09-20 15:59:16 +00:00
dce . request ( request )
2023-09-23 01:10:21 +00:00
except Exception as e :
2023-08-06 13:51:21 +00:00
dce . disconnect ( )
2023-08-07 08:13:13 +00:00
error_msg = str ( e ) . lower ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( error_msg )
2023-10-14 19:56:22 +00:00
for code in self . rpc_error_status :
2023-08-07 08:13:13 +00:00
if code in error_msg :
error_msg = self . rpc_error_status [ code ]
self . logger . fail ( ( f " { self . domain } \\ { self . username } : { process_secret ( self . password ) } ( { error_msg . upper ( ) } ) " ) , color = ( " red " if " access_denied " in error_msg else " magenta " ) )
2023-08-06 13:51:21 +00:00
return False
else :
self . check_if_admin ( )
dce . disconnect ( )
out = f " { domain } \\ { self . username } : { process_secret ( self . password ) } { self . mark_pwned ( ) } "
if self . username == " " and self . password == " " :
out + = " (Default allow anonymous login) "
self . logger . success ( out )
return True
2023-09-23 01:10:21 +00:00
2023-08-06 13:51:21 +00:00
def hash_login ( self , domain , username , ntlm_hash ) :
self . username = username
2023-09-23 01:10:21 +00:00
lmhash = " "
nthash = " "
if ntlm_hash . find ( " : " ) != - 1 :
self . lmhash , self . nthash = ntlm_hash . split ( " : " )
2023-08-06 13:51:21 +00:00
else :
2023-09-23 01:10:21 +00:00
lmhash = " "
2023-08-06 13:51:21 +00:00
nthash = ntlm_hash
2023-09-23 01:10:21 +00:00
2023-08-07 08:13:13 +00:00
self . nthash = nthash
self . lmhash = lmhash
2023-09-23 01:10:21 +00:00
2023-08-06 13:51:21 +00:00
try :
self . conn . set_credentials ( username = self . username , password = self . password , domain = self . domain , lmhash = lmhash , nthash = nthash )
dce = self . conn . get_dce_rpc ( )
dce . set_auth_type ( RPC_C_AUTHN_WINNT )
dce . set_auth_level ( RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
dce . connect ( )
dce . bind ( MSRPC_UUID_PORTMAP )
except Exception as e :
dce . disconnect ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( str ( e ) )
2023-08-27 07:06:22 +00:00
out = f " { domain } \\ { self . username } : { process_secret ( self . nthash ) } { str ( e ) } "
2023-08-07 08:13:13 +00:00
self . logger . fail ( out , color = " red " )
2023-08-06 13:51:21 +00:00
else :
try :
# Get data from rpc connection if got vaild creds
entry_handle = epm . ept_lookup_handle_t ( )
request = epm . ept_lookup ( )
2023-09-23 01:10:21 +00:00
request [ " inquiry_type " ] = 0x0
request [ " object " ] = NULL
request [ " Ifid " ] = NULL
request [ " vers_option " ] = 0x1
request [ " entry_handle " ] = entry_handle
request [ " max_ents " ] = 1
2023-09-20 15:59:16 +00:00
dce . request ( request )
2023-09-23 01:10:21 +00:00
except Exception as e :
2023-08-06 13:51:21 +00:00
dce . disconnect ( )
2023-08-07 08:13:13 +00:00
error_msg = str ( e ) . lower ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( error_msg )
2023-10-14 19:56:22 +00:00
for code in self . rpc_error_status :
2023-08-07 08:13:13 +00:00
if code in error_msg :
error_msg = self . rpc_error_status [ code ]
self . logger . fail ( ( f " { self . domain } \\ { self . username } : { process_secret ( self . nthash ) } ( { error_msg . upper ( ) } ) " ) , color = ( " red " if " access_denied " in error_msg else " magenta " ) )
2023-08-06 13:51:21 +00:00
return False
else :
self . check_if_admin ( )
dce . disconnect ( )
2023-08-07 08:13:13 +00:00
out = f " { domain } \\ { self . username } : { process_secret ( self . nthash ) } { self . mark_pwned ( ) } "
2023-08-06 13:51:21 +00:00
if self . username == " " and self . password == " " :
out + = " (Default allow anonymous login) "
self . logger . success ( out )
return True
2023-09-23 01:10:21 +00:00
# It's very complex to use wmi from rpctansport "convert" to dcom, so let we use dcom directly.
2023-08-06 13:51:21 +00:00
@requires_admin
2023-10-15 10:41:54 +00:00
def wmi ( self , wql = None , namespace = None ) :
""" Execute WQL syntax via WMI
This is done via the - - wmi flag
"""
2023-08-23 03:38:55 +00:00
records = [ ]
2023-10-15 10:41:54 +00:00
if not wql :
wql = self . args . wmi . strip ( " \n " )
2023-08-23 03:38:55 +00:00
if not namespace :
2023-08-26 03:42:54 +00:00
namespace = self . args . wmi_namespace
2023-08-23 03:38:55 +00:00
2023-08-06 13:51:21 +00:00
try :
2023-09-23 01:10:21 +00:00
dcom = DCOMConnection ( self . conn . getRemoteName ( ) , self . username , self . password , self . domain , self . lmhash , self . nthash , oxidResolver = True , doKerberos = self . doKerberos , kdcHost = self . kdcHost , aesKey = self . aesKey )
iInterface = dcom . CoCreateInstanceEx ( CLSID_WbemLevel1Login , IID_IWbemLevel1Login )
2023-08-06 13:51:21 +00:00
iWbemLevel1Login = IWbemLevel1Login ( iInterface )
2023-09-23 01:10:21 +00:00
iWbemServices = iWbemLevel1Login . NTLMLogin ( namespace , NULL , NULL )
2023-08-06 13:51:21 +00:00
iWbemLevel1Login . RemRelease ( )
2023-10-15 10:41:54 +00:00
iEnumWbemClassObject = iWbemServices . ExecQuery ( wql )
2023-08-06 13:51:21 +00:00
except Exception as e :
dcom . disconnect ( )
2023-09-01 13:49:57 +00:00
self . logger . debug ( str ( e ) )
2023-10-15 10:41:54 +00:00
self . logger . fail ( f " Execute WQL error: { e } " )
2023-08-23 03:38:55 +00:00
return False
2023-08-06 13:51:21 +00:00
else :
2023-10-15 10:41:54 +00:00
self . logger . info ( f " Executing WQL syntax: { wql } " )
try :
while True :
2023-09-23 01:10:21 +00:00
wmi_results = iEnumWbemClassObject . Next ( 0xFFFFFFFF , 1 ) [ 0 ]
2023-08-06 13:51:21 +00:00
record = wmi_results . getProperties ( )
2023-08-23 03:38:55 +00:00
records . append ( record )
2023-09-23 01:10:21 +00:00
for k , v in record . items ( ) :
2023-08-23 03:38:55 +00:00
self . logger . highlight ( f " { k } => { v [ ' value ' ] } " )
2023-10-15 10:41:54 +00:00
except Exception as e :
if str ( e ) . find ( " S_FALSE " ) < 0 :
self . logger . debug ( e )
2023-08-30 03:43:02 +00:00
dcom . disconnect ( )
2023-08-08 07:22:20 +00:00
2023-08-23 03:38:55 +00:00
return records
2023-08-06 13:51:21 +00:00
@requires_admin
2023-08-23 03:38:55 +00:00
def execute ( self , command = None , get_output = False ) :
2023-08-08 07:22:20 +00:00
output = " "
2023-08-23 03:38:55 +00:00
if not command :
command = self . args . execute
2023-08-08 07:22:20 +00:00
if not self . args . no_output :
get_output = True
2023-09-09 17:21:57 +00:00
if " systeminfo " in command and self . args . exec_timeout < 10 :
2023-08-08 07:22:20 +00:00
self . logger . fail ( " Execute ' systeminfo ' must set the interval time higher than 10 seconds " )
2023-08-06 13:51:21 +00:00
return False
2023-09-23 01:10:21 +00:00
2023-08-08 07:22:20 +00:00
if self . server_os is not None and " NT 5 " in self . server_os :
2023-08-30 03:30:19 +00:00
self . logger . fail ( " Execute command failed, not support current server os (version < NT 6) " )
2023-08-08 07:22:20 +00:00
return False
if self . args . exec_method == " wmiexec " :
2023-09-09 17:21:57 +00:00
exec_method = wmiexec . WMIEXEC ( self . conn . getRemoteName ( ) , self . username , self . password , self . domain , self . lmhash , self . nthash , self . doKerberos , self . kdcHost , self . aesKey , self . logger , self . args . exec_timeout , self . args . codec )
2023-08-30 03:14:16 +00:00
output = exec_method . execute ( command , get_output )
2023-09-23 01:10:21 +00:00
2023-08-08 07:22:20 +00:00
elif self . args . exec_method == " wmiexec-event " :
2023-09-09 17:21:57 +00:00
exec_method = wmiexec_event . WMIEXEC_EVENT ( self . conn . getRemoteName ( ) , self . username , self . password , self . domain , self . lmhash , self . nthash , self . doKerberos , self . kdcHost , self . aesKey , self . logger , self . args . exec_timeout , self . args . codec )
2023-08-30 03:14:16 +00:00
output = exec_method . execute ( command , get_output )
self . conn . disconnect ( )
2023-08-23 03:38:55 +00:00
if output == " " and get_output :
self . logger . fail ( " Execute command failed, probabaly got detection by AV. " )
return False
else :
self . logger . success ( f ' Executed command: " { command } " via { self . args . exec_method } ' )
buf = StringIO ( output ) . readlines ( )
for line in buf :
self . logger . highlight ( line . strip ( ) )
2023-09-23 01:10:21 +00:00
return output