rapid7/metasploit-framework

View on GitHub
modules/auxiliary/scanner/smb/impacket/wmiexec.py

Summary

Maintainability
D
2 days
Test Coverage
#!/usr/bin/env python3
# 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

try:
    from impacket.smbconnection import SessionError, SMBConnection, \
        SMB_DIALECT, SMB2_DIALECT_002, SMB2_DIALECT_21
    from impacket.dcerpc.v5.dcomrt import DCOMConnection, DCERPCSessionError
    from impacket.dcerpc.v5.dcom import wmi
    from impacket.dcerpc.v5.dtypes import NULL
except ImportError:
    dependencies_missing = True
else:
    dependencies_missing = False

import _msf_impacket
import metasploit.module as module

metadata = {
    'name': 'WMI Exec',
    'description': '''
        A similar approach to psexec but executing commands through WMI.
     ''',
    'authors': ['beto', 'Spencer McIntyre'],
    'date': '2018-03-19',
    'license': 'CORE_LICENSE',
    'references': [
        {'type': 'url', 'ref': 'https://github.com/CoreSecurity/impacket/blob/master/examples/wmiexec.py'}
     ],
    'type': 'single_scanner',
    'options': {
        'COMMAND':    {'type': 'string', 'description': 'The command to execute', 'required': True},
        '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': False, 'default': None},
        'SMBUser':    {'type': 'string', 'description': 'The username to authenticate as', 'required': True, 'default': None},
        'HASHES':     {'type': 'string', 'description': 'The NTLM hash to use for authentication, format: LMHASH:NTHASH', 'required': False, 'default': None}
    },
    'notes': {
        'AKA': ['wmiexec.py']
    }
}


class WMIEXEC:
    def __init__(self, command='', username='', password=None, domain='', hashes=None, share=None,
                 noOutput=False):
        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.shell = None
        if hashes is not None:
            self.__lmhash, self.__nthash = hashes.split(':')

    def run(self, addr):
        if not self.__password and not (self.__lmhash or self.__nthash):
            logging.error("Either SMBPass or HASHES must be set, aborting...")
            return

        if self.__noOutput is False:
            try:
                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")
            except SessionError as exc:
                logging.error(str(exc))
        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:
            iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
            iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
            iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
            iWbemLevel1Login.RemRelease()

            win32Process, _ = iWbemServices.GetObject('Win32_Process')

            self.shell = RemoteShell(self.__share, win32Process, smbConnection)
            if self.__command != ' ':
                self.shell.onecmd(self.__command)
            else:
                self.shell.cmdloop()
        except (DCERPCSessionError, Exception, KeyboardInterrupt) as exc:
            logging.error(str(exc))

        if smbConnection is not None:
            smbConnection.logoff()
        dcom.disconnect()


class RemoteShell(_msf_impacket.RemoteShell):
    def __init__(self, share, win32Process, smbConnection):
        self.__win32Process = win32Process
        self._pwd = 'C:\\'
        self._shell = 'cmd.exe /Q /c '
        super(RemoteShell, self).__init__(share, smbConnection)

    def execute_remote(self, data):
        command = self._shell + data
        if self._noOutput is False:
            command += ' 1> ' + '\\\\127.0.0.1\\%s' % self._share + self._output  + ' 2>&1'
        self.__win32Process.Create(command, self._pwd, None)
        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 = WMIEXEC(args['COMMAND'], args['SMBUser'], args['SMBPass'], args['SMBDomain'], 
                        hashes=args['HASHES'], share='ADMIN$', noOutput=args['OUTPUT'] != 'true')
    executer.run(args['rhost'])

if __name__ == "__main__":
    module.run(metadata, run)