예제 #1
0
    def initialize(self):
        LOG.info("Monkey is initializing...")

        if not self._singleton.try_lock():
            raise Exception(
                "Another instance of the monkey is already running")

        arg_parser = argparse.ArgumentParser()
        arg_parser.add_argument('-p', '--parent')
        arg_parser.add_argument('-t', '--tunnel')
        arg_parser.add_argument('-s', '--server')
        arg_parser.add_argument('-d', '--depth')
        opts, self._args = arg_parser.parse_known_args(self._args)

        self._parent = opts.parent
        self._default_tunnel = opts.tunnel
        self._default_server = opts.server
        if opts.depth:
            WormConfiguration.depth = int(opts.depth)
            WormConfiguration._depth_from_commandline = True
        self._keep_running = True
        self._network = NetworkScanner()
        self._dropper_path = sys.argv[0]

        if self._default_server:
            if self._default_server not in WormConfiguration.command_servers:
                LOG.debug("Added default server: %s" % self._default_server)
                WormConfiguration.command_servers.insert(
                    0, self._default_server)
            else:
                LOG.debug(
                    "Default server: %s is already in command servers list" %
                    self._default_server)
예제 #2
0
파일: monkey.py 프로젝트: 0x0mar/monkey
    def initialize(self):
        LOG.info("Monkey is initializing...")

        if not self._singleton.try_lock():
            raise Exception("Another instance of the monkey is already running")

        arg_parser = argparse.ArgumentParser()
        arg_parser.add_argument('-p', '--parent')
        arg_parser.add_argument('-t', '--tunnel')
        arg_parser.add_argument('-s', '--server')
        arg_parser.add_argument('-d', '--depth')
        opts, self._args = arg_parser.parse_known_args(self._args)

        self._parent = opts.parent
        self._default_tunnel = opts.tunnel
        self._default_server = opts.server
        if opts.depth:
            WormConfiguration.depth = int(opts.depth)
            WormConfiguration._depth_from_commandline = True
        self._keep_running = True
        self._network = NetworkScanner()
        self._dropper_path = sys.argv[0]

        if self._default_server:
            if self._default_server not in WormConfiguration.command_servers:
                LOG.debug("Added default server: %s" % self._default_server)
                WormConfiguration.command_servers.insert(0, self._default_server)
            else:
                LOG.debug("Default server: %s is already in command servers list" % self._default_server)
예제 #3
0
class ChaosMonkey(object):
    def __init__(self, args):
        self._keep_running = False
        self._exploited_machines = set()
        self._fail_exploitation_machines = set()
        self._singleton = SystemSingleton()
        self._parent = None
        self._default_tunnel = None
        self._args = args
        self._network = None
        self._dropper_path = None
        self._exploiters = None
        self._fingerprint = None
        self._default_server = None
        self._depth = 0

    def initialize(self):
        LOG.info("Monkey is initializing...")

        if not self._singleton.try_lock():
            raise Exception(
                "Another instance of the monkey is already running")

        arg_parser = argparse.ArgumentParser()
        arg_parser.add_argument('-p', '--parent')
        arg_parser.add_argument('-t', '--tunnel')
        arg_parser.add_argument('-s', '--server')
        arg_parser.add_argument('-d', '--depth')
        opts, self._args = arg_parser.parse_known_args(self._args)

        self._parent = opts.parent
        self._default_tunnel = opts.tunnel
        self._default_server = opts.server
        if opts.depth:
            WormConfiguration.depth = int(opts.depth)
            WormConfiguration._depth_from_commandline = True
        self._keep_running = True
        self._network = NetworkScanner()
        self._dropper_path = sys.argv[0]

        if self._default_server:
            if self._default_server not in WormConfiguration.command_servers:
                LOG.debug("Added default server: %s" % self._default_server)
                WormConfiguration.command_servers.insert(
                    0, self._default_server)
            else:
                LOG.debug(
                    "Default server: %s is already in command servers list" %
                    self._default_server)

    def start(self):
        LOG.info("Monkey is running...")

        if firewall.is_enabled():
            firewall.add_firewall_rule()
        ControlClient.wakeup(parent=self._parent,
                             default_tunnel=self._default_tunnel)
        ControlClient.load_control_config()

        if not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")
            return

        monkey_tunnel = ControlClient.create_control_tunnel()
        if monkey_tunnel:
            monkey_tunnel.start()

        last_exploit_time = None

        ControlClient.send_telemetry("state", {'done': False})

        self._default_server = WormConfiguration.current_server
        LOG.debug("default server: %s" % self._default_server)
        ControlClient.send_telemetry("tunnel",
                                     ControlClient.proxies.get('https'))

        if WormConfiguration.collect_system_info:
            LOG.debug("Calling system info collection")
            system_info_collector = SystemInfoCollector()
            system_info = system_info_collector.get_info()
            ControlClient.send_telemetry("system_info_collection", system_info)

        if 0 == WormConfiguration.depth:
            LOG.debug("Reached max depth, shutting down")
            ControlClient.send_telemetry("trace",
                                         "Reached max depth, shutting down")
            return
        else:
            LOG.debug("Running with depth: %d" % WormConfiguration.depth)

        for _ in xrange(WormConfiguration.max_iterations):
            ControlClient.keepalive()
            ControlClient.load_control_config()

            self._network.initialize()

            self._exploiters = [
                exploiter()
                for exploiter in WormConfiguration.exploiter_classes
            ]

            self._fingerprint = [
                fingerprint()
                for fingerprint in WormConfiguration.finger_classes
            ]

            if not self._keep_running or not WormConfiguration.alive:
                break

            machines = self._network.get_victim_machines(
                WormConfiguration.scanner_class,
                max_find=WormConfiguration.victims_max_find,
                stop_callback=ControlClient.check_for_stop)
            is_empty = True
            for machine in machines:
                if ControlClient.check_for_stop():
                    break

                is_empty = False
                for finger in self._fingerprint:
                    LOG.info(
                        "Trying to get OS fingerprint from %r with module %s",
                        machine, finger.__class__.__name__)
                    finger.get_host_fingerprint(machine)

                ControlClient.send_telemetry(
                    'scan', {
                        'machine': machine.as_dict(),
                        'scanner': WormConfiguration.scanner_class.__name__
                    })

                # skip machines that we've already exploited
                if machine in self._exploited_machines:
                    LOG.debug("Skipping %r - already exploited", machine)
                    continue
                elif machine in self._fail_exploitation_machines:
                    if WormConfiguration.retry_failed_explotation:
                        LOG.debug(
                            "%r - exploitation failed before, trying again",
                            machine)
                    else:
                        LOG.debug("Skipping %r - exploitation failed before",
                                  machine)
                        continue

                if monkey_tunnel:
                    monkey_tunnel.set_tunnel_for_host(machine)
                if self._default_server:
                    LOG.debug("Default server: %s set to machine: %r" %
                              (self._default_server, machine))
                    machine.set_default_server(self._default_server)

                successful_exploiter = None
                for exploiter in self._exploiters:
                    if not exploiter.is_os_supported(machine):
                        LOG.info(
                            "Skipping exploiter %s host:%r, os is not supported",
                            exploiter.__class__.__name__, machine)
                        continue

                    LOG.info("Trying to exploit %r with exploiter %s...",
                             machine, exploiter.__class__.__name__)

                    try:
                        if exploiter.exploit_host(machine,
                                                  WormConfiguration.depth):
                            successful_exploiter = exploiter
                            break
                        else:
                            LOG.info("Failed exploiting %r with exploiter %s",
                                     machine, exploiter.__class__.__name__)
                            ControlClient.send_telemetry(
                                'exploit', {
                                    'result': False,
                                    'machine': machine.__dict__,
                                    'exploiter': exploiter.__class__.__name__
                                })

                    except Exception, exc:
                        LOG.error("Exception while attacking %s using %s: %s",
                                  machine, exploiter.__class__.__name__, exc)
                        continue

                if successful_exploiter:
                    self._exploited_machines.add(machine)
                    last_exploit_time = time.time()
                    ControlClient.send_telemetry(
                        'exploit', {
                            'result': True,
                            'machine': machine.__dict__,
                            'exploiter':
                            successful_exploiter.__class__.__name__
                        })

                    LOG.info("Successfully propagated to %s using %s", machine,
                             successful_exploiter.__class__.__name__)

                    # check if max-exploitation limit is reached
                    if WormConfiguration.victims_max_exploit <= len(
                            self._exploited_machines):
                        self._keep_running = False

                        LOG.info("Max exploited victims reached (%d)",
                                 WormConfiguration.victims_max_exploit)
                        break
                else:
                    self._fail_exploitation_machines.add(machine)

            if not is_empty:
                time.sleep(WormConfiguration.timeout_between_iterations)

        if self._keep_running and WormConfiguration.alive:
            LOG.info("Reached max iterations (%d)",
                     WormConfiguration.max_iterations)
        elif not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")

        # if host was exploited, before continue to closing the tunnel ensure the exploited host had its chance to
        # connect to the tunnel
        if last_exploit_time and (time.time() - last_exploit_time < 60):
            time.sleep(time.time() - last_exploit_time)

        if monkey_tunnel:
            monkey_tunnel.stop()
            monkey_tunnel.join()
예제 #4
0
from network.network_scanner import NetworkScanner

def nmap_result_callback(hosts):
    print("scan finished")
    for host in hosts:
        print("Found host", host.ip_address, "with MAC address", host.mac_address)
        print("  ports: ")
        for port in host.ports:
            print("    ", port.port_id, port.protocol, port.service)


scanner = NetworkScanner.create()

network_interfaces = scanner.get_network_interfaces()

print("Found network interfaces:", network_interfaces)

nif = network_interfaces[0]

scanner.scan_network_callback(nif, nmap_result_callback, port_scan=False)
print("Network scan started asynchronously")
print(nif.get_nmap_arg())
예제 #5
0
파일: monkey.py 프로젝트: 0x0mar/monkey
class ChaosMonkey(object):
    def __init__(self, args):
        self._keep_running = False
        self._exploited_machines = set()
        self._fail_exploitation_machines = set()
        self._singleton = SystemSingleton()
        self._parent = None
        self._default_tunnel = None
        self._args = args
        self._network = None
        self._dropper_path = None
        self._exploiters = None
        self._fingerprint = None
        self._default_server = None
        self._depth = 0

    def initialize(self):
        LOG.info("Monkey is initializing...")

        if not self._singleton.try_lock():
            raise Exception("Another instance of the monkey is already running")

        arg_parser = argparse.ArgumentParser()
        arg_parser.add_argument('-p', '--parent')
        arg_parser.add_argument('-t', '--tunnel')
        arg_parser.add_argument('-s', '--server')
        arg_parser.add_argument('-d', '--depth')
        opts, self._args = arg_parser.parse_known_args(self._args)

        self._parent = opts.parent
        self._default_tunnel = opts.tunnel
        self._default_server = opts.server
        if opts.depth:
            WormConfiguration.depth = int(opts.depth)
            WormConfiguration._depth_from_commandline = True
        self._keep_running = True
        self._network = NetworkScanner()
        self._dropper_path = sys.argv[0]

        if self._default_server:
            if self._default_server not in WormConfiguration.command_servers:
                LOG.debug("Added default server: %s" % self._default_server)
                WormConfiguration.command_servers.insert(0, self._default_server)
            else:
                LOG.debug("Default server: %s is already in command servers list" % self._default_server)

    def start(self):
        LOG.info("Monkey is running...")

        if firewall.is_enabled():
            firewall.add_firewall_rule()
        ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel)
        ControlClient.load_control_config()

        if not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")
            return

        monkey_tunnel = ControlClient.create_control_tunnel()
        if monkey_tunnel:
            monkey_tunnel.start()

        ControlClient.send_telemetry("state", {'done': False})

        self._default_server = WormConfiguration.current_server
        LOG.debug("default server: %s" % self._default_server)
        ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https'))

        if WormConfiguration.collect_system_info:
            LOG.debug("Calling system info collection")
            system_info_collector = SystemInfoCollector()
            system_info = system_info_collector.get_info()
            ControlClient.send_telemetry("system_info_collection", system_info)

        if 0 == WormConfiguration.depth:
            LOG.debug("Reached max depth, shutting down")
            ControlClient.send_telemetry("trace", "Reached max depth, shutting down")
            return
        else:
            LOG.debug("Running with depth: %d" % WormConfiguration.depth)

        for _ in xrange(WormConfiguration.max_iterations):
            ControlClient.keepalive()
            ControlClient.load_control_config()

            self._network.initialize()

            self._exploiters = [exploiter() for exploiter in WormConfiguration.exploiter_classes]

            self._fingerprint = [fingerprint() for fingerprint in WormConfiguration.finger_classes]

            if not self._keep_running or not WormConfiguration.alive:
                break

            machines = self._network.get_victim_machines(WormConfiguration.scanner_class,
                                                         max_find=WormConfiguration.victims_max_find,
                                                         stop_callback=ControlClient.check_for_stop)
            is_empty = True
            for machine in machines:
                if ControlClient.check_for_stop():
                    break

                is_empty = False
                for finger in self._fingerprint:
                    LOG.info("Trying to get OS fingerprint from %r with module %s",
                             machine, finger.__class__.__name__)
                    finger.get_host_fingerprint(machine)

                ControlClient.send_telemetry('scan', {'machine': machine.as_dict(),
                                                      'scanner': WormConfiguration.scanner_class.__name__})

                # skip machines that we've already exploited
                if machine in self._exploited_machines:
                    LOG.debug("Skipping %r - already exploited",
                              machine)
                    continue
                elif machine in self._fail_exploitation_machines:
                    if WormConfiguration.retry_failed_explotation:
                        LOG.debug("%r - exploitation failed before, trying again", machine)
                    else:
                        LOG.debug("Skipping %r - exploitation failed before", machine)
                        continue

                successful_exploiter = None

                if monkey_tunnel:
                    monkey_tunnel.set_tunnel_for_host(machine)
                if self._default_server:
                    LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine))
                    machine.set_default_server(self._default_server)

                for exploiter in self._exploiters:
                    if not exploiter.is_os_supported(machine):
                        LOG.info("Skipping exploiter %s host:%r, os is not supported",
                                 exploiter.__class__.__name__, machine)
                        continue

                    LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__)

                    try:
                        if exploiter.exploit_host(machine, WormConfiguration.depth):
                            successful_exploiter = exploiter
                            break
                        else:
                            LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__)
                            ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__,
                                                                     'exploiter': exploiter.__class__.__name__})

                    except Exception, exc:
                        LOG.error("Exception while attacking %s using %s: %s",
                                  machine, exploiter.__class__.__name__, exc)
                        continue

                if successful_exploiter:
                    self._exploited_machines.add(machine)
                    ControlClient.send_telemetry('exploit', {'result': True, 'machine': machine.__dict__,
                                                             'exploiter': successful_exploiter.__class__.__name__})

                    LOG.info("Successfully propagated to %s using %s",
                             machine, successful_exploiter.__class__.__name__)

                    # check if max-exploitation limit is reached
                    if WormConfiguration.victims_max_exploit <= len(self._exploited_machines):
                        self._keep_running = False

                        LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit)
                        break
                else:
                    self._fail_exploitation_machines.add(machine)

            if not is_empty:
                time.sleep(WormConfiguration.timeout_between_iterations)

        if self._keep_running and WormConfiguration.alive:
            LOG.info("Reached max iterations (%d)", WormConfiguration.max_iterations)
        elif not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")

        if monkey_tunnel:
            monkey_tunnel.stop()
            monkey_tunnel.join()
예제 #6
0
class ChaosMonkey(object):
    def __init__(self, args):
        self._keep_running = False
        self._exploited_machines = set()
        self._fail_exploitation_machines = set()
        self._singleton = SystemSingleton()
        self._parent = None
        self._default_tunnel = None
        self._args = args
        self._network = None
        self._dropper_path = None
        self._exploiters = None
        self._fingerprint = None
        self._default_server = None
        self._depth = 0

    def initialize(self):
        LOG.info("Monkey is initializing...")

        if not self._singleton.try_lock():
            raise Exception(
                "Another instance of the monkey is already running")

        arg_parser = argparse.ArgumentParser()
        arg_parser.add_argument('-p', '--parent')
        arg_parser.add_argument('-t', '--tunnel')
        arg_parser.add_argument('-s', '--server')
        arg_parser.add_argument('-d', '--depth')
        opts, self._args = arg_parser.parse_known_args(self._args)

        self._parent = opts.parent
        self._default_tunnel = opts.tunnel
        self._default_server = opts.server
        if opts.depth:
            WormConfiguration.depth = int(opts.depth)
            WormConfiguration._depth_from_commandline = True
        self._keep_running = True
        self._network = NetworkScanner()
        self._dropper_path = sys.argv[0]

        if self._default_server:
            if self._default_server not in WormConfiguration.command_servers:
                LOG.debug("Added default server: %s" % self._default_server)
                WormConfiguration.command_servers.insert(
                    0, self._default_server)
            else:
                LOG.debug(
                    "Default server: %s is already in command servers list" %
                    self._default_server)

    def start(self):
        LOG.info("Monkey is running...")

        if firewall.is_enabled():
            firewall.add_firewall_rule()
        ControlClient.wakeup(parent=self._parent,
                             default_tunnel=self._default_tunnel)
        ControlClient.load_control_config()

        if not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")
            return

        monkey_tunnel = ControlClient.create_control_tunnel()
        if monkey_tunnel:
            monkey_tunnel.start()

        ControlClient.send_telemetry("state", {'done': False})

        self._default_server = WormConfiguration.current_server
        LOG.debug("default server: %s" % self._default_server)
        ControlClient.send_telemetry(
            "tunnel", {'proxy': ControlClient.proxies.get('https')})

        if WormConfiguration.collect_system_info:
            LOG.debug("Calling system info collection")
            system_info_collector = SystemInfoCollector()
            system_info = system_info_collector.get_info()
            ControlClient.send_telemetry("system_info_collection", system_info)

        if 0 == WormConfiguration.depth:
            LOG.debug("Reached max depth, shutting down")
            ControlClient.send_telemetry("trace",
                                         "Reached max depth, shutting down")
            return
        else:
            LOG.debug("Running with depth: %d" % WormConfiguration.depth)

        for iteration_index in xrange(WormConfiguration.max_iterations):
            ControlClient.keepalive()
            ControlClient.load_control_config()

            LOG.debug("Users to try: %s" %
                      str(WormConfiguration.exploit_user_list))
            LOG.debug("Passwords to try: %s" %
                      str(WormConfiguration.exploit_password_list))

            self._network.initialize()

            self._exploiters = WormConfiguration.exploiter_classes

            self._fingerprint = [
                fingerprint()
                for fingerprint in WormConfiguration.finger_classes
            ]

            if not self._keep_running or not WormConfiguration.alive:
                break

            machines = self._network.get_victim_machines(
                WormConfiguration.scanner_class,
                max_find=WormConfiguration.victims_max_find,
                stop_callback=ControlClient.check_for_stop)
            is_empty = True
            for machine in machines:
                if ControlClient.check_for_stop():
                    break

                is_empty = False
                for finger in self._fingerprint:
                    LOG.info(
                        "Trying to get OS fingerprint from %r with module %s",
                        machine, finger.__class__.__name__)
                    finger.get_host_fingerprint(machine)

                ControlClient.send_telemetry(
                    'scan', {
                        'machine': machine.as_dict(),
                        'scanner': WormConfiguration.scanner_class.__name__
                    })

                # skip machines that we've already exploited
                if machine in self._exploited_machines:
                    LOG.debug("Skipping %r - already exploited", machine)
                    continue
                elif machine in self._fail_exploitation_machines:
                    if WormConfiguration.retry_failed_explotation:
                        LOG.debug(
                            "%r - exploitation failed before, trying again",
                            machine)
                    else:
                        LOG.debug("Skipping %r - exploitation failed before",
                                  machine)
                        continue

                if monkey_tunnel:
                    monkey_tunnel.set_tunnel_for_host(machine)
                if self._default_server:
                    LOG.debug("Default server: %s set to machine: %r" %
                              (self._default_server, machine))
                    machine.set_default_server(self._default_server)

                successful_exploiter = None
                for exploiter in [
                        exploiter(machine) for exploiter in self._exploiters
                ]:
                    if not exploiter.is_os_supported():
                        LOG.info(
                            "Skipping exploiter %s host:%r, os is not supported",
                            exploiter.__class__.__name__, machine)
                        continue

                    LOG.info("Trying to exploit %r with exploiter %s...",
                             machine, exploiter.__class__.__name__)

                    result = False
                    try:
                        result = exploiter.exploit_host()
                        if result:
                            successful_exploiter = exploiter
                            break
                        else:
                            LOG.info("Failed exploiting %r with exploiter %s",
                                     machine, exploiter.__class__.__name__)

                    except Exception as exc:
                        LOG.exception(
                            "Exception while attacking %s using %s: %s",
                            machine, exploiter.__class__.__name__, exc)
                    finally:
                        exploiter.send_exploit_telemetry(result)

                if successful_exploiter:
                    self._exploited_machines.add(machine)

                    LOG.info("Successfully propagated to %s using %s", machine,
                             successful_exploiter.__class__.__name__)

                    # check if max-exploitation limit is reached
                    if WormConfiguration.victims_max_exploit <= len(
                            self._exploited_machines):
                        self._keep_running = False

                        LOG.info("Max exploited victims reached (%d)",
                                 WormConfiguration.victims_max_exploit)
                        break
                else:
                    self._fail_exploitation_machines.add(machine)

            if (not is_empty) and (WormConfiguration.max_iterations >
                                   iteration_index + 1):
                time_to_sleep = WormConfiguration.timeout_between_iterations
                LOG.info(
                    "Sleeping %d seconds before next life cycle iteration",
                    time_to_sleep)
                time.sleep(time_to_sleep)

        if self._keep_running and WormConfiguration.alive:
            LOG.info("Reached max iterations (%d)",
                     WormConfiguration.max_iterations)
        elif not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")

        # if host was exploited, before continue to closing the tunnel ensure the exploited host had its chance to
        # connect to the tunnel
        if len(self._exploited_machines) > 0:
            time_to_sleep = WormConfiguration.keep_tunnel_open_time
            LOG.info(
                "Sleeping %d seconds for exploited machines to connect to tunnel",
                time_to_sleep)
            time.sleep(time_to_sleep)

        if monkey_tunnel:
            monkey_tunnel.stop()
            monkey_tunnel.join()

    def cleanup(self):
        LOG.info("Monkey cleanup started")
        self._keep_running = False

        # Signal the server (before closing the tunnel)
        ControlClient.send_telemetry("state", {'done': True})

        # Close tunnel
        tunnel_address = ControlClient.proxies.get('https', '').replace(
            'https://', '').split(':')[0]
        if tunnel_address:
            LOG.info("Quitting tunnel %s", tunnel_address)
            tunnel.quit_tunnel(tunnel_address)

        firewall.close()

        self._singleton.unlock()

        if WormConfiguration.self_delete_in_cleanup and -1 == sys.executable.find(
                'python'):
            try:
                if "win32" == sys.platform:
                    from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
                    startupinfo = subprocess.STARTUPINFO()
                    startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW
                    startupinfo.wShowWindow = SW_HIDE
                    subprocess.Popen(DELAY_DELETE_CMD %
                                     {'file_path': sys.executable},
                                     stdin=None,
                                     stdout=None,
                                     stderr=None,
                                     close_fds=True,
                                     startupinfo=startupinfo)
                else:
                    os.remove(sys.executable)
            except Exception as exc:
                LOG.error("Exception in self delete: %s", exc)

        LOG.info("Monkey is shutting down")
예제 #7
0
파일: monkey.py 프로젝트: subkanthi/monkey
class InfectionMonkey(object):
    def __init__(self, args):
        self._keep_running = False
        self._exploited_machines = set()
        self._fail_exploitation_machines = set()
        self._singleton = SystemSingleton()
        self._parent = None
        self._default_tunnel = None
        self._args = args
        self._network = None
        self._dropper_path = None
        self._exploiters = None
        self._fingerprint = None
        self._default_server = None
        self._depth = 0
        self._opts = None
        self._upgrading_to_64 = False

    def initialize(self):
        LOG.info("Monkey is initializing...")

        if not self._singleton.try_lock():
            raise Exception("Another instance of the monkey is already running")

        arg_parser = argparse.ArgumentParser()
        arg_parser.add_argument('-p', '--parent')
        arg_parser.add_argument('-t', '--tunnel')
        arg_parser.add_argument('-s', '--server')
        arg_parser.add_argument('-d', '--depth', type=int)
        self._opts, self._args = arg_parser.parse_known_args(self._args)

        self._parent = self._opts.parent
        self._default_tunnel = self._opts.tunnel
        self._default_server = self._opts.server
        if self._opts.depth:
            WormConfiguration._depth_from_commandline = True
        self._keep_running = True
        self._network = NetworkScanner()
        self._dropper_path = sys.argv[0]

        if self._default_server:
            if self._default_server not in WormConfiguration.command_servers:
                LOG.debug("Added default server: %s" % self._default_server)
                WormConfiguration.command_servers.insert(0, self._default_server)
            else:
                LOG.debug("Default server: %s is already in command servers list" % self._default_server)

    def start(self):
        LOG.info("Monkey is running...")

        if not ControlClient.find_server(default_tunnel=self._default_tunnel):
            LOG.info("Monkey couldn't find server. Going down.")
            return

        if WindowsUpgrader.should_upgrade():
            self._upgrading_to_64 = True
            self._singleton.unlock()
            LOG.info("32bit monkey running on 64bit Windows. Upgrading.")
            WindowsUpgrader.upgrade(self._opts)
            return

        ControlClient.wakeup(parent=self._parent)
        ControlClient.load_control_config()

        if not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")
            return

        if firewall.is_enabled():
            firewall.add_firewall_rule()

        monkey_tunnel = ControlClient.create_control_tunnel()
        if monkey_tunnel:
            monkey_tunnel.start()

        ControlClient.send_telemetry("state", {'done': False})

        self._default_server = WormConfiguration.current_server
        LOG.debug("default server: %s" % self._default_server)
        ControlClient.send_telemetry("tunnel", {'proxy': ControlClient.proxies.get('https')})

        if WormConfiguration.collect_system_info:
            LOG.debug("Calling system info collection")
            system_info_collector = SystemInfoCollector()
            system_info = system_info_collector.get_info()
            ControlClient.send_telemetry("system_info_collection", system_info)

        if 0 == WormConfiguration.depth:
            LOG.debug("Reached max depth, shutting down")
            ControlClient.send_telemetry("trace", "Reached max depth, shutting down")
            return
        else:
            LOG.debug("Running with depth: %d" % WormConfiguration.depth)

        for iteration_index in xrange(WormConfiguration.max_iterations):
            ControlClient.keepalive()
            ControlClient.load_control_config()

            LOG.debug("Users to try: %s" % str(WormConfiguration.exploit_user_list))
            LOG.debug("Passwords to try: %s" % str(WormConfiguration.exploit_password_list))

            self._network.initialize()

            self._exploiters = WormConfiguration.exploiter_classes

            self._fingerprint = [fingerprint() for fingerprint in WormConfiguration.finger_classes]

            if not self._keep_running or not WormConfiguration.alive:
                break

            machines = self._network.get_victim_machines(WormConfiguration.scanner_class,
                                                         max_find=WormConfiguration.victims_max_find,
                                                         stop_callback=ControlClient.check_for_stop)
            is_empty = True
            for machine in machines:
                if ControlClient.check_for_stop():
                    break

                is_empty = False
                for finger in self._fingerprint:
                    LOG.info("Trying to get OS fingerprint from %r with module %s",
                             machine, finger.__class__.__name__)
                    finger.get_host_fingerprint(machine)

                ControlClient.send_telemetry('scan', {'machine': machine.as_dict(),
                                                      'scanner': WormConfiguration.scanner_class.__name__})

                # skip machines that we've already exploited
                if machine in self._exploited_machines:
                    LOG.debug("Skipping %r - already exploited",
                              machine)
                    continue
                elif machine in self._fail_exploitation_machines:
                    if WormConfiguration.retry_failed_explotation:
                        LOG.debug("%r - exploitation failed before, trying again", machine)
                    else:
                        LOG.debug("Skipping %r - exploitation failed before", machine)
                        continue

                if monkey_tunnel:
                    monkey_tunnel.set_tunnel_for_host(machine)
                if self._default_server:
                    LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine))
                    machine.set_default_server(self._default_server)

                successful_exploiter = None
                for exploiter in [exploiter(machine) for exploiter in self._exploiters]:
                    if not exploiter.is_os_supported():
                        LOG.info("Skipping exploiter %s host:%r, os is not supported",
                                 exploiter.__class__.__name__, machine)
                        continue

                    LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__)

                    result = False
                    try:
                        result = exploiter.exploit_host()
                        if result:
                            successful_exploiter = exploiter
                            break
                        else:
                            LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__)

                    except Exception as exc:
                        LOG.exception("Exception while attacking %s using %s: %s",
                                      machine, exploiter.__class__.__name__, exc)
                    finally:
                        exploiter.send_exploit_telemetry(result)

                if successful_exploiter:
                    self._exploited_machines.add(machine)

                    LOG.info("Successfully propagated to %s using %s",
                             machine, successful_exploiter.__class__.__name__)

                    # check if max-exploitation limit is reached
                    if WormConfiguration.victims_max_exploit <= len(self._exploited_machines):
                        self._keep_running = False

                        LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit)
                        break
                else:
                    self._fail_exploitation_machines.add(machine)

            if (not is_empty) and (WormConfiguration.max_iterations > iteration_index + 1):
                time_to_sleep = WormConfiguration.timeout_between_iterations
                LOG.info("Sleeping %d seconds before next life cycle iteration", time_to_sleep)
                time.sleep(time_to_sleep)

        if self._keep_running and WormConfiguration.alive:
            LOG.info("Reached max iterations (%d)", WormConfiguration.max_iterations)
        elif not WormConfiguration.alive:
            LOG.info("Marked not alive from configuration")

        # if host was exploited, before continue to closing the tunnel ensure the exploited host had its chance to
        # connect to the tunnel
        if len(self._exploited_machines) > 0:
            time_to_sleep = WormConfiguration.keep_tunnel_open_time
            LOG.info("Sleeping %d seconds for exploited machines to connect to tunnel", time_to_sleep)
            time.sleep(time_to_sleep)

        if monkey_tunnel:
            monkey_tunnel.stop()
            monkey_tunnel.join()

    def cleanup(self):
        LOG.info("Monkey cleanup started")
        self._keep_running = False

        if self._upgrading_to_64:
            InfectionMonkey.close_tunnel()
            firewall.close()
        else:
            ControlClient.send_telemetry("state", {'done': True})  # Signal the server (before closing the tunnel)
            InfectionMonkey.close_tunnel()
            firewall.close()
            if WormConfiguration.send_log_to_server:
                self.send_log()
            self._singleton.unlock()

        InfectionMonkey.self_delete()
        LOG.info("Monkey is shutting down")

    @staticmethod
    def close_tunnel():
        tunnel_address = ControlClient.proxies.get('https', '').replace('https://', '').split(':')[0]
        if tunnel_address:
            LOG.info("Quitting tunnel %s", tunnel_address)
            tunnel.quit_tunnel(tunnel_address)

    @staticmethod
    def self_delete():
        if WormConfiguration.self_delete_in_cleanup \
                and -1 == sys.executable.find('python'):
            try:
                if "win32" == sys.platform:
                    from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
                    startupinfo = subprocess.STARTUPINFO()
                    startupinfo.dwFlags = CREATE_NEW_CONSOLE | STARTF_USESHOWWINDOW
                    startupinfo.wShowWindow = SW_HIDE
                    subprocess.Popen(DELAY_DELETE_CMD % {'file_path': sys.executable},
                                     stdin=None, stdout=None, stderr=None,
                                     close_fds=True, startupinfo=startupinfo)
                else:
                    os.remove(sys.executable)
            except Exception as exc:
                LOG.error("Exception in self delete: %s", exc)

    def send_log(self):
        monkey_log_path = utils.get_monkey_log_path()
        if os.path.exists(monkey_log_path):
            with open(monkey_log_path, 'r') as f:
                log = f.read()
        else:
            log = ''

        ControlClient.send_log(log)
예제 #8
0
 def __init__(self):
     super().__init__()
     self.datetime = QDateTime.currentDateTime()
     self.initUI()
     self.scanner = NetworkScanner()
예제 #9
0
class MyApp(QMainWindow):

    def __init__(self):
        super().__init__()
        self.datetime = QDateTime.currentDateTime()
        self.initUI()
        self.scanner = NetworkScanner()

    def initUI(self):

        ##time status
        self.statusBar().showMessage('Updated : ' + self.datetime.toString(Qt.DefaultLocaleShortDate))

        ##list setting
        self.iotList = QListWidget(self)
        self.iotList.setGeometry(QRect(20, 80, 761, 480))
        self.iotList.setAutoFillBackground(True)
        self.iotList.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.iotList.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.iotList.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
        self.iotList.setAutoScrollMargin(14)
        self.iotList.setEditTriggers(QAbstractItemView.CurrentChanged)
        self.iotList.setObjectName("iotList")
        self.iotList.setStyleSheet("border-color: gray;")


        ##Scan Button
        self.scanbtn = QPushButton('Scan', self)
        self.scanbtn.setCheckable(False)
        self.scanbtn.move(20, 20)
        self.scanbtn.setIcon(QIcon('LocalNetworkGUI/scanicon.png'))
        self.scanbtn.resize(self.scanbtn.sizeHint())
        self.scanbtn.clicked.connect(self.scan_Click)
        self.scanbtn.toggle()

        ##Add Device Button
        addbtn = QPushButton('Add a device', self)
        addbtn.setCheckable(False)
        addbtn.move(115, 20)
        addbtn.setIcon(QIcon('LocalNetworkGUI/addicon.png'))
        addbtn.resize(addbtn.sizeHint())
        addbtn.clicked.connect(self.add_Click)
        addbtn.toggle()

        ##Add Semi trusted Device Button
        addbtn = QPushButton('Add a semi trusted device', self)
        addbtn.setCheckable(False)
        addbtn.move(245, 20)
        addbtn.setIcon(QIcon('LocalNetworkGUI/addicon.png'))
        addbtn.resize(addbtn.sizeHint())
        addbtn.clicked.connect(self.add_semitrusted_Click)
        addbtn.toggle()


        ##Delete Device Button
        deletebtn = QPushButton('Delete a device', self)
        deletebtn.setCheckable(False)
        deletebtn.move(436, 20)
        deletebtn.setIcon(QIcon('LocalNetworkGUI/deleteicon.png'))
        deletebtn.resize(deletebtn.sizeHint())
        deletebtn.clicked.connect(self.delete_Click)
        deletebtn.toggle()

        ##Rename Button
        renamebtn = QPushButton('Rename ', self)
        renamebtn.setCheckable(False)
        renamebtn.move(574, 20)
        renamebtn.setIcon(QIcon('LocalNetworkGUI/renameicon.png'))
        renamebtn.resize(renamebtn.sizeHint())
        renamebtn.clicked.connect(self.rename_Click)
        renamebtn.toggle()

        ##History Device Button
        historybtn = QPushButton('History', self)
        historybtn.setCheckable(False)
        historybtn.move(670, 20)
        historybtn.setIcon(QIcon('LocalNetworkGUI/historyicon.png'))
        historybtn.resize(historybtn.sizeHint())
        #historybtn.setStyleSheet('background: red;')
        historybtn.clicked.connect(self.history_Click)
        historybtn.toggle()

        ##Risk Label
        risk = QLabel(self)
        risk.resize(50, 50)
        pixmap = QPixmap("LocalNetworkGUI/riskicon.png")
        pixmap = pixmap.scaledToWidth(30)
        risk.setPixmap(QPixmap(pixmap))
        risk.move(640, 15)
        risk.hide()

        ##window
        self.setWindowTitle("Home IoT security")
        self.setWindowIcon(QIcon('LocalNetworkGUI/homeicon.png'))
        self.setGeometry(300, 200, 801, 600)
        self.show()

    ## button function

    ## add button
    def add_Click(self):
        if self.iotList.currentItem().state == 0:
            self.add_question()
        else:
            self.add_information()

    def add_question(self):
        reply = QMessageBox.question(self, 'question', 'Are you sure to add this device?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            self.iotList.currentItem().state = 1
            self.iotList.currentItem().setIcon(QIcon('LocalNetworkGUI/safeicon.png'))
            self.iotList.currentItem().setBackground(QColor(200, 255, 200))
            item = self.iotList.takeItem(self.iotList.currentRow())

            trust = item.text().split(' ')[3] + "\n"
            f = open('trusted', 'a')
            f.write(trust)
            f.close()

            self.iotList.addItem(item)


    def add_information(self):
        QMessageBox.information(self, 'information', 'Already Added!', QMessageBox.Ok)

    ## add semi trusted button
    def add_semitrusted_Click(self):
        if self.iotList.currentItem().state == 0:
            self.add_semitrusted_question()
        else:
            self.add_semitrusted_information()

    def add_semitrusted_question(self):
        reply = QMessageBox.question(self, 'question', 'Are you sure to add this device?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            self.iotList.currentItem().state = 2
            self.iotList.currentItem().setIcon(QIcon('LocalNetworkGUI/safeicon.png'))
            self.iotList.currentItem().setBackground(QColor(255, 240, 150))
            item = self.iotList.takeItem(self.iotList.currentRow())

            Whitelist.get_instance().add_semiwhitelisted(item.host)

            trust = item.text().split(' ')[3] + "\n"
            f = open('trusted', 'a')
            f.write(trust)
            f.close()

            self.iotList.addItem(item)

    def add_semitrusted_information(self):
        QMessageBox.information(self, 'information', 'Already Added!', QMessageBox.Ok)

    ## delete button
    def delete_Click(self):
        self.delete_question1()

    def delete_question1(self):
        reply = QMessageBox.question(self, 'question', 'Are you sure to delete this device?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            if self.iotList.currentItem().state == 0:
                self.delete_question2()
            else:
                f = open("trusted", 'r')
                dataset = f.read()
                f.close()

                f = open("trusted", 'w')
                f.close()

                f = open("trusted", 'a')
                itemList = dataset.split('\n')
                for i in itemList:
                    if self.iotList.currentItem().text().split(" ")[3] not in i:
                        f.write(i + "\n")
                f.close()

                mac = self.iotList.currentItem().host.mac_address
                if mac in Whitelist.get_instance().semiwhitelist:
                    Whitelist.get_instance().remove_semiwhitelisted(mac)

                self.iotList.takeItem(self.iotList.currentRow())

    def delete_question2(self):
        reply = QMessageBox.question(self, 'question', 'This device is unconfirmed.\r\nDo you want to report?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

        if reply == QMessageBox.Yes:
            self.delete_report()
        self.iotList.takeItem(self.iotList.currentRow())

    def delete_report(self):
        QMessageBox.information(self, 'information', 'Reported.', QMessageBox.Ok)

    ## rename button
    def rename_Click(self):
        if (self.iotList.currentItem().state == 1) or (self.iotList.currentItem().state == 2):
            self.rename_edit()
        else:
            self.rename_warning()

    def rename_warning(self):
        QMessageBox.warning(self, 'Warning', 'This device is unconfirmed.\r\nPlease check first.', QMessageBox.Ok)

    def rename_edit(self):
        text, ok = QInputDialog.getText(self, 'Input Name', 'Enter new name:')
        st = self.iotList.currentItem().text().split("\r\n")
        self.iotList.currentItem().setText(st[0] + "\r\n" + str(text) + "\r\n")
        if ok:
            f = open("trusted", 'r')
            find = f.read()
            f.close()

            f = open("trusted", 'w')
            f.close()

            f = open("trusted", 'a')
            itemList = find.split('\n')
            for i in itemList:
                if self.iotList.currentItem().text().split(" ")[3] in i:
                    temp = i.split("=")
                    f.write(temp[0] + "=" + str(text) + "\n")
                else:
                    f.write(i + '\n')
            f.close()
    
    # history button
    def history_Click(self):
        history = HistoryGUI().__init__()

    ##scan button

    def scan_Click(self):
        self.scanbtn.setEnabled(False)
        print("Starting scan")
        self.scanner.scan_network_callback(lambda x: self.on_scan_completion(x), port_scan=True)

    def on_scan_completion(self, hosts):
        print("Scan completed")
        self.scanbtn.setEnabled(True)
        HistoryArchive.get_instance().add_scan(hosts)
        self.iotList.clear()
        i = 0

        whitelist = Whitelist.get_instance()

        for host in hosts:

            item = QListWidgetItem()
            item.state = 0
            item.host = host
            self.iotList.addItem(item)
            item = self.iotList.item(i)
            item_text_lines = [host.get_GUI_name(), "", "", ""]

            f = open("trusted", 'r')
            while True:
                line = f.readline()
                if not line: break
                if host.get_GUI_name().split(" ")[3] in line:
                    temp = line.split("=")
                    item_text_lines[1] = temp[len(temp)-1]
                    item.state = 1
            f.close()

            if len(host.ports) > 0:
                item_text_lines[2] = "  Ports: " + ", ".join((str(port.port_id) for port in host.ports))

            if host.mac_address in whitelist.semiwhitelist:
                allowed_ports = whitelist.semiwhitelist[host.mac_address]
                item.state = 2
                item.setIcon(QIcon('LocalNetworkGUI/safeicon.png'))
                item.setBackground(QColor(255, 240, 150))
                kick = False

                for port in host.ports:
                    port_str = str(port.port_id)
                    if port_str not in allowed_ports:
                        print("Device", host.get_GUI_name(), "has illegal port", port.port_id, "open!")
                        item_text_lines[3] = "    Illegal port {}. Deauthenticating from network...".format(port.port_id)
                        item_text_lines.append("")
                        kick = True
                if kick:
                    DeauthHandler.deauth_device(host, duration=20)
            elif item.state == 0:
                item.setIcon(QIcon('LocalNetworkGUI/dangericon.png'))
                item.setBackground(QColor(255, 195, 200))
            elif item.state == 1:
                item.setIcon(QIcon('LocalNetworkGUI/safeicon.png'))
                item.setBackground(QColor(200, 255, 200))
            else:
                item.setIcon(QIcon('LocalNetworkGUI/disconnecticon.png'))
                item.setBackground(QColor(200, 200, 200))
            item.setText("\r\n".join(item_text_lines))
            i += 1