Skip to content

Commit 25c62f6

Browse files
authored
Merge pull request #1088 from SecureAuthCorp/pr-605-catchup
Add silent command
2 parents 8aa5626 + be3d990 commit 25c62f6

3 files changed

Lines changed: 138 additions & 100 deletions

File tree

examples/atexec.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
class TSCH_EXEC:
3939
def __init__(self, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, kdcHost=None,
40-
command=None, sessionId=None):
40+
command=None, sessionId=None, silentCommand=False):
4141
self.__username = username
4242
self.__password = password
4343
self.__domain = domain
@@ -47,6 +47,7 @@ def __init__(self, username='', password='', domain='', hashes=None, aesKey=None
4747
self.__doKerberos = doKerberos
4848
self.__kdcHost = kdcHost
4949
self.__command = command
50+
self.__silentCommand = silentCommand
5051
self.sessionId = sessionId
5152

5253
if hashes is not None:
@@ -157,7 +158,8 @@ def cmd_split(cmdline):
157158
</Exec>
158159
</Actions>
159160
</Task>
160-
""" % (xml_escape(cmd), xml_escape(args))
161+
""" % ((xml_escape(cmd) if self.__silentCommand is False else self.__command.split()[0]),
162+
(xml_escape(args) if self.__silentCommand is False else " ".join(self.__command.split()[1:])))
161163
taskCreated = False
162164
try:
163165
logging.info('Creating task \\%s' % tmpName)
@@ -201,6 +203,10 @@ def cmd_split(cmdline):
201203
dce.disconnect()
202204
return
203205

206+
if self.__silentCommand:
207+
dce.disconnect()
208+
return
209+
204210
smbConnection = rpctransport.get_smb_connection()
205211
waitOnce = True
206212
while True:
@@ -222,7 +228,7 @@ def cmd_split(cmdline):
222228
raise
223229
logging.debug('Deleting file ADMIN$\\Temp\\%s' % tmpFileName)
224230
smbConnection.deleteFile('ADMIN$', 'Temp\\%s' % tmpFileName)
225-
231+
226232
dce.disconnect()
227233

228234

@@ -235,8 +241,9 @@ def cmd_split(cmdline):
235241
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
236242
parser.add_argument('command', action='store', nargs='*', default=' ', help='command to execute at the target ')
237243
parser.add_argument('-session-id', action='store', type=int, help='an existed logon session to use (no output, no cmd.exe)')
238-
239244
parser.add_argument('-ts', action='store_true', help='adds timestamp to every logging output')
245+
parser.add_argument('-silentcommand', action='store_true', default = False, help='does not execute cmd.exe to run '
246+
'given command (no output)')
240247
parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
241248
parser.add_argument('-codec', action='store', help='Sets encoding used (codec) from the target\'s output (default '
242249
'"%s"). If errors are detected, run chcp.com at the target, '
@@ -303,5 +310,5 @@ def cmd_split(cmdline):
303310
options.k = True
304311

305312
atsvc_exec = TSCH_EXEC(username, password, domain, options.hashes, options.aesKey, options.k, options.dc_ip,
306-
' '.join(options.command), options.session_id)
313+
' '.join(options.command), options.session_id, options.silentcommand)
307314
atsvc_exec.play(address)

examples/dcomexec.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def getInterface(self, interface, resp):
9898
oxid=objRef['std']['oxid'], oid=objRef['std']['oxid'],
9999
target=interface.get_target()))
100100

101-
def run(self, addr):
102-
if self.__noOutput is False:
101+
def run(self, addr, silentCommand=False):
102+
if self.__noOutput is False and silentCommand is False:
103103
smbConnection = SMBConnection(addr, addr)
104104
if self.__doKerberos is False:
105105
smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
@@ -163,17 +163,21 @@ def run(self, addr):
163163

164164
iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
165165
pExecuteShellCommand = iActiveView.GetIDsOfNames(('ExecuteShellCommand',))[0]
166-
self.shell = RemoteShellMMC20(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection, self.__shell_type)
166+
self.shell = RemoteShellMMC20(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection, self.__shell_type, silentCommand)
167167
else:
168168
resp = iDocument.GetIDsOfNames(('Application',))
169169
resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
170170

171171
iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
172172
pExecuteShellCommand = iActiveView.GetIDsOfNames(('ShellExecute',))[0]
173-
self.shell = RemoteShell(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection, self.__shell_type)
173+
self.shell = RemoteShell(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection, self.__shell_type, silentCommand)
174174

175175
if self.__command != ' ':
176-
self.shell.onecmd(self.__command)
176+
try:
177+
self.shell.onecmd(self.__command)
178+
except TypeError:
179+
if not silentCommand:
180+
raise
177181
if self.shell is not None:
178182
self.shell.do_exit('')
179183
else:
@@ -196,7 +200,7 @@ def run(self, addr):
196200
dcom.disconnect()
197201

198202
class RemoteShell(cmd.Cmd):
199-
def __init__(self, share, quit, executeShellCommand, smbConnection, shell_type):
203+
def __init__(self, share, quit, executeShellCommand, smbConnection, shell_type, silentCommand=False):
200204
cmd.Cmd.__init__(self)
201205
self._share = share
202206
self._output = '\\' + OUTPUT_FILENAME
@@ -207,6 +211,7 @@ def __init__(self, share, quit, executeShellCommand, smbConnection, shell_type):
207211
self.__quit = quit
208212
self._executeShellCommand = executeShellCommand
209213
self.__transferClient = smbConnection
214+
self._silentCommand = silentCommand
210215
self._pwd = 'C:\\windows\\system32'
211216
self._noOutput = False
212217
self.intro = '[!] Launching semi-interactive shell - Careful what you execute\n[!] Press help for extra shell commands'
@@ -365,11 +370,15 @@ def output_callback(data):
365370
self.__transferClient.deleteFile(self._share, self._output)
366371

367372
def execute_remote(self, data, shell_type='cmd'):
368-
if shell_type == 'powershell':
369-
data = '$ProgressPreference="SilentlyContinue";' + data
370-
data = self.__pwsh + b64encode(data.encode('utf-16le')).decode()
373+
if self._silentCommand is True:
374+
self._shell = data.split()[0]
375+
command = ' '.join(data.split()[1:])
376+
else:
377+
if shell_type == 'powershell':
378+
data = '$ProgressPreference="SilentlyContinue";' + data
379+
data = self.__pwsh + b64encode(data.encode('utf-16le')).decode()
380+
command = '/Q /c ' + data
371381

372-
command = '/Q /c ' + data
373382
if self._noOutput is False:
374383
command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output + ' 2>&1'
375384

@@ -430,11 +439,15 @@ def send_data(self, data):
430439

431440
class RemoteShellMMC20(RemoteShell):
432441
def execute_remote(self, data, shell_type='cmd'):
433-
if shell_type == 'powershell':
434-
data = '$ProgressPreference="SilentlyContinue";' + data
435-
data = self._RemoteShell__pwsh + b64encode(data.encode('utf-16le')).decode()
442+
if self._silentCommand is True:
443+
self._shell = data.split()[0]
444+
command = ' '.join(data.split()[1:])
445+
else:
446+
if shell_type == 'powershell':
447+
data = '$ProgressPreference="SilentlyContinue";' + data
448+
data = self._RemoteShell__pwsh + b64encode(data.encode('utf-16le')).decode()
449+
command = '/Q /c ' + data
436450

437-
command = '/Q /c ' + data
438451
if self._noOutput is False:
439452
command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output + ' 2>&1'
440453

@@ -532,6 +545,7 @@ def load_smbclient_auth_file(path):
532545

533546
parser = argparse.ArgumentParser(add_help = True, description = "Executes a semi-interactive shell using the "
534547
"ShellBrowserWindow DCOM object.")
548+
535549
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
536550
parser.add_argument('-share', action='store', default = 'ADMIN$', help='share where the output will be grabbed from '
537551
'(default ADMIN$)')
@@ -548,12 +562,12 @@ def load_smbclient_auth_file(path):
548562
help='DCOM object to be used to execute the shell command (default=ShellWindows)')
549563
parser.add_argument('-com-version', action='store', metavar = "MAJOR_VERSION:MINOR_VERSION", help='DCOM version, '
550564
'format is MAJOR_VERSION:MINOR_VERSION e.g. 5.7')
551-
552565
parser.add_argument('-shell-type', action='store', default = 'cmd', choices = ['cmd', 'powershell'], help='choose '
553566
'a command processor for the semi-interactive shell')
554-
555567
parser.add_argument('command', nargs='*', default = ' ', help='command to execute at the target. If empty it will '
556568
'launch a semi-interactive shell')
569+
parser.add_argument('-silentcommand', action='store_true', default = False,
570+
help='does not execute cmd.exe to run given command (no output, cannot run dir/cd/etc.)')
557571

558572
group = parser.add_argument_group('authentication')
559573

@@ -588,6 +602,9 @@ def load_smbclient_auth_file(path):
588602
if ' '.join(options.command) == ' ' and options.nooutput is True:
589603
logging.error("-nooutput switch and interactive shell not supported")
590604
sys.exit(1)
605+
if options.silentcommand and options.command == ' ':
606+
logging.error("-silentcommand switch and interactive shell not supported")
607+
sys.exit(1)
591608

592609
if options.debug is True:
593610
logging.getLogger().setLevel(logging.DEBUG)
@@ -627,7 +644,7 @@ def load_smbclient_auth_file(path):
627644

628645
executer = DCOMEXEC(' '.join(options.command), username, password, domain, options.hashes, options.aesKey,
629646
options.share, options.nooutput, options.k, options.dc_ip, options.object, options.shell_type)
630-
executer.run(address)
647+
executer.run(address, options.silentcommand)
631648
except (Exception, KeyboardInterrupt) as e:
632649
if logging.getLogger().level == logging.DEBUG:
633650
import traceback

0 commit comments

Comments
 (0)