Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hashes option and better error handling to wmiexec #17145

Merged
merged 1 commit into from
Nov 18, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 35 additions & 25 deletions modules/auxiliary/scanner/smb/impacket/wmiexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import sys

try:
from impacket.smbconnection import SMBConnection, SMB_DIALECT, \
SMB2_DIALECT_002, SMB2_DIALECT_21
from impacket.dcerpc.v5.dcomrt import DCOMConnection
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:
Expand All @@ -41,8 +41,9 @@
'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': True, 'default': None},
'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']
Expand All @@ -51,7 +52,7 @@


class WMIEXEC:
def __init__(self, command='', username='', password='', domain='', hashes=None, share=None,
def __init__(self, command='', username='', password=None, domain='', hashes=None, share=None,
noOutput=False):
self.__command = command
self.__username = username
Expand All @@ -65,25 +66,34 @@ def __init__(self, command='', username='', password='', domain='', hashes=None,
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:
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")
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

Expand All @@ -102,8 +112,8 @@ def run(self, addr):
self.shell.onecmd(self.__command)
else:
self.shell.cmdloop()
except (Exception, KeyboardInterrupt) as e:
logging.error(str(e))
except (DCERPCSessionError, Exception, KeyboardInterrupt) as exc:
logging.error(str(exc))

if smbConnection is not None:
smbConnection.logoff()
Expand Down Expand Up @@ -131,8 +141,8 @@ def run(args):
return

_msf_impacket.pre_run_hook(args)
executer = WMIEXEC(args['COMMAND'], args['SMBUser'], args['SMBPass'], args['SMBDomain'],
share='ADMIN$', noOutput=args['OUTPUT'] != 'true')
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__":
Expand Down