Esempio n. 1
0
class ETFConsole(Cmd):
    # Cmd is defined as an old style class, therefor inheritance
    # will not work and class variables have to be declared outside __init__

    # Backend Tools
    configs = ConfigurationManager(
        "./core/ConfigurationManager/etf.conf").config
    aircommunicator = AirCommunicator()
    spawnmanager = SpawnManager()

    basic_commands = [
        "start", "stop", "status", "spawn", "restore", "get", "set", "config",
        "back", "listargs", "copy", "add", "del", "show"
    ]

    services = ["airhost", "airscanner", "airdeauthor"]
    spawners = ["mitmf", "beef", "ettercap", "sslstrip"]

    filter_keywords = ["where", "only"]
    plugin_keyword = ["with"]

    airhost_plugins = ["dnsspoofer", "credentialprinter"]
    airscanner_plugins = ["packetlogger", "selfishwifi"]
    airdeauthor_plugins = []

    copy_options = ["ap", "probe"]
    add_del_options = ["aps",
                       "clients"]  # Meant to be followed by filter or integer
    show_options = [
        "sniffed_aps", "sniffed_probes", "deauth_aps", "deauth_clients",
        "connected_clients"
    ]  # Meant to be followed by filter or integer

    # Configuration Handling
    current_config_mode = configs["etf"]["aircommunicator"]
    config_mode_string = "etf/aircommunicator/"

    # do and complete of configuration options
    def do_restore(self, args):
        entered = args.split()
        if len(entered) != 1:
            print "[-] Only 1 argument expected after spawn command"

        self.spawnmanager.restore_spawner(args)

    def do_spawn(self, args):
        entered = args.split()
        if len(entered) != 1:
            print "[-] Only 1 argument expected after spawn command"

        try:
            self.spawnmanager.add_spawner(
                args, self.configs["etf"]["spawner"][args]["system_location"],
                " ".join(self.configs["etf"]["spawner"][args]["args"]))
        except KeyError:
            print "[-] Spawner for '{}' does not exist.".format(args)

    def spawner_completion(self, text, line):
        entered = line.split()
        out = None
        if len(entered) == 1:
            out = self.spawners
        elif len(entered) == 2:
            out = [
                option for option in self.spawners if option.startswith(text)
            ]

        return out

    def complete_spawn(self, text, line, begidx, endidx):
        return self.spawner_completion(text, line)

    def complete_restore(self, text, line, begidx, endidx):
        return self.spawner_completion(text, line)

    def do_listargs(self, args):
        is_var = lambda key: (isinstance(self.current_config_mode[key], str) or
                              isinstance(self.current_config_mode[key], list))

        print "\n".join([
            "{:>20} ={:>20}; ({})".format(
                key,
                self.current_config_mode[key] if is_var(key) else "(dict)",
                "var" if is_var(key) else "mode")
            for key in self.current_config_mode.keys()
        ])

    def do_back(self, args):
        mode = [
            mode for mode in self.config_mode_string.split("/") if mode != ''
        ]
        if len(mode) == 1:
            pass
        else:
            mode = mode[:-1]
            self.config_mode_string = ""
            self.current_config_mode = self.configs
            for layer in mode:
                self.current_config_mode = self.current_config_mode[layer]
                self.config_mode_string += layer + "/"

        self.update_prompt()

    def do_config(self, args):
        arg = args.split()
        if len(arg) != 1:
            print "[-] Only 1 arg expected after 'config'"
            return

        try:
            config_key = arg[0]
            dict_string, config = self._look_for_config(
                "", self.configs, config_key)
            dict_string = "/".join(
                dict_string[:-1].split("/")
                [::-1])  # the output string is from bottom to top, we reverse
            self.current_config_mode = config
            self.config_mode_string = dict_string
            self.update_prompt()
        except Exception:
            print "'{key}' does not exist in the configuration file".format(
                key=config_key)

    def _look_for_config(self, dict_string, dict_root, dict_key):
        if dict_key in dict_root:
            dict_string += dict_key + "/"
            return (dict_string, dict_root[dict_key])

        for key, value in dict_root.items():
            if isinstance(value, dict):
                try:
                    dict_string, item = self._look_for_config(
                        dict_string, value, dict_key)
                    dict_string += key + "/"
                    if item is not None:
                        return (dict_string, item)
                except:
                    pass

    def complete_config(self, text, line, begidx, endidx):
        args = line.split()
        all_configs = self.services + \
           self.spawners + \
           self.airscanner_plugins + \
           self.airhost_plugins + \
           self.airdeauthor_plugins

        if len(args) == 1:
            return all_configs
        elif len(args) == 2:
            return [
                config for config in all_configs if config.startswith(args[1])
            ]

    def do_get(self, args):
        var = args.split()
        if len(var) != 1:
            print "[-] Only 1 arg expected after 'get'"
            return

        try:
            mode = var[0]
            if  isinstance(self.current_config_mode[mode], str) or \
             isinstance(self.current_config_mode[mode], list):

                config, value = mode, self.current_config_mode[mode]
                print "{config} = {value}".format(
                    config=config, value=self.current_config_mode[mode])
        except KeyError:
            print "'{key}' does not exist in the configuration file".format(
                key=mode)

    def complete_get(self, text, line, begidx, endidx):
        return self.complete_vars(text)

    def do_set(self, args):
        try:
            splitted_args = args.split()
            if len(splitted_args) == 2:
                var, value = splitted_args[0], splitted_args[1]
            else:
                var, value = splitted_args[0], splitted_args[1:]

            self.current_config_mode[
                var]  # raise KeyError before assignment if option does not exist
            self.current_config_mode[var] = value
            self.configs.write()
            print "{config} = {value}".format(
                config=var, value=self.current_config_mode[var])
        except KeyError:
            print "'{key}' does not exist in the configuration file".format(
                key=mode)

    def complete_set(self, text, line, begidx, endidx):
        return self.complete_vars(text)

    def complete_vars(self, text):
        out = [keyword for keyword  in  self.current_config_mode
               if  keyword.startswith(text) and \
                (isinstance(self.current_config_mode[keyword], str) or \
                isinstance(self.current_config_mode[keyword], list))]
        return out

    def complete_modes(self, text):
        out = [keyword for keyword  in  self.current_config_mode
               if  keyword.startswith(text) and not \
                (isinstance(self.current_config_mode[keyword], str) or \
                isinstance(self.current_config_mode[keyword], list))]
        return out

    # Copy Add Del
    def do_copy(self, args):
        args = args.split()
        if len(args) == 2:
            try:
                id = int(args[-1])  # line should be something like "copy ap 4"
            except ValueError:
                print "[-] ID must be an integer value"
                print "Copy syntax: copy [option] [ID]"
                return
            if args[0] == "ap":
                self.aircommunicator.airhost_copy_ap(id)
            elif args[0] == "probe":
                self.aircommunicator.airhost_copy_probe(id)

    def complete_copy(self, text, line, begidx, endidx):
        entered = line.split()
        if len(entered) == 1:
            if not text or text == "":
                return self.copy_options
        elif len(entered) == 2:
            start = entered[1]
            return [
                option for option in self.copy_options
                if option.startswith(start)
            ]

    def do_add(self, args):
        args = args.split()
        if len(args) >= 1:
            filter_string = self._parse_filter_string(args)
            self.aircommunicator.deauthor_add(args[0], filter_string)

    def do_del(self, args):
        args = args.split()
        if len(args) >= 1:
            filter_string = self._parse_filter_string(args)
            self.aircommunicator.deauthor_del(args[0], filter_string)

    def complete_add(self, text, line, begidx, endidx):
        return self.complete_addel(line, text)

    def complete_del(self, text, line, begidx, endidx):
        return self.complete_addel(line, text)

    def _parse_filter_string(self, args):
        filter_string = None
        if len(args) == 3:
            try:
                id = int(args[2])
                filter_string = "where id = {}".format(str(id))
            except:
                pass
        elif len(args) > 3:
            filter_string = " ".join(args[1:])

        return filter_string

    def complete_addel(self, line, text):
        if not text or text == "":
            return self.show_empty_text_addel_options(line)
        else:
            return self.show_to_complete_addel_options(line, text)

    def show_empty_text_addel_options(self, line):
        entered = line.split()
        out = None
        if len(entered) < 3:
            out = self.complete_filter_command(self.add_del_options, "",
                                               entered)
        elif len(entered) >= 3:
            # list filter args (id, ssid, bssid, channel, etc...)
            addel = entered[0]
            if addel == "add":
                if entered[1] == "aps":
                    out = vars(AccessPoint()).keys()
                elif entered[1] == "clients":
                    out = vars(ProbeInfo()).keys()
            elif addel == "del":
                if entered[1] == "aps":
                    out = vars(DeauthAP()).keys()
                elif entered[1] == "clients":
                    out = vars(DeauthClient()).keys()

        return out

    def show_to_complete_addel_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) <= 3:
            out = self.complete_filter_command(self.add_del_options, text,
                                               entered)
        elif len(entered) > 3:
            start = entered[-1]
            addel = entered[0]
            if addel == "add":
                if entered[1] == "aps":
                    out = [
                        keyword for keyword in vars(AccessPoint()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "clients":
                    out = [
                        keyword for keyword in vars(ProbeInfo()).keys()
                        if keyword.startswith(start)
                    ]
            elif addel == "del":
                if entered[1] == "aps":
                    out = [
                        keyword for keyword in vars(DeauthAP()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "clients":
                    out = [
                        keyword for keyword in vars(DeauthClient()).keys()
                        if keyword.startswith(start)
                    ]

        return out

    def complete_filter_command(self, options, text, entered):
        out = None
        if not text or text == "":
            if len(entered) == 1:
                out = options
            elif len(entered) == 2:
                out = self.filter_keywords
        else:
            if len(entered) == 2:
                # Here the first parameter after 'show' is already complete and the user wants the next
                if entered[1] in options:
                    out = [text + " "]
                # Here the first parameter after 'show' is incomplete and the user wants completion
                else:
                    start = entered[1]
                    out = [
                        keyword for keyword in options
                        if keyword.startswith(start)
                    ]
            elif len(entered) == 3:
                # Completion for the 'where' or 'only' keyword
                if entered[2] in self.filter_keywords:
                    out = [text + " "]
                else:
                    start = entered[2]
                    out = [
                        keyword for keyword in self.filter_keywords
                        if keyword.startswith(start)
                    ]
        return out

    # Show

    def do_show(self, args):
        args = args.split()
        if len(args) >= 1:
            option = args[0]
            filter_string = ""
            if len(args) >= 2:
                filter_string = " ".join(args[1:])

            if option == "sniffed_aps":
                self.aircommunicator.print_sniffed_aps(filter_string)
            elif option == "sniffed_probes":
                self.aircommunicator.print_sniffed_probes(filter_string)
            elif option == "deauth_aps":
                self.aircommunicator.print_aps_to_deauth(filter_string)
            elif option == "deauth_clients":
                self.aircommunicator.print_clients_to_deauth(filter_string)
            elif option == "connected_clients":
                self.aircommunicator.print_connected_clients(filter_string)

    def complete_show(self, text, line, begidx, endidx):
        if not text or text == "":
            return self.show_empty_text_show_options(line)
        else:
            return self.show_to_complete_show_options(line, text)

    def show_empty_text_show_options(self, line):
        entered = line.split()
        out = None
        if len(entered) < 3:
            out = self.complete_filter_command(self.show_options, "", entered)
        elif len(entered) >= 3:
            # list filter args (id, ssid, bssid, channel, etc...)
            if entered[1] == "sniffed_aps":
                out = vars(AccessPoint()).keys()
            elif entered[1] == "sniffed_probes":
                out = vars(ProbeInfo()).keys()
            elif entered[1] == "deauth_aps":
                out = vars(DeauthAP()).keys()
            elif entered[1] == "deauth_clients":
                out = vars(DeauthClient()).keys()
            elif entered[1] == "connected_clients":
                out = vars(Client()).keys()

        return out

    def show_to_complete_show_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) < 4:
            out = self.complete_filter_command(self.show_options, text,
                                               entered)
        elif len(entered) >= 4:
            start = entered[-1]
            if entered[1] in self.show_options:
                if entered[1] == "sniffed_aps":
                    out = [
                        keyword for keyword in vars(AccessPoint()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "sniffed_probes":
                    out = [
                        keyword for keyword in vars(ProbeInfo()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "deauth_aps":
                    out = [
                        keyword for keyword in vars(DeauthAP()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "deauth_clients":
                    out = [
                        keyword for keyword in vars(DeauthClient()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "connected_clients":
                    out = [
                        keyword for keyword in vars(Client()).keys()
                        if keyword.startswith(start)
                    ]

        return out

    # Start

    def do_start(self, args):
        args = args.split()
        if len(args) >= 1:
            service = args[0]
            plugins = []
            if "with" in args:
                plugins = args[args.index("with") + 1:]

            self.aircommunicator.service(service, "start", plugins)

    def do_stop(self, args):
        args = args.split()
        if len(args) >= 1:
            service = args[0]
            self.aircommunicator.service(service, "stop")

    def complete_start(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def complete_stop(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def complete_status(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def _complete_basic(self, line, text):
        if not text or text == "":
            return self.show_empty_text_start_options(line)
        else:
            return self.show_to_complete_start_options(line, text)

    def show_empty_text_start_options(self, line):
        entered = line.split()
        out = None
        if len(entered) == 1:
            out = self.services
        elif len(entered) == 2:
            out = self.plugin_keyword
        elif len(entered) >= 3:
            if entered[1] == "airhost":
                out = self.airhost_plugins
            elif entered[1] == "airscanner":
                out = self.airscanner_plugins
            elif entered[1] == "airdeauthor":
                out = self.airdeauthor_plugins

        return out

    def show_to_complete_start_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) == 2:
            # Here the first parameter after 'air' is already complete and the user wants the next
            if entered[1] in self.services:
                out = [text + " "]
            # Here the first parameter after 'air' is incomplete and the user wants completion
            else:
                start = entered[1]
                out = [
                    keyword for keyword in self.services
                    if keyword.startswith(start)
                ]
        elif len(entered) == 3:
            # Completion for the 'with' keyword
            if entered[2] in self.plugin_keyword:
                out = [text + " "]
            else:
                out = self.plugin_keyword
        elif len(entered) == 4:
            start = entered[-1]
            if entered[1] in self.services:
                if entered[1] == "airhost":
                    out = [
                        keyword for keyword in self.airhost_plugins
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "airscanner":
                    out = [
                        keyword for keyword in self.airscanner_plugins
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "airdeauthor":
                    out = [
                        keyword for keyword in self.airdeauthor_plugins
                        if keyword.startswith(start)
                    ]

        return out

    def update_prompt(self):
        self.prompt = "ETF{mode_start}{mode}{mode_end}::> ".format(
            mode_start=colored("[", "cyan"),
            mode=colored(console.config_mode_string, "green"),
            mode_end=colored("]", "cyan"))

    def do_EOF(self, line):  # control-D
        print "Exiting..."
        self.aircommunicator.stop_air_communications(True, True, True)
        self.spawnmanager.restore_all()
        os.system('service networking restart')
        os.system('service network-manager restart')
        return True

    # Just overwriting this method so it doesn't execute the last non-empty line
    def emptyline(self):
        pass
class ETFConsole(Cmd):
    # Cmd is defined as an old style class, therefor inheritance
    # will not work and class variables have to be declared outside __init__

    # Backend Tools
    configs = ConfigurationManager(
        "./core/ConfigurationManager/etf.conf").config
    aircommunicator = AirCommunicator()
    etfitm = EvilInTheMiddle()
    spawnmanager = SpawnManager()

    # Static strings to help with autocompletion

    basic_commands = [
        "start", "stop", "status", "spawn", "restore", "get", "set", "config",
        "back", "listargs", "copy", "add", "del", "show"
    ]

    services = [
        "airhost", "airscanner", "airinjector", "aircracker", "mitmproxy"
    ]
    aux_services = ["aplauncher", "dnsmasqhandler"]
    spawners = ["mitmf", "beef-xss", "ettercap", "sslstrip"]

    filter_keywords = ["where", "only"]
    plugin_keyword = ["with"]

    airhost_plugins = ["dnsspoofer", "credentialsniffer", "karma"]
    airscanner_plugins = [
        "packetlogger", "selfishwifi", "credentialsniffer", "arpreplayer",
        "caffelatte"
    ]
    airinjector_plugins = [
        "credentialsniffer", "deauthenticator", "arpreplayer", "caffelatte"
    ]
    aircracker_types = ["wpa_crackers", "half_wpa_crackers"]
    aircrackers = ["cowpatty", "aircrack-ng", "halwpaid"]
    mitmproxy_plugins = ["downloadreplacer", "beefinjector", "peinjector"]

    copy_options = ["ap", "probe"]
    add_del_options = ["aps", "clients",
                       "probes"]  # Meant to be followed by ID
    show_options = [
        "sniffed_aps", "sniffed_probes", "sniffed_clients", "ap_targets",
        "client_targets", "connected_clients", "wpa_handshakes",
        "half_wpa_handshakes", "wep_data_logs"
    ]  # Meant to be followed by filter
    crack_options = ["wpa_handshakes", "half_wpa_handshakes",
                     "wep_data"]  # Meant to be followed by ID

    # Configuration Handling
    current_config_mode = configs["etf"]["aircommunicator"]
    config_mode_string = "etf/aircommunicator/"

    # do and complete of configuration options
    def do_restore(self, args):
        entered = args.split()
        if len(entered) != 1:
            print "[-] Only 1 argument expected after spawn command"

        self.spawnmanager.restore_spawner(args)

    def do_spawn(self, args):
        entered = args.split()
        if len(entered) != 1:
            print "[-] Only 1 argument expected after spawn command"
        try:
            self.spawnmanager.add_spawner(args)
        except KeyError as e:
            print e
            print "[-] Spawner for '{}' does not exist.".format(args)

    def spawner_completion(self, text, line):
        entered = line.split()
        out = None
        if len(entered) == 1:
            out = self.spawners
        elif len(entered) == 2:
            out = [
                option for option in self.spawners if option.startswith(text)
            ]

        return out

    def complete_spawn(self, text, line, begidx, endidx):
        return self.spawner_completion(text, line)

    def complete_restore(self, text, line, begidx, endidx):
        return self.spawner_completion(text, line)

    def do_listargs(self, args):
        is_var = lambda key: (isinstance(self.current_config_mode[key], str) or
                              isinstance(self.current_config_mode[key], list))

        print "\n".join([
            "{:>20} ={:>20}; ({})".format(
                key,
                self.current_config_mode[key] if is_var(key) else "(dict)",
                "var" if is_var(key) else "mode")
            for key in self.current_config_mode.keys()
        ])

    def do_back(self, args):
        mode = [
            mode for mode in self.config_mode_string.split("/") if mode != ''
        ]
        if len(mode) == 1:
            pass
        else:
            mode = mode[:-1]
            self.config_mode_string = ""
            self.current_config_mode = self.configs
            for layer in mode:
                self.current_config_mode = self.current_config_mode[layer]
                self.config_mode_string += layer + "/"

        self.update_prompt()

    def do_config(self, args):
        arg = args.split()
        if len(arg) != 1:
            print "[-] Only 1 arg expected after 'config'"
            return

        try:
            config_key = arg[0]
            dict_string, config = self._look_for_config(
                "", self.configs, config_key)
            dict_string = "/".join(
                dict_string[:-1].split("/")
                [::-1])  # the output string is from bottom to top, we reverse
            self.current_config_mode = config
            self.config_mode_string = dict_string
            self.update_prompt()
        except Exception:
            print "'{key}' does not exist in the configuration file".format(
                key=config_key)

    def _look_for_config(self, dict_string, dict_root, dict_key):
        if dict_key in dict_root:
            dict_string += dict_key + "/"
            return (dict_string, dict_root[dict_key])

        for key, value in dict_root.items():
            if isinstance(value, dict):
                try:
                    dict_string, item = self._look_for_config(
                        dict_string, value, dict_key)
                    dict_string += key + "/"
                    if item is not None:
                        return (dict_string, item)
                except:
                    pass

    def complete_config(self, text, line, begidx, endidx):
        args = line.split()
        all_configs =   self.services + \
                        self.aux_services + \
                        self.spawners + \
                        self.airscanner_plugins + \
                        self.airhost_plugins + \
                        self.airinjector_plugins + \
                        self.aircracker_types + \
                        self.aircrackers + \
                        self.mitmproxy_plugins

        if len(args) == 1:
            return all_configs
        elif len(args) == 2:
            return [
                config for config in all_configs if config.startswith(args[1])
            ]

    def do_get(self, args):
        var = args.split()
        if len(var) != 1:
            print "[-] Only 1 arg expected after 'get'"
            return

        try:
            mode = var[0]
            if  isinstance(self.current_config_mode[mode], str) or \
                isinstance(self.current_config_mode[mode], list):

                config, value = mode, self.current_config_mode[mode]
                print "{config} = {value}".format(
                    config=config, value=self.current_config_mode[mode])
        except KeyError:
            print "'{key}' does not exist in the configuration file".format(
                key=mode)

    def complete_get(self, text, line, begidx, endidx):
        return self.complete_vars(text)

    def do_set(self, args):
        is_var = lambda key: (isinstance(self.current_config_mode[key], str) or
                              isinstance(self.current_config_mode[key], list))
        try:
            splitted_args = args.split()
            if len(splitted_args) == 2:
                var, value = splitted_args[0], splitted_args[1]
            else:
                var, value = splitted_args[0], splitted_args[1:]

            # raise KeyError before assignment if option does not exist
            if not is_var(var):
                return

            self._set_global_config(self.configs, var, value)
            self.configs.write()
            print "{config} = {value}".format(
                config=var, value=self.current_config_mode[var])
        except KeyError:
            print "'{key}' does not exist in the configuration file".format(
                key=var)
        except Exception:
            pass

    def _set_global_config(self, dict_root, var, val):
        if var in dict_root.keys():
            dict_root[var] = val

        for key, value in dict_root.items():
            if isinstance(value, dict):
                try:
                    self._set_global_config(value, var, val)
                except:
                    pass

    def complete_set(self, text, line, begidx, endidx):
        return self.complete_vars(text)

    def complete_vars(self, text):
        out = [keyword for keyword  in  self.current_config_mode
                                    if  keyword.startswith(text) and \
                                        (isinstance(self.current_config_mode[keyword], str) or \
                                        isinstance(self.current_config_mode[keyword], list))]
        return out

    def complete_modes(self, text):
        out = [keyword for keyword  in  self.current_config_mode
                                    if  keyword.startswith(text) and not \
                                        (isinstance(self.current_config_mode[keyword], str) or \
                                        isinstance(self.current_config_mode[keyword], list))]
        return out

    # Copy Add Del
    def do_copy(self, args):
        args = args.split()
        if len(args) == 2:
            try:
                id = int(args[-1])  # line should be something like "copy ap 4"
            except ValueError:
                print "[-] ID must be an integer value"
                print "Copy syntax: copy [option] [ID]"
                return
            if args[0] == "ap":
                self.aircommunicator.airhost_copy_ap(id)
            elif args[0] == "probe":
                self.aircommunicator.airhost_copy_probe(id)

    def complete_copy(self, text, line, begidx, endidx):
        entered = line.split()
        if len(entered) == 1:
            if not text or text == "":
                return self.copy_options
        elif len(entered) == 2:
            start = entered[1]
            return [
                option for option in self.copy_options
                if option.startswith(start)
            ]

    def do_add(self, args):
        args = args.split()
        if len(args) >= 1:
            filter_string = self._parse_filter_string(args)
            self.aircommunicator.injector_add(args[0], filter_string)

    def do_del(self, args):
        args = args.split()
        if len(args) >= 1:
            filter_string = self._parse_filter_string(args)
            self.aircommunicator.injector_del(args[0], filter_string)

    def complete_add(self, text, line, begidx, endidx):
        return self.complete_addel(line, text)

    def complete_del(self, text, line, begidx, endidx):
        return self.complete_addel(line, text)

    def _parse_filter_string(self, args):
        filter_string = None
        if len(args) == 3:
            try:
                id = int(args[2])
                filter_string = "where id = {}".format(str(id))
            except:
                pass
        elif len(args) > 3:
            filter_string = " ".join(args[1:])

        return filter_string

    def complete_addel(self, line, text):
        if not text or text == "":
            return self.show_empty_text_addel_options(line)
        else:
            return self.show_to_complete_addel_options(line, text)

    def show_empty_text_addel_options(self, line):
        entered = line.split()
        out = None
        if len(entered) < 3:
            out = self.complete_filter_command(self.add_del_options, "",
                                               entered)
        elif len(entered) >= 3:
            # list filter args (id, ssid, bssid, channel, etc...)
            addel = entered[0]
            if addel == "add":
                if entered[1] == "aps":
                    out = vars(AccessPoint()).keys()
                elif entered[1] == "probes":
                    out = vars(ProbeInfo()).keys()
            elif addel == "del":
                if entered[1] == "aps":
                    out = vars(AccessPoint()).keys()
                elif entered[1] == "clients":
                    out = vars(WiFiClient()).keys()

        return out

    def show_to_complete_addel_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) <= 3:
            out = self.complete_filter_command(self.add_del_options, text,
                                               entered)
        elif len(entered) > 3:
            start = entered[-1]
            addel = entered[0]
            if addel == "add":
                if entered[1] == "aps":
                    out = [
                        keyword for keyword in vars(AccessPoint()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "probes":
                    out = [
                        keyword for keyword in vars(ProbeInfo()).keys()
                        if keyword.startswith(start)
                    ]
            elif addel == "del":
                if entered[1] == "aps":
                    out = [
                        keyword for keyword in vars(AccessPoint()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "clients":
                    out = [
                        keyword for keyword in vars(WiFiClient()).keys()
                        if keyword.startswith(start)
                    ]

        return out

    def complete_filter_command(self, options, text, entered):
        out = None
        if not text or text == "":
            if len(entered) == 1:
                out = options
            elif len(entered) == 2:
                out = self.filter_keywords
        else:
            if len(entered) == 2:
                # Here the first parameter after 'show' is already complete and the user wants the next
                if entered[1] in options:
                    out = [text + " "]
                # Here the first parameter after 'show' is incomplete and the user wants completion
                else:
                    start = entered[1]
                    out = [
                        keyword for keyword in options
                        if keyword.startswith(start)
                    ]
            elif len(entered) == 3:
                # Completion for the 'where' or 'only' keyword
                if entered[2] in self.filter_keywords:
                    out = [text + " "]
                else:
                    start = entered[2]
                    out = [
                        keyword for keyword in self.filter_keywords
                        if keyword.startswith(start)
                    ]
        return out

    # Show

    def do_show(self, args):
        args = args.split()
        if len(args) >= 1:
            option = args[0]
            filter_string = ""
            if len(args) >= 2:
                filter_string = " ".join(args[1:])

            if option == "sniffed_aps":
                self.aircommunicator.print_sniffed_aps(filter_string)
            elif option == "sniffed_clients":
                self.aircommunicator.print_sniffed_clients(filter_string)
            elif option == "sniffed_probes":
                self.aircommunicator.print_sniffed_probes(filter_string)
            elif option == "ap_targets":
                self.aircommunicator.print_ap_injection_targets(filter_string)
            elif option == "client_targets":
                self.aircommunicator.print_client_injection_targets(
                    filter_string)
            elif option == "connected_clients":
                self.aircommunicator.print_connected_clients(filter_string)
            elif option == "wpa_handshakes":
                self.aircommunicator.print_captured_handshakes(
                    filter_string, False)
            elif option == "half_wpa_handshakes":
                self.aircommunicator.print_captured_handshakes(
                    filter_string, True)
            elif option == "wep_data_logs":
                self.aircommunicator.print_wep_data_logs(filter_string)

    def complete_show(self, text, line, begidx, endidx):
        if not text or text == "":
            return self.show_empty_text_show_options(line)
        else:
            return self.show_to_complete_show_options(line, text)

    def show_empty_text_show_options(self, line):
        entered = line.split()
        out = None
        if len(entered) < 3:
            out = self.complete_filter_command(self.show_options, "", entered)
        elif len(entered) >= 3:
            # list filter args (id, ssid, bssid, channel, etc...)
            if entered[1] == "sniffed_aps":
                out = vars(AccessPoint()).keys()
            elif entered[1] == "sniffed_clients":
                out = vars(WiFiClient()).keys()
            elif entered[1] == "sniffed_probes":
                out = vars(ProbeInfo()).keys()
            elif entered[1] == "ap_targets":
                out = vars(AccessPoint()).keys()
            elif entered[1] == "client_targets":
                out = vars(WiFiClient()).keys()
            elif entered[1] == "connected_clients":
                out = vars(Client()).keys()
            elif entered[1] == "wpa_handshakes" or entered[
                    1] == "half_wpa_handshakes":
                out = vars(WPAHandshake()).keys()

        return out

    def show_to_complete_show_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) < 4:
            out = self.complete_filter_command(self.show_options, text,
                                               entered)
        elif len(entered) >= 4:
            start = entered[-1]
            if entered[1] in self.show_options:
                if entered[1] == "sniffed_aps":
                    out = [
                        keyword for keyword in vars(AccessPoint()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "sniffed_clients":
                    out = [
                        keyword for keyword in vars(WiFiClient()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "sniffed_probes":
                    out = [
                        keyword for keyword in vars(ProbeInfo()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "ap_targets":
                    out = [
                        keyword for keyword in vars(AccessPoint()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "client_targets":
                    out = [
                        keyword for keyword in vars(WiFiClient()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "connected_clients":
                    out = [
                        keyword for keyword in vars(Client()).keys()
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "wpa_handshakes" or entered[
                        1] == "half_wpa_handshakes":
                    out = [
                        keyword for keyword in vars(WPAHandshake()).keys()
                        if keyword.startswith(start)
                    ]
        return out

    # Start

    def do_start(self, args):
        args = args.split()
        if len(args) >= 1:
            service = args[0]
            plugins = []
            if "with" in args:
                plugins = args[args.index("with") + 1:]

            if "air" in service:
                self.aircommunicator.service(service, "start", plugins)
            elif service == "mitmproxy":
                self.start_mitmproxy(plugins)

    def start_mitmproxy(self, plugins):
        mitm_configs = self.configs["etf"]["mitmproxy"]
        try:
            listen_port = int(mitm_configs["lport"])  # Verify if it is integer
            listen_host = mitm_configs["lhost"] if len(
                mitm_configs["lhost"].split(".")) == 4 else "127.0.0.1"
            ssl = mitm_configs["ssl"].lower() == "true"
            client_cert = mitm_configs["client_cert"]
            certs = mitm_configs["certs"]
            if type(certs) is not list and certs != "":
                certs = [certs]
            elif certs == "":
                certs = []

            certs = map(lambda x: x.split("=")
                        if "=" in x else ["*", x], certs)

            mitm_plugins = []
            for plugin in plugins:
                if plugin in self.mitmproxy_plugins:
                    mitm_plugins.append(plugin)

        except Exception as e:
            print "[-] Something is wrong with the configuration of mitmproxy:\n", e
            return

        self.etfitm.pass_config(listen_host, listen_port, ssl, client_cert,
                                certs, mitm_plugins)
        self.etfitm.start()

    def do_stop(self, args):
        args = args.split()
        if len(args) >= 1:
            service = args[0]
            if "air" in service:
                self.aircommunicator.service(service, "stop")
            elif service == "mitmproxy":
                self.etfitm.stop()

    def complete_start(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def complete_stop(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def complete_status(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def _complete_basic(self, line, text):
        if not text or text == "":
            return self.show_empty_text_start_options(line)
        else:
            return self.show_to_complete_start_options(line, text)

    def show_empty_text_start_options(self, line):
        entered = line.split()
        out = None
        if len(entered) == 1:
            out = self.services
        elif len(entered) == 2:
            out = self.plugin_keyword
        elif len(entered) >= 3:
            if entered[1] == "airhost":
                out = self.airhost_plugins
            elif entered[1] == "airscanner":
                out = self.airscanner_plugins
            elif entered[1] == "airinjector":
                out = self.airinjector_plugins
            elif entered[1] == "mitmproxy":
                out = self.mitmproxy_plugins

        return out

    def show_to_complete_start_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) == 2:
            # Here the first parameter after 'air' is already complete and the user wants the next
            if entered[1] in self.services:
                out = [text + " "]
            # Here the first parameter after 'air' is incomplete and the user wants completion
            else:
                start = entered[1]
                out = [
                    keyword for keyword in self.services
                    if keyword.startswith(start)
                ]
        elif len(entered) == 3:
            # Completion for the 'with' keyword
            if entered[2] in self.plugin_keyword:
                out = [text + " "]
            else:
                out = self.plugin_keyword
        elif len(entered) >= 4:
            start = entered[-1]
            if entered[1] in self.services:
                if entered[1] == "airhost":
                    out = [
                        keyword for keyword in self.airhost_plugins
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "airscanner":
                    out = [
                        keyword for keyword in self.airscanner_plugins
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "airinjector":
                    out = [
                        keyword for keyword in self.airinjector_plugins
                        if keyword.startswith(start)
                    ]
                elif entered[1] == "mitmproxy":
                    out = [
                        keyword for keyword in self.mitmproxy_plugins
                        if keyword.startswith(start)
                    ]

        return out

    def do_crack(self, args):
        args = args.split()
        try:
            id, is_handshake, is_half = int(
                args[1]), "handshake" in args[0], "half" in args[0]
        except:
            print "[-] ID must be int"
            return
        if is_handshake:
            self.aircommunicator.crack_handshake(id, is_half)
        else:
            self.aircommunicator.crack_wep(id)

    def complete_crack(self, text, line, begidx, endidx):
        out = None
        entered = line.split()

        if not text or text == "":
            if len(entered) == 1:
                out = self.crack_options
        else:
            if len(entered) == 2:
                if entered[1] in self.crack_options:
                    out = [text + " "]
                else:
                    out = [
                        keyword for keyword in self.crack_options
                        if keyword.startswith(entered[1])
                    ]
        return out

    def update_prompt(self):
        self.prompt = "ETF{mode_start}{mode}{mode_end}::> ".format(
            mode_start=colored("[", "cyan"),
            mode=colored(console.config_mode_string, "green"),
            mode_end=colored("]", "cyan"))

    def do_EOF(self, line):  # control-D
        print "Exiting..."
        self.aircommunicator.stop_air_communications(True, True, True)
        console.aircommunicator.network_manager.cleanup()
        self.etfitm.stop()
        self.spawnmanager.restore_all()
        os._exit(0)

    # Just overwriting this method so it doesn't execute the last non-empty line
    def emptyline(self):
        pass
class ETFConsole(Cmd):

    def __init__(self, history = []):
        # Super for "old style" class
        Cmd.__init__(self)
        # Load command history
        for cmd in history:
            readline.add_history(cmd.strip())

        # Backend Tools
        self.configmanager = ConfigurationManager("core/ConfigurationManager/etf.conf")
        self.configs = self.configmanager.config
        self.aircommunicator = AirCommunicator(self.configs["etf"]["aircommunicator"])
        self.etfitm          = EvilInTheMiddle(self.configs["etf"]["mitmproxy"])
        self.spawnmanager    = SpawnManager(self.configs["etf"]["spawner"])

        # Static strings to help with autocompletion

        self.basic_commands = [  "start", "stop", "status",
                            "spawn", "restore",
                            "getconf", "setconf", "config", "back", "listargs",
                            "copy", "add", "del", "display",
                            "new_session", "save_session", "load_session"  ]

        self.services = ["airhost", "airscanner", "airinjector", "aircracker", "mitmproxy"]
        self.aux_services = ["aplauncher", "dnsmasqhandler"]
        self.spawners = ["mitmf", "beef-xss", "ettercap", "sslstrip"]

        self.filter_keywords = ["where", "only"]
        self.plugin_keyword = ["with"]

        self.airhost_plugins = ["dnsspoofer", "credentialsniffer", "karma"]
        self.airscanner_plugins = ["packetlogger", "selfishwifi", "credentialsniffer", "arpreplayer", "caffelatte"]
        self.airinjector_plugins = ["credentialsniffer", "deauthenticator", "arpreplayer", "caffelatte"]
        self.aircracker_types = ["wpa_crackers", "half_wpa_crackers"]
        self.aircrackers = ["cowpatty", "aircrack-ng", "halwpaid"]
        self.mitmproxy_plugins = ["downloadreplacer", "beefinjector", "peinjector"]

        self.copy_options = ["ap", "probe"]
        self.add_del_options = ["aps", "clients", "probes"]                             # Meant to be followed by ID
        self.display_options = ["sniffed_aps", "sniffed_probes", "sniffed_clients",
                        "ap_targets", "client_targets", "connected_clients",
                        "wpa_handshakes", "half_wpa_handshakes", "wep_data_logs",
                        "caffelatte_data_logs", "sessions"]                             # Meant to be followed by filter
        self.crack_options = ["wpa_handshakes", "half_wpa_handshakes",
                         "wep_data", "caffelatte_data"]                                 # Meant to be followed by ID

        self.display_options_vars =  {
                                    "sniffed_aps"           : vars(AccessPoint()).keys(),
                                    "sniffed_probes"        : vars(ProbeInfo()).keys(),
                                    "sniffed_clients"       : vars(WiFiClient()).keys(),
                                    "ap_targets"            : vars(AccessPoint()).keys(),
                                    "client_targets"        : vars(WiFiClient()).keys(),
                                    "connected_clients"     : vars(Client()).keys(),
                                    "wpa_handshakes"        : vars(WPAHandshake()).keys(),
                                    "half_wpa_handshakes"   : vars(WPAHandshake()).keys(),
                                    "wep_data_logs"         : vars(WEPDataFile()).keys(),
                                    "caffelatte_data_logs"  : vars(CaffeLatteDataFile()).keys(),
                                    "sessions"              : vars(Session()).keys()
                                }

        self.display_options_methods =   {
                                        "sniffed_aps"           : self.aircommunicator.print_sniffed_aps,
                                        "sniffed_clients"       : self.aircommunicator.print_sniffed_clients,
                                        "sniffed_probes"        : self.aircommunicator.print_sniffed_probes,
                                        "ap_targets"            : self.aircommunicator.print_ap_injection_targets,
                                        "client_targets"        : self.aircommunicator.print_client_injection_targets,
                                        "connected_clients"     : self.aircommunicator.print_connected_clients,
                                        "wpa_handshakes"        : self.aircommunicator.print_captured_handshakes,
                                        "half_wpa_handshakes"   : self.aircommunicator.print_captured_half_handshakes,
                                        "wep_data_logs"         : self.aircommunicator.print_wep_data_logs,
                                        "caffelatte_data_logs"  : self.aircommunicator.print_caffelatte_data_logs,
                                        "sessions"              : SessionManager().print_sessions
                                    }

        self.plugin_options =   {
                                    "airhost"       : self.airhost_plugins,
                                    "airscanner"    : self.airscanner_plugins,
                                    "airinjector"   : self.airinjector_plugins,
                                    "mitmproxy"     : self.mitmproxy_plugins,
                                }

        self.addel_options =    {
                                    "aps"     : vars(AccessPoint()).keys(),
                                    "clients" : vars(WiFiClient()).keys(),
                                    "probes"  : vars(ProbeInfo()).keys()
                                }

        # Configuration Handling
        self.current_config_mode = self.configs["etf"]["aircommunicator"]
        self.config_mode_string = "etf/aircommunicator/"

    # do and complete of configuration options
    def do_restore(self, args):
        entered = args.split()
        if len(entered) != 1:
            print "[-] Only 1 argument expected after spawn command"

        self.spawnmanager.restore_spawner(args)

    def do_spawn(self, args):
        entered = args.split()
        if len(entered) != 1:
            print "[-] Only 1 argument expected after spawn command"
        try:
            self.spawnmanager.add_spawner(args)
        except KeyError as e:
            print e
            print "[-] Spawner for '{}' does not exist.".format(args)

    def spawner_completion(self, text, line):
        entered = line.split()
        out = None
        if len(entered) == 1:
            out = self.spawners
        elif len(entered) == 2:
            out = [option for option in self.spawners if option.startswith(text)]

        return out

    def complete_spawn(self, text, line, begidx, endidx):
        return self.spawner_completion(text, line)

    def complete_restore(self, text, line, begidx, endidx):
        return self.spawner_completion(text, line)

    def do_listargs(self, args):
        is_var = lambda key: (  isinstance(self.current_config_mode[key], str) or
                                isinstance(self.current_config_mode[key], list))

        print "\n".join([ "{:>20} ={:>20}; ({})".format(key,
                            self.current_config_mode[key] if is_var(key) else "(dict)",
                            "var" if is_var(key) else "mode")
                        for key in self.current_config_mode.keys()])

    def do_back(self, args):
        mode = [mode for mode in self.config_mode_string.split("/") if mode != '']
        if len(mode) == 1:
            pass
        else:
            mode = mode[:-1]
            self.config_mode_string = ""
            self.current_config_mode = self.configs
            for layer in mode:
                self.current_config_mode = self.current_config_mode[layer]
                self.config_mode_string += layer + "/"

        self.update_prompt()

    def do_config(self, args):
        arg = args.split()
        if len(arg) != 1:
            print "[-] Only 1 arg expected after 'config'"
            return

        try:
            config_key = arg[0]
            dict_string, config = self._look_for_config("", self.configs, config_key)
            dict_string = "/".join(dict_string[:-1].split("/")[::-1])  # the output string is from bottom to top, we reverse
            self.current_config_mode = config
            self.config_mode_string = dict_string
            self.update_prompt()
        except Exception:
            print "'{key}' does not exist in the configuration file".format(key = config_key)

    def _look_for_config(self, dict_string, dict_root, dict_key):
        if dict_key in dict_root:
            dict_string += dict_key + "/"
            return (dict_string, dict_root[dict_key])

        for key, value in dict_root.items():
            if isinstance(value, dict):
                try:
                    dict_string, item = self._look_for_config(dict_string, value, dict_key)
                    dict_string += key + "/"
                    if item is not None:
                        return (dict_string, item)
                except: pass

    def complete_config(self, text, line, begidx, endidx):
        args = line.split()
        all_configs =   self.services + \
                        self.aux_services + \
                        self.spawners + \
                        self.airscanner_plugins + \
                        self.airhost_plugins + \
                        self.airinjector_plugins + \
                        self.aircracker_types + \
                        self.aircrackers + \
                        self.mitmproxy_plugins

        if len(args) == 1:
            return all_configs
        elif len(args) == 2:
            return [config for config in all_configs if config.startswith(args[1])]

    def do_getconf(self, args):
        var = args.split()
        if len(var) != 1:
            print "[-] Only 1 arg expected after 'get'"
            return

        try:
            mode = var[0]
            if isinstance(self.current_config_mode[mode], str) or \
               isinstance(self.current_config_mode[mode], list):

                config, value = mode, self.current_config_mode[mode]
                print "{config} = {value}".format(  config = config,
                                                    value = self.current_config_mode[mode])
        except KeyError:
            print "'{key}' does not exist in the configuration file".format(key = mode)

    def complete_getconf(self, text, line, begidx, endidx):
        return self.complete_vars(text)

    def do_setconf(self, args):
        is_var = lambda key: (  isinstance(self.current_config_mode[key], str) or
                                isinstance(self.current_config_mode[key], list))
        try:
            splitted_args = args.split()
            if len(splitted_args) == 2:
                var, value = splitted_args[0], splitted_args[1]
            else:
                var, value = splitted_args[0], splitted_args[1:]

            # raise KeyError before assignment if option does not exist
            if not is_var(var):
                return

            self.configmanager.set_global_config(var, value)
            self.configmanager.write()
            print "{config} = {value}".format(  config = var,
                                                value = self.current_config_mode[var])
        except KeyError:
            print "'{key}' does not exist in the configuration file".format(key = var)
        except Exception as e:
            raise e
            pass

    def complete_setconf(self, text, line, begidx, endidx):
        return self.complete_vars(text)

    def complete_vars(self, text):
        out = [keyword for keyword  in  self.current_config_mode
                                    if  keyword.startswith(text) and
                                        (isinstance(self.current_config_mode[keyword], str) or
                                        isinstance(self.current_config_mode[keyword], list))]
        return out

    def complete_modes(self, text):
        out = [keyword for keyword  in  self.current_config_mode
                                    if  keyword.startswith(text) and not
                                        (isinstance(self.current_config_mode[keyword], str) or
                                        isinstance(self.current_config_mode[keyword], list))]
        return out

    # Copy Add Del
    def do_copy(self, args):
        args = args.split()
        if len(args) == 2:
            try:
                id = int(args[-1])  # line should be something like "copy ap 4"
            except ValueError:
                print "[-] ID must be an integer value"
                print "Copy syntax: copy [option] [ID]"
                return
            if args[0] == "ap":
                self.aircommunicator.airhost_copy_ap(id)
            elif args[0] == "probe":
                self.aircommunicator.airhost_copy_probe(id)

    def complete_copy(self, text, line, begidx, endidx):
        entered = line.split()
        if len(entered) == 1:
            if not text or text == "":
                return self.copy_options
        elif len(entered) == 2:
            start = entered[1]
            return [option for option in self.copy_options if option.startswith(start)]

    def do_add(self, args):
        args = args.split()
        if len(args) >= 1:
            filter_string = self._parse_filter_string(args)
            self.aircommunicator.injector_add(args[0], filter_string)

    def do_del(self, args):
        args = args.split()
        if len(args) >= 1:
            filter_string = self._parse_filter_string(args)
            self.aircommunicator.injector_del(args[0], filter_string)

    def complete_add(self, text, line, begidx, endidx):
        return self.complete_addel(line, text)

    def complete_del(self, text, line, begidx, endidx):
        return self.complete_addel(line, text)

    def _parse_filter_string(self, args):
        filter_string = None
        if len(args) == 3:
            try:
                id = int(args[2])
                filter_string = "where id = {}".format(str(id))
            except:
                pass
        elif len(args) > 3:
            filter_string = " ".join(args[1:])

        return filter_string

    def complete_addel(self, line, text):
        if not text or text == "":
            return self.show_empty_text_addel_options(line)
        else:
            return self.show_to_complete_addel_options(line, text)

    def show_empty_text_addel_options(self, line):
        entered = line.split()
        out = None
        if len(entered) < 3:
            out = self.complete_filter_command(self.add_del_options, "", entered)
        elif len(entered) >= 3:
            # list filter args (id, ssid, bssid, channel, etc...)
            try:
                out = self.addel_options[entered[1]]
            except:
                print "[-] No option to add or del called '{}' !".format(entered[1])

        return out

    def show_to_complete_addel_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) <= 3:
            out = self.complete_filter_command(self.add_del_options, text, entered)
        elif len(entered) > 3:
            start = entered[-1]
            try:
                out = [keyword for keyword in self.addel_options[entered[1]] if keyword.startswith(start)]
            except:
                print "[-] No option to add or del called '{}' !".format(entered[1])

        return out

    def complete_filter_command(self, options, text, entered):
        out = None
        if not text or text == "":
            if len(entered) == 1:
                out = options
            elif len(entered) == 2:
                out = self.filter_keywords
        else:
            if len(entered) == 2:
                # Here the first parameter after 'show' is already complete and the user wants the next
                if entered[1] in options:
                    out = [text + " "]
                # Here the first parameter after 'show' is incomplete and the user wants completion
                else:
                    start = entered[1]
                    out = [keyword for keyword in options if keyword.startswith(start)]
            elif len(entered) == 3:
                # Completion for the 'where' or 'only' keyword
                if entered[2] in self.filter_keywords:
                    out = [text + " "]
                else:
                    start = entered[2]
                    out = [keyword for keyword in self.filter_keywords if keyword.startswith(start)]
        return out

    # Display
    def do_display(self, args):
        args = args.split()
        if len(args) >= 1:
            option = args[0]
            filter_string = ""
            if len(args) >= 2:
                filter_string = " ".join(args[1:])

            if option in self.display_options_methods.keys():
                self.display_options_methods[option](filter_string)

    def complete_display(self, text, line, begidx, endidx):
        if not text or text == "":
            return self.display_empty_text_display_options(line)
        else:
            return self.display_to_complete_display_options(line, text)

    def display_empty_text_display_options(self, line):
        entered = line.split()
        out = None
        if len(entered) < 3:
            out = self.complete_filter_command(self.display_options, "", entered)
        elif len(entered) >= 3:
            # list filter args (id, ssid, bssid, channel, etc...)
            try:
                out = self.display_options_vars[entered[1]]
            except:
                print "[-] No display option called '{}' !".format(entered[1])

        return out

    def display_to_complete_display_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) < 4:
            out = self.complete_filter_command(self.display_options, text, entered)
        elif len(entered) >= 4:
            start = entered[-1]
            if entered[1] in self.display_options:
                try:
                    out = [keyword for keyword in self.display_options_vars[entered[1]] if keyword.startswith(start)]
                except:
                    print "[-] No display option called '{}' !".format(entered[1])

        return out

    # Start
    def do_start(self, args):
        args = args.split()
        if len(args) >= 1:
            service = args[0]
            plugins = []
            if "with" in args:
                plugins = args[args.index("with") + 1:]
            if "air" in service:
                self.aircommunicator.service(service, "start", plugins)
            elif service == "mitmproxy":
                self.start_mitmproxy(plugins)

    def start_mitmproxy(self, plugins):
        mitm_configs = self.configs["etf"]["mitmproxy"]
        try:
            listen_port = int(mitm_configs["lport"])  # Verify if it is integer
            listen_host = mitm_configs["lhost"] if len(mitm_configs["lhost"].split(".")) == 4 else "127.0.0.1"
            ssl = mitm_configs["ssl"].lower() == "true"
            client_cert = mitm_configs["client_cert"]
            certs       = mitm_configs["certs"]
            if type(certs) is not list and certs != "":
                certs = [certs]
            elif certs == "":
                certs = []

            certs = map(lambda x: x.split("=") if "=" in x else ["*", x], certs)

            mitm_plugins = []
            for plugin in plugins:
                if plugin in self.mitmproxy_plugins:
                    mitm_plugins.append(plugin)

        except Exception as e:
            print "[-] Something is wrong with the configuration of mitmproxy:\n", e
            return

        self.etfitm.pass_config(listen_host, listen_port, ssl, client_cert, certs, mitm_plugins)
        self.etfitm.start()

    def do_stop(self, args):
        args = args.split()
        if len(args) >= 1:
            service = args[0]
            if "air" in service:
                self.aircommunicator.service(service, "stop")
            elif service == "mitmproxy":
                self.etfitm.stop()

    def complete_start(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def complete_stop(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def complete_status(self, text, line, begidx, endidx):
        return self._complete_basic(line, text)

    def _complete_basic(self, line, text):
        if not text or text == "":
            return self.show_empty_text_start_options(line)
        else:
            return self.show_to_complete_start_options(line, text)

    def show_empty_text_start_options(self, line):
        entered = line.split()
        out = None
        if len(entered) == 1:
            out = self.services
        elif len(entered) == 2:
            out = self.plugin_keyword
        elif len(entered) >= 3:
            try:
                out = self.plugin_options[entered[1]]
            except:
                print "[-] No plugin options for '{}'".format(entered[1])

        return out

    def show_to_complete_start_options(self, line, text):
        entered = line.split()
        out = None
        if len(entered) == 2:
            # Here the first parameter after 'start' is already complete and the user wants the next
            if entered[1] in self.services:
                out = [text + " "]
            # Here the first parameter after 'start' is incomplete and the user wants completion
            else:
                start = entered[1]
                out = [keyword for keyword in self.services if keyword.startswith(start)]
        elif len(entered) == 3:
            # Completion for the 'with' keyword
            if entered[2] in self.plugin_keyword:
                out = [text + " "]
            else:
                out = self.plugin_keyword
        elif len(entered) >= 4:
            start = entered[-1]
            if entered[1] in self.services:
                try:
                    out = [keyword for keyword in self.plugin_options[entered[1]] if keyword.startswith(start)]
                except:
                    print "[-] No plugin options for '{}'".format(entered[1])

        return out

    def do_crack(self, args):
        args = args.split()
        try:
            id, is_handshake, is_half, is_latte = int(args[1]), "handshake"in args[0], "half" in args[0], "latte" in args[0]
        except:
            print "[-] ID must be int"
            return
        if is_handshake:
            self.aircommunicator.crack_handshake(id, is_half)
        else:
            self.aircommunicator.crack_wep(id, is_latte)

    def complete_crack(self, text, line, begidx, endidx):
        out = None
        entered = line.split()

        if not text or text == "":
            if len(entered) == 1:
                out = self.crack_options
        else:
            if len(entered) == 2:
                if entered[1] in self.crack_options:
                    out = [text + " "]
                else:
                    out = [keyword for keyword in self.crack_options if keyword.startswith(entered[1])]
        return out

    def do_new_session(self, args):
        args = args.split()
        if len(args) == 0:
            print "[-] You have to specify a name for a the new session."
            return

        name = "_".join(args)
        SessionManager().start_new_session(name)
        self.aircommunicator.load_session_data()

    def do_save_session(self, args):
        args = args.split()
        if SessionManager().get_current_session_name() != "":
            SessionManager().save_session()
            print "[+] Saved current session '{}' under '{}'!".format(SessionManager().get_current_session_name(),
                                                                      SessionManager().get_current_session_path())
        else:
            if len(args) >= 1:
                SessionManager().save_session(args[0])
                print "[+] Saved current session '{}' under '{}'!".format(SessionManager().get_current_session_name(),
                                                                          SessionManager().get_current_session_path())
            else:
                print "Cannot save nameless session. Please add a name after the command."

    def do_load_session(self, args):
        args = args.split()
        try:
            index = int(args[0])
        except:
            print "[-] Index must be Integer."
            return

        SessionManager().load_session(index)

    def update_prompt(self):
        self.prompt = "ETF{mode_start}{mode}{mode_end}::> ".format( mode_start = colored("[", "cyan"),
                                                                    mode = colored(console.config_mode_string, "green"),
                                                                    mode_end = colored("]", "cyan"))

    def do_eof(self, line):  # control-D
        print "[+] Stopping all air communications"
        self.aircommunicator.stop_air_communications(True, True, True)
        self.aircommunicator.network_manager.cleanup()
        self.etfitm.stop()
        self.spawnmanager.restore_all()
        print "Closing Session..."
        SessionManager().close_session()
        print "Exiting..."
        os._exit(0)

    # Just overwriting this method so it doesn't execute the last non-empty line
    def emptyline(self):
        pass

    def postcmd(self, stop, line):
        complete_line = readline.get_history_item(readline.get_current_history_length())
        if complete_line.strip() != "":
            SessionManager().log_command(complete_line)
    def __init__(self, history = []):
        # Super for "old style" class
        Cmd.__init__(self)
        # Load command history
        for cmd in history:
            readline.add_history(cmd.strip())

        # Backend Tools
        self.configmanager = ConfigurationManager("core/ConfigurationManager/etf.conf")
        self.configs = self.configmanager.config
        self.aircommunicator = AirCommunicator(self.configs["etf"]["aircommunicator"])
        self.etfitm          = EvilInTheMiddle(self.configs["etf"]["mitmproxy"])
        self.spawnmanager    = SpawnManager(self.configs["etf"]["spawner"])

        # Static strings to help with autocompletion

        self.basic_commands = [  "start", "stop", "status",
                            "spawn", "restore",
                            "getconf", "setconf", "config", "back", "listargs",
                            "copy", "add", "del", "display",
                            "new_session", "save_session", "load_session"  ]

        self.services = ["airhost", "airscanner", "airinjector", "aircracker", "mitmproxy"]
        self.aux_services = ["aplauncher", "dnsmasqhandler"]
        self.spawners = ["mitmf", "beef-xss", "ettercap", "sslstrip"]

        self.filter_keywords = ["where", "only"]
        self.plugin_keyword = ["with"]

        self.airhost_plugins = ["dnsspoofer", "credentialsniffer", "karma"]
        self.airscanner_plugins = ["packetlogger", "selfishwifi", "credentialsniffer", "arpreplayer", "caffelatte"]
        self.airinjector_plugins = ["credentialsniffer", "deauthenticator", "arpreplayer", "caffelatte"]
        self.aircracker_types = ["wpa_crackers", "half_wpa_crackers"]
        self.aircrackers = ["cowpatty", "aircrack-ng", "halwpaid"]
        self.mitmproxy_plugins = ["downloadreplacer", "beefinjector", "peinjector"]

        self.copy_options = ["ap", "probe"]
        self.add_del_options = ["aps", "clients", "probes"]                             # Meant to be followed by ID
        self.display_options = ["sniffed_aps", "sniffed_probes", "sniffed_clients",
                        "ap_targets", "client_targets", "connected_clients",
                        "wpa_handshakes", "half_wpa_handshakes", "wep_data_logs",
                        "caffelatte_data_logs", "sessions"]                             # Meant to be followed by filter
        self.crack_options = ["wpa_handshakes", "half_wpa_handshakes",
                         "wep_data", "caffelatte_data"]                                 # Meant to be followed by ID

        self.display_options_vars =  {
                                    "sniffed_aps"           : vars(AccessPoint()).keys(),
                                    "sniffed_probes"        : vars(ProbeInfo()).keys(),
                                    "sniffed_clients"       : vars(WiFiClient()).keys(),
                                    "ap_targets"            : vars(AccessPoint()).keys(),
                                    "client_targets"        : vars(WiFiClient()).keys(),
                                    "connected_clients"     : vars(Client()).keys(),
                                    "wpa_handshakes"        : vars(WPAHandshake()).keys(),
                                    "half_wpa_handshakes"   : vars(WPAHandshake()).keys(),
                                    "wep_data_logs"         : vars(WEPDataFile()).keys(),
                                    "caffelatte_data_logs"  : vars(CaffeLatteDataFile()).keys(),
                                    "sessions"              : vars(Session()).keys()
                                }

        self.display_options_methods =   {
                                        "sniffed_aps"           : self.aircommunicator.print_sniffed_aps,
                                        "sniffed_clients"       : self.aircommunicator.print_sniffed_clients,
                                        "sniffed_probes"        : self.aircommunicator.print_sniffed_probes,
                                        "ap_targets"            : self.aircommunicator.print_ap_injection_targets,
                                        "client_targets"        : self.aircommunicator.print_client_injection_targets,
                                        "connected_clients"     : self.aircommunicator.print_connected_clients,
                                        "wpa_handshakes"        : self.aircommunicator.print_captured_handshakes,
                                        "half_wpa_handshakes"   : self.aircommunicator.print_captured_half_handshakes,
                                        "wep_data_logs"         : self.aircommunicator.print_wep_data_logs,
                                        "caffelatte_data_logs"  : self.aircommunicator.print_caffelatte_data_logs,
                                        "sessions"              : SessionManager().print_sessions
                                    }

        self.plugin_options =   {
                                    "airhost"       : self.airhost_plugins,
                                    "airscanner"    : self.airscanner_plugins,
                                    "airinjector"   : self.airinjector_plugins,
                                    "mitmproxy"     : self.mitmproxy_plugins,
                                }

        self.addel_options =    {
                                    "aps"     : vars(AccessPoint()).keys(),
                                    "clients" : vars(WiFiClient()).keys(),
                                    "probes"  : vars(ProbeInfo()).keys()
                                }

        # Configuration Handling
        self.current_config_mode = self.configs["etf"]["aircommunicator"]
        self.config_mode_string = "etf/aircommunicator/"
Esempio n. 5
0
    def __init__(self, history=[]):
        # Super for "old style" class
        Cmd.__init__(self)
        # Load command history
        for cmd in history:
            readline.add_history(cmd.strip())

        # Backend Tools
        self.configmanager = ConfigurationManager(
            "core/ConfigurationManager/etf.conf")
        self.configs = self.configmanager.config
        self.aircommunicator = AirCommunicator(
            self.configs["etf"]["aircommunicator"])
        self.etfitm = EvilInTheMiddle(self.configs["etf"]["mitmproxy"])
        self.spawnmanager = SpawnManager(self.configs["etf"]["spawner"])

        # Static strings to help with autocompletion

        self.basic_commands = [
            "start", "stop", "status", "spawn", "restore", "getconf",
            "setconf", "config", "back", "listargs", "copy", "add", "del",
            "display", "new_session", "save_session", "load_session"
        ]

        self.services = [
            "airhost", "airscanner", "airinjector", "aircracker", "mitmproxy"
        ]
        self.aux_services = ["aplauncher", "dnsmasqhandler"]
        self.spawners = ["mitmf", "beef-xss", "ettercap", "sslstrip"]

        self.filter_keywords = ["where", "only"]
        self.plugin_keyword = ["with"]

        self.airhost_plugins = ["dnsspoofer", "credentialsniffer", "karma"]
        self.airscanner_plugins = [
            "packetlogger", "selfishwifi", "credentialsniffer", "arpreplayer",
            "caffelatte"
        ]
        self.airinjector_plugins = [
            "credentialsniffer", "deauthenticator", "arpreplayer", "caffelatte"
        ]
        self.aircracker_types = ["wpa_crackers", "half_wpa_crackers"]
        self.aircrackers = ["cowpatty", "aircrack-ng", "halwpaid"]
        self.mitmproxy_plugins = [
            "downloadreplacer", "beefinjector", "peinjector"
        ]

        self.copy_options = ["ap", "probe"]
        self.add_del_options = ["aps", "clients",
                                "probes"]  # Meant to be followed by ID
        self.display_options = [
            "sniffed_aps", "sniffed_probes", "sniffed_clients", "ap_targets",
            "client_targets", "connected_clients", "wpa_handshakes",
            "half_wpa_handshakes", "wep_data_logs", "caffelatte_data_logs",
            "sessions"
        ]  # Meant to be followed by filter
        self.crack_options = [
            "wpa_handshakes", "half_wpa_handshakes", "wep_data",
            "caffelatte_data"
        ]  # Meant to be followed by ID

        self.display_options_vars = {
            "sniffed_aps": vars(AccessPoint()).keys(),
            "sniffed_probes": vars(ProbeInfo()).keys(),
            "sniffed_clients": vars(WiFiClient()).keys(),
            "ap_targets": vars(AccessPoint()).keys(),
            "client_targets": vars(WiFiClient()).keys(),
            "connected_clients": vars(Client()).keys(),
            "wpa_handshakes": vars(WPAHandshake()).keys(),
            "half_wpa_handshakes": vars(WPAHandshake()).keys(),
            "wep_data_logs": vars(WEPDataFile()).keys(),
            "caffelatte_data_logs": vars(CaffeLatteDataFile()).keys(),
            "sessions": vars(Session()).keys()
        }

        self.display_options_methods = {
            "sniffed_aps": self.aircommunicator.print_sniffed_aps,
            "sniffed_clients": self.aircommunicator.print_sniffed_clients,
            "sniffed_probes": self.aircommunicator.print_sniffed_probes,
            "ap_targets": self.aircommunicator.print_ap_injection_targets,
            "client_targets":
            self.aircommunicator.print_client_injection_targets,
            "connected_clients": self.aircommunicator.print_connected_clients,
            "wpa_handshakes": self.aircommunicator.print_captured_handshakes,
            "half_wpa_handshakes":
            self.aircommunicator.print_captured_half_handshakes,
            "wep_data_logs": self.aircommunicator.print_wep_data_logs,
            "caffelatte_data_logs":
            self.aircommunicator.print_caffelatte_data_logs,
            "sessions": SessionManager().print_sessions
        }

        self.plugin_options = {
            "airhost": self.airhost_plugins,
            "airscanner": self.airscanner_plugins,
            "airinjector": self.airinjector_plugins,
            "mitmproxy": self.mitmproxy_plugins,
        }

        self.addel_options = {
            "aps": vars(AccessPoint()).keys(),
            "clients": vars(WiFiClient()).keys(),
            "probes": vars(ProbeInfo()).keys()
        }

        # Configuration Handling
        self.current_config_mode = self.configs["etf"]["aircommunicator"]
        self.config_mode_string = "etf/aircommunicator/"