Skip to content
This repository was archived by the owner on Dec 6, 2023. It is now read-only.

Commit 6a8ab5e

Browse files
author
byt3bl33d3r
committed
This commit introduces failover command execution
If a command or module fails to run using a certain execution method (e.g wmiexec) it will automatically try another one. This behavior can be overrided by using the --exec-method flag
1 parent a6cc776 commit 6a8ab5e

File tree

6 files changed

+76
-75
lines changed

6 files changed

+76
-75
lines changed

core/connection.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from traceback import format_exc
12
from core.helpers import highlight
23
from core.execmethods.mssqlexec import MSSQLEXEC
34
from core.execmethods.wmiexec import WMIEXEC
@@ -211,17 +212,42 @@ def execute(self, payload, get_output=False, method=None):
211212

212213
elif not self.args.mssql:
213214

214-
if not method:
215-
method = self.args.exec_method
216-
217-
if method == 'wmiexec':
218-
exec_method = WMIEXEC(self.host, self.username, self.password, self.domain, self.conn, self.hash, self.args.share)
219-
220-
elif method == 'smbexec':
221-
exec_method = SMBEXEC(self.host, self.args.smb_port, self.username, self.password, self.domain, self.hash, self.args.share)
222-
223-
elif method == 'atexec':
224-
exec_method = TSCH_EXEC(self.host, self.username, self.password, self.domain, self.hash) #self.args.share)
215+
if not method and not self.args.exec_method:
216+
try:
217+
exec_method = WMIEXEC(self.host, self.username, self.password, self.domain, self.conn, self.hash, self.args.share)
218+
except:
219+
if self.args.verbose:
220+
self.logger.debug('Error executing command via wmiexec, traceback:')
221+
self.logger.debug(format_exc())
222+
223+
try:
224+
exec_method = SMBEXEC(self.host, self.args.smb_port, self.username, self.password, self.domain, self.hash, self.args.share)
225+
except:
226+
if self.args.verbose:
227+
self.logger.debug('Error executing command via smbexec, traceback:')
228+
self.logger.debug(format_exc())
229+
230+
try:
231+
exec_method = TSCH_EXEC(self.host, self.username, self.password, self.domain, self.hash) #self.args.share)
232+
except:
233+
if self.args.verbose:
234+
self.logger.debug('Error executing command via atexec, traceback:')
235+
self.logger.debug(format_exc())
236+
return
237+
238+
elif method or self.args.exec_method:
239+
240+
if not method:
241+
method = self.args.exec_method
242+
243+
if method == 'wmiexec':
244+
exec_method = WMIEXEC(self.host, self.username, self.password, self.domain, self.conn, self.hash, self.args.share)
245+
246+
elif method == 'smbexec':
247+
exec_method = SMBEXEC(self.host, self.args.smb_port, self.username, self.password, self.domain, self.hash, self.args.share)
248+
249+
elif method == 'atexec':
250+
exec_method = TSCH_EXEC(self.host, self.username, self.password, self.domain, self.hash) #self.args.share)
225251

226252
if self.cmeserver:
227253
if hasattr(self.cmeserver.server.module, 'on_request') or hasattr(self.cmeserver.server.module, 'on_response'):

core/connector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def connector(target, args, db, module, context, cmeserver):
127127
if args.pscommand:
128128
output = connection.execute(create_ps_command(args.pscommand), get_output=get_output, method=args.exec_method)
129129

130-
logger.success('Executed command via {}'.format(args.exec_method))
130+
logger.success('Executed command {}'.format('via {}'.format(args.exec_method) if args.exec_method else ''))
131131
buf = StringIO(output).readlines()
132132
for line in buf:
133133
logger.highlight(line.strip())

core/execmethods/atexec.py

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import traceback
2-
31
from impacket.dcerpc.v5 import tsch, transport
42
from impacket.dcerpc.v5.dtypes import NULL
53
from core.helpers import gen_random_string
@@ -38,11 +36,8 @@ def __init__(self, target, username, password, domain, hashes=None):
3836

3937
def execute(self, command, output=False):
4038
self.__retOutput = output
41-
try:
42-
self.doStuff(command)
43-
return self.__outputBuffer
44-
except Exception as e:
45-
traceback.print_exc()
39+
self.doStuff(command)
40+
return self.__outputBuffer
4641

4742
def doStuff(self, command):
4843

@@ -113,33 +108,28 @@ def output_callback(data):
113108

114109
#logging.info("Task XML: {}".format(xml))
115110
taskCreated = False
116-
try:
117-
#logging.info('Creating task \\%s' % tmpName)
118-
tsch.hSchRpcRegisterTask(dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
119-
taskCreated = True
120-
121-
#logging.info('Running task \\%s' % tmpName)
122-
tsch.hSchRpcRun(dce, '\\%s' % tmpName)
123-
124-
done = False
125-
while not done:
126-
#logging.debug('Calling SchRpcGetLastRunInfo for \\%s' % tmpName)
127-
resp = tsch.hSchRpcGetLastRunInfo(dce, '\\%s' % tmpName)
128-
if resp['pLastRuntime']['wYear'] != 0:
129-
done = True
130-
else:
131-
sleep(2)
132-
133-
#logging.info('Deleting task \\%s' % tmpName)
111+
#logging.info('Creating task \\%s' % tmpName)
112+
tsch.hSchRpcRegisterTask(dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
113+
taskCreated = True
114+
115+
#logging.info('Running task \\%s' % tmpName)
116+
tsch.hSchRpcRun(dce, '\\%s' % tmpName)
117+
118+
done = False
119+
while not done:
120+
#logging.debug('Calling SchRpcGetLastRunInfo for \\%s' % tmpName)
121+
resp = tsch.hSchRpcGetLastRunInfo(dce, '\\%s' % tmpName)
122+
if resp['pLastRuntime']['wYear'] != 0:
123+
done = True
124+
else:
125+
sleep(2)
126+
127+
#logging.info('Deleting task \\%s' % tmpName)
128+
tsch.hSchRpcDelete(dce, '\\%s' % tmpName)
129+
taskCreated = False
130+
131+
if taskCreated is True:
134132
tsch.hSchRpcDelete(dce, '\\%s' % tmpName)
135-
taskCreated = False
136-
except tsch.DCERPCSessionError, e:
137-
traceback.print_exc()
138-
e.get_packet().dump()
139-
140-
finally:
141-
if taskCreated is True:
142-
tsch.hSchRpcDelete(dce, '\\%s' % tmpName)
143133

144134
peer = ':'.join(map(str, self.__rpctransport.get_socket().getpeername()))
145135
#self.__logger.success('Executed command via ATEXEC')

core/execmethods/smbexec.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import traceback
2-
31
from gevent import sleep
42
from impacket.dcerpc.v5 import transport, scmr
53
from impacket.smbconnection import *
@@ -58,11 +56,7 @@ def __init__(self, host, protocol, username = '', password = '', domain = '', ha
5856
#rpctransport.set_kerberos(self.__doKerberos)
5957

6058
self.__scmr = self.__rpctransport.get_dce_rpc()
61-
try:
62-
self.__scmr.connect()
63-
except Exception as e:
64-
traceback.print_exc()
65-
59+
self.__scmr.connect()
6660
s = self.__rpctransport.get_smb_connection()
6761
# We don't wanna deal with timeouts from now on.
6862
s.setTimeout(100000)
@@ -73,17 +67,14 @@ def __init__(self, host, protocol, username = '', password = '', domain = '', ha
7367
self.transferClient = self.__rpctransport.get_smb_connection()
7468

7569
def execute(self, command, output=False):
76-
self.__retOutput = output
77-
try:
78-
if self.__retOutput:
79-
self.cd('')
80-
81-
self.execute_remote(command)
82-
self.finish()
83-
return self.__outputBuffer
84-
except Exception as e:
85-
traceback.print_exc()
70+
self.__retOutput = output
71+
if self.__retOutput:
72+
self.cd('')
8673

74+
self.execute_remote(command)
75+
self.finish()
76+
return self.__outputBuffer
77+
8778
def cd(self, s):
8879
self.execute_remote('cd ' )
8980

core/execmethods/wmiexec.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import ntpath
2-
import traceback
32

43
from gevent import sleep
54
from core.helpers import gen_random_string
@@ -45,19 +44,14 @@ def __init__(self, target, username, password, domain, smbconnection, hashes=Non
4544

4645
def execute(self, command, output=False):
4746
self.__retOutput = output
48-
try:
49-
if self.__retOutput:
50-
self.__smbconnection.setTimeout(100000)
51-
self.cd('\\')
47+
if self.__retOutput:
48+
self.__smbconnection.setTimeout(100000)
49+
self.cd('\\')
5250

53-
self.execute_remote(command)
54-
self.__dcom.disconnect()
55-
return self.__outputBuffer
56-
except Exception as e:
57-
traceback.print_exc()
58-
self.__dcom.disconnect()
51+
self.execute_remote(command)
52+
self.__dcom.disconnect()
53+
return self.__outputBuffer
5954

60-
6155
def cd(self, s):
6256
self.execute_remote('cd ' + s)
6357
if len(self.__outputBuffer.strip('\r\n')) > 0:

crackmapexec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
sgroup.add_argument("--depth", type=int, default=10, help='Spider recursion depth (default: 10)')
108108

109109
cgroup = parser.add_argument_group("Command Execution", "Options for executing commands")
110-
cgroup.add_argument('--exec-method', choices={"wmiexec", "smbexec", "atexec"}, default="wmiexec", help="Method to execute the command. Ignored if in MSSQL mode (default: wmiexec)")
110+
cgroup.add_argument('--exec-method', choices={"wmiexec", "smbexec", "atexec"}, default=None, help="Method to execute the command. Ignored if in MSSQL mode (default: wmiexec)")
111111
cgroup.add_argument('--force-ps32', action='store_true', help='Force the PowerShell command to run in a 32-bit process')
112112
cgroup.add_argument('--no-output', action='store_true', dest='no_output', help='Do not retrieve command output')
113113
cgroup.add_argument("-x", metavar="COMMAND", dest='command', help="Execute the specified command")

0 commit comments

Comments
 (0)