Exemplo n.º 1
0
 def __init__(self, session, config_path=None):
     reset_config(filepath=config_path)
     try:
         control_config()
     except ValueError as e:
         logger.error(e)
         raise e
     self.config_path = config_path
     self.host = config.get(Sections.SERVER, "host")
     self.api_port = config.get(Sections.SERVER, "api_port")
     self.websocket_port = config.get(Sections.SERVER, "websocket_port")
     self.workspace = config.get(Sections.SERVER, "workspace")
     self.agent_token = config[Sections.TOKENS].get("agent", None)
     self.agent_name = config.get(Sections.AGENT, "agent_name")
     self.session = session
     self.websocket = None
     self.websocket_token = None
     executors_list_str = config[Sections.AGENT].get("executors", []).split(",")
     if "" in executors_list_str:
         executors_list_str.remove("")
     self.executors = {
         executor_name:
             Executor(executor_name, config) for executor_name in executors_list_str
     }
     ssl_cert_path = config[Sections.SERVER].get("ssl_cert", None)
     self.ws_ssl_enabled = self.api_ssl_enabled = config[Sections.SERVER].get("ssl", "False").lower() in ["t", "true"]
     self.api_kwargs = {"ssl": ssl.create_default_context(cafile=ssl_cert_path)} if self.api_ssl_enabled and ssl_cert_path else {}
     self.ws_kwargs = {"ssl": ssl.create_default_context(cafile=ssl_cert_path)} if self.ws_ssl_enabled and ssl_cert_path else {}
     self.execution_id = None
def test_with_agent_token(delete_token):
    runner = CliRunner()

    content_path = old_version_path() / '1.0_with_agent_token.ini'

    with open(content_path, 'r') as content_file:
        content = content_file.read()

    with runner.isolated_filesystem() as file_system:

        path = Path(file_system) / "dispatcher.ini"
        with path.open(mode="w") as content_file:
            content_file.write(content)
        env = os.environ
        env["DEBUG_INPUT_MODE"] = "True"
        input_str = f"A\n{DispatcherInput(delete_agent_token=delete_token).input_str()}Q\n"
        escape_string = "\0\n" * 1000
        result = runner.invoke(config_wizard,
                               args=["-c", path],
                               input=f'{input_str}{escape_string}',
                               env=env)
        assert result.exit_code == 0, result.exception

        config_mod.reset_config(path)
        if delete_token:
            assert "agent" not in config_mod.instance.options(
                config_mod.Sections.TOKENS)
        else:
            assert "agent" in config_mod.instance.options(
                config_mod.Sections.TOKENS)
def test_basic_built(tmp_custom_config, config_changes_dict):  # noqa F811
    reset_config(tmp_custom_config.config_file_path)
    config_path = tmp_custom_config.config_file_path.with_suffix(".yaml")
    for section in config_changes_dict["replace"]:
        for option in config_changes_dict["replace"][section]:
            if section == "executor":
                if "ex1" not in configuration[Sections.AGENT][Sections.EXECUTORS]:
                    configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"] = {}
                configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"][option] = config_changes_dict["replace"][
                    section
                ][option]
                continue
            elif section not in configuration:
                configuration[section] = {}
            configuration[section][option] = config_changes_dict["replace"][section][option]
    for section in config_changes_dict["remove"]:
        if "section" in config_changes_dict["remove"][section]:
            if section in configuration:
                configuration.pop(section)
        else:
            for option in config_changes_dict["remove"][section]:
                if (
                    section == "executor"
                    and "ex1" in configuration[Sections.AGENT][Sections.EXECUTORS]
                    and option in configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"]
                ):
                    configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"].pop(option)
                elif section in configuration and option in configuration[section]:
                    configuration[section].pop(option)
    save_config(config_path)
    if "expected_exception" in config_changes_dict:
        with pytest.raises(config_changes_dict["expected_exception"]):
            Dispatcher(None, config_path)
    else:
        Dispatcher(None, config_path)
def tmp_custom_config():
    config = TmpConfig()
    ini_path = pathlib.Path(
        __file__).parent.parent / "data" / "test_config.ini"
    shutil.copyfile(ini_path, config.config_file_path)
    reset_config(config.config_file_path)
    yield config
    os.remove(config.config_file_path)
def tmp_custom_config(config=None):
    config = TmpConfig()
    ini_path = (pathlib.Path(__file__).parent.parent / 'data' /
                'test_config.ini')
    shutil.copyfile(ini_path, config.config_file_path)
    reset_config(config.config_file_path)
    yield config
    os.remove(config.config_file_path)
Exemplo n.º 6
0
def process_config_file(config_filepath: Path, logger):
    if config_filepath is None and not os.path.exists(config.CONFIG_FILENAME):
        logger.info("Config file doesn't exist. Run the command "
                    "`faraday-dispatcher config-wizard` to create one")
        exit(1)
    config_filepath = config_filepath or Path(config.CONFIG_FILENAME)
    config_filepath = Path(config_filepath)
    config.reset_config(config_filepath)
    return config_filepath
Exemplo n.º 7
0
def test_new_config(testing_inputs: Dict[(str, object)], ini_config):
    runner = CliRunner()

    content = None
    content_path = ini_config["dir"]

    if content_path != "":
        with open(content_path, "r") as content_file:
            content = content_file.read()

    with runner.isolated_filesystem() as file_system:

        if content:
            path = Path(file_system) / "dispatcher.ini"
            with path.open(mode="w") as content_file:
                content_file.write(content)
        else:
            path = Path(file_system)
        """
        The in_data variable will be consumed for the cli command, but in order
        to avoid unexpected inputs with no data (and a infinite wait),
        a \0\n block of input is added at the end of the input. Furthermore the
         \0 is added as a possible choice of the ones and should exit with
        error.
        """
        in_data = "Q\nN\n" if ini_config["id_str"] == "no_ini" else ""
        in_data += parse_inputs(testing_inputs) + "\0\n" * 1000
        env = os.environ
        env["DEBUG_INPUT_MODE"] = "True"

        result = runner.invoke(config_wizard, args=["-c", path], input=in_data, env=env)
        assert result.exit_code == testing_inputs["exit_code"], result.exception
        if "exception" in testing_inputs:
            assert str(result.exception) == str(testing_inputs["exception"])
            assert testing_inputs["exception"].__class__ == result.exception.__class__
        else:
            # Control '\0' is not passed in the output, as the input is echoed
            assert "\0\n" not in result.output
        if "expected_outputs" in testing_inputs:
            for expected_output in testing_inputs["expected_outputs"]:
                assert expected_output in result.output

        expected_executors_set = set.union(ini_config["old_executors"], testing_inputs["after_executors"])
        expected_workspaces_set = set.union(ini_config["old_workspaces"], testing_inputs["after_workspaces"])

        if path.suffix == ".ini":
            path = path.with_suffix(".yaml")
        config_mod.reset_config(path)
        executor_config_set = set(config_mod.instance[Sections.AGENT].get("executors"))
        assert executor_config_set == expected_executors_set
        workspace_config_set = set(config_mod.instance[Sections.SERVER].get("workspaces"))

        assert workspace_config_set == expected_workspaces_set
        assert f"Section: {Sections.TOKENS}" not in result.output
    def __init__(self, session, config_path=None):
        reset_config(filepath=config_path)
        try:
            verify()
            control_config()
        except ValueError as e:
            logger.error(e)
            raise e
        self.config_path = config_path
        self.host = config.get(Sections.SERVER, "host")
        self.api_port = config.get(Sections.SERVER, "api_port")
        self.websocket_port = config.get(Sections.SERVER, "websocket_port")
        self.agent_token = config[Sections.TOKENS].get(
            "agent", None) if Sections.TOKENS in config else None
        self.agent_name = config.get(Sections.AGENT, "agent_name")
        self.session = session
        self.websocket = None
        self.websocket_token = None
        self.workspaces = _parse_list(config.get(Sections.SERVER,
                                                 "workspaces"))

        self.executors = {
            executor_name: Executor(executor_name, config)
            for executor_name in _parse_list(config[Sections.AGENT].get(
                "executors", ""))
        }
        self.ws_ssl_enabled = self.api_ssl_enabled = config[
            Sections.SERVER].get("ssl", "False").lower() in [
                "t",
                "true",
            ]
        ssl_cert_path = config[Sections.SERVER].get("ssl_cert", None)
        if not Path(ssl_cert_path).exists():
            raise ValueError(
                f"SSL cert does not exist in path {ssl_cert_path}")
        self.api_kwargs: Dict[str, object] = ({
            "ssl":
            ssl.create_default_context(cafile=ssl_cert_path)
            if "HTTPS_PROXY" not in os.environ else False
        } if self.api_ssl_enabled and ssl_cert_path else {})
        if "HTTPS_PROXY" in os.environ:
            logger.info("HTTPS_PROXY is set; will not do SSL verify")
            ws_ssl_context = ssl.create_default_context()
            ws_ssl_context.check_hostname = False
            ws_ssl_context.verify_mode = ssl.CERT_NONE
        else:
            ws_ssl_context = ssl.create_default_context(cafile=ssl_cert_path)
        self.ws_kwargs = {"ssl": ws_ssl_context} if self.ws_ssl_enabled else {}
        self.execution_id = None
        self.executor_tasks: Dict[str, List[Task]] = {
            Dispatcher.TaskLabels.EXECUTOR: [],
            Dispatcher.TaskLabels.CONNECTION_CHECK: [],
        }
        self.sigterm_received = False
 def __init__(self, session, config_path=None):
     reset_config(filepath=config_path)
     try:
         control_config()
     except ValueError as e:
         logger.error(e)
         raise e
     self.config_path = config_path
     self.host = config.instance[Sections.SERVER]["host"]
     self.api_port = config.instance[Sections.SERVER]["api_port"]
     self.websocket_port = config.instance[Sections.SERVER]["websocket_port"]
     self.agent_token = (
         config.instance[Sections.TOKENS].get("agent") if Sections.TOKENS in config.instance else None
     )
     self.agent_name = config.instance[Sections.AGENT]["agent_name"]
     self.session = session
     self.websocket = None
     self.websocket_token = None
     self.workspaces = config.instance[Sections.SERVER]["workspaces"]
     self.executors = {
         executor_name: Executor(executor_name, executor_data)
         for executor_name, executor_data in config.instance[Sections.AGENT].get("executors", {}).items()
     }
     self.ws_ssl_enabled = self.api_ssl_enabled = config.instance[Sections.SERVER].get("ssl", False)
     ssl_cert_path = config.instance[Sections.SERVER].get("ssl_cert", None)
     ssl_ignore = config.instance[Sections.SERVER].get("ssl_ignore", False)
     if not Path(ssl_cert_path).exists():
         raise ValueError(f"SSL cert does not exist in path {ssl_cert_path}")
     if self.api_ssl_enabled:
         if ssl_cert_path:
             ssl_cert_context = ssl.create_default_context(cafile=ssl_cert_path)
             self.api_kwargs = {"ssl": ssl_cert_context}
             self.ws_kwargs = {"ssl": ssl_cert_context}
         else:
             if ssl_ignore or "HTTPS_PROXY" in os.environ:
                 ignore_ssl_context = ssl.create_default_context()
                 ignore_ssl_context.check_hostname = False
                 ignore_ssl_context.verify_mode = ssl.CERT_NONE
                 self.api_kwargs = {"ssl": ignore_ssl_context}
                 self.ws_kwargs = {"ssl": ignore_ssl_context}
             else:
                 self.api_kwargs: Dict[str, object] = {}
                 self.ws_kwargs: Dict[str, object] = {}
     else:
         self.api_kwargs: Dict[str, object] = {}
         self.ws_kwargs: Dict[str, object] = {}
     self.execution_id = None
     self.executor_tasks: Dict[str, List[Task]] = {
         Dispatcher.TaskLabels.EXECUTOR: [],
         Dispatcher.TaskLabels.CONNECTION_CHECK: [],
     }
     self.sigterm_received = False
def test_new_config(testing_inputs: Dict[(str, object)], ini_config):
    runner = CliRunner()

    content = None
    content_path = ini_config["dir"]

    if content_path != "":
        with open(content_path, 'r') as content_file:
            content = content_file.read()

    with runner.isolated_filesystem() as file_system:

        if content:
            path = Path(file_system) / "dispatcher.ini"
            with path.open(mode="w") as content_file:
                content_file.write(content)
        else:
            path = Path(file_system)
        ''' 
        The in_data variable will be consumed for the cli command, but in order to avoid unexpected inputs with no
        data (and a infinite wait), a \0\n block of input is added at the end of the input. Furthermore the \0 is added
        as a possible choice of the ones and should exit with error.
        '''
        in_data = parse_inputs(testing_inputs) + "\0\n" * 1000
        env = os.environ
        env["DEBUG_INPUT_MODE"] = "True"
        result = runner.invoke(config_wizard,
                               args=["-c", path],
                               input=in_data,
                               env=env)
        assert result.exit_code == testing_inputs[
            "exit_code"], result.exception
        if "exception" in testing_inputs:
            assert str(result.exception) == str(testing_inputs["exception"])
            assert result.exception.__class__ == testing_inputs[
                "exception"].__class__
        else:
            assert '\0\n' not in result.output  # Control '\0' is not passed in the output, as the input is echoed
        if "expected_outputs" in testing_inputs:
            for expected_output in testing_inputs["expected_outputs"]:
                assert expected_output in result.output

        expected_executors_set = set.union(ini_config["old_executors"],
                                           testing_inputs["after_executors"])

        config_mod.reset_config(path)
        executor_config_set = set(
            config_mod.instance.get(config_mod.Sections.AGENT,
                                    "executors").split(","))
        if '' in executor_config_set:
            executor_config_set.remove('')
        assert executor_config_set == expected_executors_set
Exemplo n.º 11
0
    def __init__(self, config_filepath: Path):
        self.config_filepath = config_filepath

        try:
            config.reset_config(config_filepath)
        except ValueError as e:
            if e.args[1] or config_filepath.is_file():
                # the filepath is either a file, or a folder containing a file,
                # which can't be processed
                raise e
        config.control_config()
        self.executors_dict = {}
        self.load_executors()
Exemplo n.º 12
0
    def __init__(self, config_filepath: Path):
        self.config_filepath = config_filepath

        try:
            config.reset_config(config_filepath)
        except ValueError as e:
            if e.args[1] or config_filepath.is_file():
                raise e  # the filepath is either a file, or a folder containing a file, which can't be processed
        try:
            config.verify()
        except ValueError as e:
            print(f"{Bcolors.FAIL}{e}{Bcolors.ENDC}")
            sys.exit(1)
        self.executors_list = []
        self.load_executors()
Exemplo n.º 13
0
 def __init__(self, session, config_path=None):
     reset_config(filepath=config_path)
     self.control_config()
     self.config_path = config_path
     self.host = config.get(Sections.SERVER, "host")
     self.api_port = config.get(Sections.SERVER, "api_port")
     self.websocket_port = config.get(Sections.SERVER, "websocket_port")
     self.workspace = config.get(Sections.SERVER, "workspace")
     self.agent_token = config[Sections.TOKENS].get("agent", None)
     self.agent_name = config.get(Sections.AGENT, "agent_name")
     self.session = session
     self.websocket = None
     self.websocket_token = None
     self.executors = {
         executor_name: Executor(executor_name, config)
         for executor_name in config[Sections.AGENT].get("executors",
                                                         []).split(",")
     }
def test_with_agent_token(delete_token):
    runner = CliRunner()

    content_path = old_version_path() / "1.2_with_agent_token.ini"

    with open(content_path, "r") as content_file:
        content = content_file.read()

    with runner.isolated_filesystem() as file_system:

        path = Path(file_system) / "dispatcher.ini"
        with path.open(mode="w") as content_file:
            content_file.write(content)
        env = os.environ
        env["DEBUG_INPUT_MODE"] = "True"
        input_str = DispatcherInput(
            ssl="false",
            delete_agent_token=delete_token,
            workspaces=[
                WorkspaceInput(name="aworkspace", adm_type=ADMType.ADD)
            ],
        ).input_str()
        input_str = f"A\n{input_str}Q\n"
        escape_string = "\0\n" * 1000
        result = runner.invoke(
            config_wizard,
            args=["-c", path],
            input=f"{input_str}{escape_string}",
            env=env,
        )
        assert result.exit_code == 0, result.exception
        assert f"Section: {config_mod.Sections.TOKENS}" in result.output

        config_mod.reset_config(path)
        if delete_token:
            assert "agent" not in config_mod.instance.options(
                config_mod.Sections.TOKENS)
        else:
            assert "agent" in config_mod.instance.options(
                config_mod.Sections.TOKENS)
Exemplo n.º 15
0
async def main(config_file):

    if config_file is None and not os.path.exists(config.CONFIG_FILENAME):
        logger.info("Config file doesn't exist. Creating a new one")
        os.makedirs(config.CONFIG_PATH, exist_ok=True)
        shutil.copyfile(config.EXAMPLE_CONFIG_FILENAME, config.CONFIG_FILENAME)
        logger.info(f"Config file at {config.CONFIG_FILENAME} created")
    config_file = config_file or config.CONFIG_FILENAME
    config.reset_config(config_file)

    async with ClientSession(raise_for_status=True) as session:
        try:
            dispatcher = Dispatcher(session, config_file)
        except ValueError as ex:
            print(f'{Bcolors.FAIL}Error configuring dispatcher: '
                  f'{Bcolors.BOLD}{str(ex)}{Bcolors.ENDC}')
            print(f'Try checking your config file located at {Bcolors.BOLD}'
                  f'{config.CONFIG_FILENAME}{Bcolors.ENDC}')
            return 1
        await dispatcher.register()
        await dispatcher.connect()

    return 0
from faraday_agent_dispatcher.config import instance as config, reset_config, Sections,\
    save_config, EXAMPLE_CONFIG_FILENAME

from faraday_agent_dispatcher.utils.url_utils import api_url

from tests.data.basic_executor import host_data, vuln_data
from tests.utils.text_utils import fuzzy_string

import os
from pathlib import Path
from requests import Session
import subprocess
import time

reset_config(EXAMPLE_CONFIG_FILENAME)
HOST = config.get(Sections.SERVER, "host")
API_PORT = config.get(Sections.SERVER, "api_port")
WS_PORT = config.get(Sections.SERVER, "websocket_port")
WORKSPACE = fuzzy_string(
    6).lower()  # TODO FIX WHEN FARADAY ACCEPTS CAPITAL FIRST LETTER
AGENT_NAME = fuzzy_string(6)
EXECUTOR_NAME = fuzzy_string(6)

USER = os.getenv("FARADAY_USER")
EMAIL = os.getenv("FARADAY_EMAIL")
PASS = os.getenv("FARADAY_PASSWORD")

CONFIG_DIR = "./config_file.ini"
LOGGER_DIR = "./logs"

agent_ok_status_keys_set = {
def tmp_default_config():
    config = TmpConfig()
    shutil.copyfile(EXAMPLE_CONFIG_FILENAME, config.config_file_path)
    reset_config(config.config_file_path)
    yield config
    os.remove(config.config_file_path)
Exemplo n.º 18
0
def test_override_ssl_cert_with_default(ini_config):
    runner = CliRunner()
    content = None
    content_path = ini_config["dir"]

    if content_path != "":
        with open(content_path, "r") as content_file:
            content = content_file.read()

    with runner.isolated_filesystem() as file_system:

        if content:
            path = Path(file_system) / "dispatcher.ini"
            with path.open(mode="w") as content_file:
                content_file.write(content)
        else:
            path = Path(file_system)
        """
        The in_data variable will be consumed for the cli command, but in order
        to avoid unexpected inputs with no data (and a infinite wait),
        a \0\n block of input is added at the end of the input. Furthermore the
        \0 is added as a possible choice of the ones and should exit with
        error.
        """

        testing_inputs = [
            {
                "dispatcher_input": DispatcherInput(
                    host="https://127.0.0.1",
                    workspaces=[WorkspaceInput(name="aworkspace", adm_type=ADMType.ADD)],
                    ssl_cert=Path(__file__).parent.parent / "data" / "mock.pub",
                ),
            },
            {
                "dispatcher_input": DispatcherInput(
                    host="https://127.0.0.1",
                    ssl_cert="",
                    workspaces=[WorkspaceInput(name="aworkspace", adm_type=ADMType.ADD)],
                ),
            },
        ]

        in_data0 = parse_inputs(testing_inputs[0]) + "\0\n" * 1000
        env = os.environ
        env["DEBUG_INPUT_MODE"] = "True"
        result = runner.invoke(config_wizard, args=["-c", path], input=in_data0, env=env)
        assert result.exit_code == 0, result.exception
        # Control '\0' is not passed in the output, as the input is echoed
        assert "\0\n" not in result.output

        path = path.with_suffix(".yaml")

        in_data1 = parse_inputs(testing_inputs[1]) + "\0\n" * 1000
        env = os.environ
        env["DEBUG_INPUT_MODE"] = "True"
        result = runner.invoke(config_wizard, args=["-c", path], input=in_data1, env=env)
        assert result.exit_code == 0, result.exception
        # Control '\0' is not passed in the output, as the input is echoed
        assert "\0\n" not in result.output

        config_mod.reset_config(path)
        assert "" == config_mod.instance[Sections.SERVER]["ssl_cert"]
        assert f"Section: {Sections.TOKENS}" not in result.output