Example #1
0
    def apply(self, user_input):
        # Check if the user explicitly asked to bypass this check
        if "!bypass" in user_input:
            user_input = user_input.replace("!bypass", "")  # Remove this option from the command line
            return ProcessorAction.FORWARD, user_input

        # Verify if the command is being proxyfied.
        commands = get_commands(user_input)
        for c in self.PROXY_COMMANDS:
            if c in commands:  # The user remembered to issue a proxy command. All is well.
                return ProcessorAction.FORWARD, user_input

        # The command is not proxified. Should it be?
        for c in self.NETWORK_COMMANDS:
            if c in commands:  # The command should probably be proxyfied.
                children = get_children()
                for child in children:
                    # There is already a network command running in FFM. This means (for instance) that the user
                    # SSH'd into another machine, in which case there is no risk of leaking the local IP address.
                    if os.path.basename(child) in self.NETWORK_COMMANDS:
                        return ProcessorAction.FORWARD, user_input

                write_str("FFM blocked a command which might need to be proxied. Add \"!bypass\" to the "
                          "command line to override or use:\r\n * " + "\r\n * ".join(self.PROXY_COMMANDS) +
                          "\r\n", LogLevel.ERROR)
                return ProcessorAction.CANCEL, None

        # No dangerous command was issued, proceed.
        return ProcessorAction.FORWARD, user_input
Example #2
0
    def apply(self, user_input):
        # Add the proxy commands to the tokens: torify ssh is considered to be an SSH call.
        separators = CMDLINE_SEPARATORS + tuple(
            context.config["AssertTorify"]["proxy_commands"].split())
        if "ssh" not in get_commands(user_input, separators=separators):
            return ProcessorAction.FORWARD, user_input

        ssh_cmdline = get_arguments(user_input, "ssh")

        # Block the command if the username is leaking
        if context.config["SSHOptions"]["require_explicit_username"]:
            if "@" not in ssh_cmdline:
                write_str(
                    "FFM blocked a command that may leak your local username. "
                    "Please specify the remote user explicitly.\r\n",
                    LogLevel.ERROR)
                return ProcessorAction.CANCEL, None

        # Add the -T option if it is missing
        if context.config["SSHOptions"]["force_disable_pty_allocation"]:
            if not re.search(r'\-[a-zA-Z]*T',
                             ssh_cmdline):  # Check if the -T option is present
                write_str(
                    "Notice: automatically adding the -T option to the ssh command!\r\n",
                    LogLevel.WARNING)
                return ProcessorAction.FORWARD, (user_input.replace(
                    ssh_cmdline, "%s %s" % (ssh_cmdline, "-T"), 1))
            return ProcessorAction.FORWARD, user_input

        # Nothing done
        return ProcessorAction.FORWARD, user_input
    def apply(self, user_input):
        # Add the proxy commands to the tokens: torify rdesktop is considered to be a rdesktop call.
        separators = CMDLINE_SEPARATORS + tuple(
            context.config["AssertTorify"]["proxy_commands"].split())
        if "rdesktop" not in get_commands(user_input, separators=separators):
            return ProcessorAction.FORWARD, user_input

        rdesktop_cmdline = get_arguments(user_input, "rdesktop")

        # Use argparse to look for the interesting arguments in the rdesktop command:
        parser = SilentArgumentParser()
        parser.add_argument("-u")
        try:
            args, _ = parser.parse_known_args(rdesktop_cmdline.split())
        except RuntimeError:
            # The rdesktop command line seems invalid. Let SSH display its error message / usage.
            return ProcessorAction.FORWARD, user_input

        # Block the command if the username is leaking
        if context.config["RdesktopOptions"]["require_explicit_username"]:
            if not args.u:
                write_str(
                    "FFM blocked a command that may leak your local username. "
                    "Please specify the remote user explicitly with the -u option.\r\n",
                    LogLevel.ERROR)
                return ProcessorAction.CANCEL, None
        return ProcessorAction.FORWARD, user_input
Example #4
0
 def execute(self):
     write_str("List of commands available:\r\n")
     strings = []
     for c in COMMAND_LIST:
         strings.append("\t%s: %s\r\n" % (c.name(), c.description()))
     # Sort the plugins by alphabetical order.
     for s in sorted(strings):
         write_str(s)
Example #5
0
def register_plugin(plugin):
    if not issubclass(plugin, Command):
        write_str(
            "Tried to register %s which is not a valid command!\r\n" %
            str(plugin), LogLevel.ERROR)
        return
    elif plugin in COMMAND_LIST:
        write_str("Tried to register %s twice!\r\n" % str(plugin),
                  LogLevel.ERROR)
        return
    else:
        COMMAND_LIST.add(plugin)
Example #6
0
    def apply(self, user_input):
        # Add the proxy commands to the tokens: torify ssh is considered to be an SSH call.
        separators = CMDLINE_SEPARATORS + tuple(context.config["AssertTorify"]["proxy_commands"].split())
        if "ssh" not in get_commands(user_input, separators=separators):
            return ProcessorAction.FORWARD, user_input

        ssh_cmdline = get_arguments(user_input, "ssh")
        options_added = []

        # Use argparse to look for the interesting arguments in the SSH command:
        parser = SilentArgumentParser()
        parser.add_argument("-l", nargs='?', default=None)
        parser.add_argument("-T", action="store_true")
        parser.add_argument("-o", nargs='+')
        parser.add_argument("-i", nargs='+')
        parser.add_argument("-v", action="store_true")
        parser.add_argument("-N", action="store_true")
        parser.add_argument("-D")
        parser.add_argument("-L")
        parser.add_argument("-R")
        parser.add_argument("positional", nargs='+')
        try:
            args, _ = parser.parse_known_args(ssh_cmdline.split())
        except RuntimeError:
            # The SSH command line seems invalid. Let SSH display its error message / usage.
            return ProcessorAction.FORWARD, user_input

        # Block the command if the username is leaking
        if context.config["SSHOptions"]["require_explicit_username"]:
            if not any("@" in arg for arg in args.positional) and not args.l:
                write_str("FFM blocked a command that may leak your local username. "
                          "Please specify the remote user explicitly.\r\n", LogLevel.ERROR)
                return ProcessorAction.CANCEL, None

        # Add -oPubkeyAuthentication=no to prevent SSH keys from leaking.
        if context.config["SSHOptions"]["prevent_ssh_key_leaks"]:
            if not args.i and (
                    not args.o or
                    not any("PubkeyAuthentication" in option for option in args.o)
            ):
                options_added.append("-oPubkeyAuthentication=no")

        # Add the -T option if it is missing
        if context.config["SSHOptions"]["force_disable_pty_allocation"]:
            if not args.T:
                options_added.append("-T")

        if options_added:
            user_input = user_input.replace(ssh_cmdline, "%s %s" % (ssh_cmdline, " ".join(options_added)), 1)
            write_str("Notice: the following options were added to the SSH command: %s.\r\n" % ", ".join(options_added),
                      LogLevel.WARNING)
        return ProcessorAction.FORWARD, user_input
Example #7
0
    def apply(self, user_input):
        # Add the proxy commands to the tokens: torify ssh is considered to be an SSH call.
        separators = CMDLINE_SEPARATORS + tuple(AssertTorify.PROXY_COMMANDS)
        if "ssh" not in get_commands(user_input, separators=separators):
            return ProcessorAction.FORWARD, user_input

        ssh_cmdline = get_arguments(user_input, "ssh")
        if not re.search(r'\-[a-zA-Z]*T',
                         ssh_cmdline):  # Check if the -T option is present
            write_str(
                "Notice: automatically adding the -T option to the ssh command!\r\n",
                LogLevel.WARNING)
            return ProcessorAction.FORWARD, (user_input.replace(
                ssh_cmdline, "%s %s" % (ssh_cmdline, "-T"), 1))
        return ProcessorAction.FORWARD, user_input
Example #8
0
    def test_standard_case(self):
        f = "unittest_ffm.log"
        cmdline = "   !log    %s" % f
        self.assertTrue(parse_commands(cmdline))
        self.assertIsNotNone(self.context.log)
        self.assertEqual(f, self.context.log.name)

        message = "Unit test!"
        write_str(message)

        cmdline = "!log off"
        self.assertTrue(parse_commands(cmdline))
        self.assertIsNone(self.context.log)

        self.assertTrue(os.path.exists(f))
        with open(f, "r") as fd:
            self.assertEqual(message, fd.read())
        os.remove(f)
Example #9
0
def parse_commands(command_line):
    for c in COMMAND_LIST:
        if re.match(c.regexp(), command_line):
            # TODO: parse better?
            args = command_line.split()
            try:
                command_instance = c(*args)
            except RuntimeError as e:  # The constructor throws: show the command usage.
                c.usage()
                if str(e):
                    write_str("%s\r\n" % str(e), LogLevel.WARNING)
            else:
                try:
                    command_instance.execute()
                except Exception as e:
                    write_str("Command failed with error: %s\r\n" % str(e),
                              LogLevel.WARNING)
            return True
    # No commands match, don't do anything.
    return False
Example #10
0
def register_processor(plugin):
    if not issubclass(plugin, Processor):
        write_str(
            "Tried to register %s which is not a valid command!\r\n" %
            str(plugin), LogLevel.ERROR)
        return
    if plugin.type() == ProcessorType.INPUT:
        destination = INPUT_PROCESSOR_LIST
    elif plugin.type() == ProcessorType.OUTPUT:
        destination = OUTPUT_PROCESSOR_LIST
    else:
        write_str("The processor's type (%s) is unsupported." % plugin.type())
        return

    # The plugin name needs to be checked on the class name, as the full path may vary
    # depending on where the plugin is imported.
    plugin_name = str(plugin).split(".")[-1]
    for p in destination:
        if str(p).split(".")[-1] == plugin_name:
            write_str("Tried to register %s twice!\r\n" % str(plugin),
                      LogLevel.ERROR)
            return
    else:
        destination.add(plugin)
Example #11
0
 def usage():
     write_str("Usage: !list\r\n")