Exemple #1
0
    def start(self):
        # Logo.
        logo()

        # Setup shell auto-complete.
        def complete(text, state):
            # Try to autocomplete commands.
            cmds = [i for i in self.cmd.commands if i.startswith(text)]
            if state < len(cmds):
                return cmds[state]

            # Try to autocomplete modules.
            mods = [i for i in __modules__ if i.startswith(text)]
            if state < len(mods):
                return mods[state]

            # Then autocomplete paths.
            if text.startswith("~"):
                text = "{0}{1}".format(expanduser("~"), text[1:])
            return (glob.glob(text+'*')+[None])[state]

        # Auto-complete on tabs.
        readline.set_completer_delims(' \t\n;')
        readline.parse_and_bind('tab: complete')
        readline.set_completer(complete)

        # Save commands in history file.
        def save_history(path):
            readline.write_history_file(path)

        # If there is an history file, read from it and load the history
        # so that they can be loaded in the shell.
        # Now we are storing the history file in the local project folder
        history_path = os.path.join(__project__.path, 'history')

        if os.path.exists(history_path):
            readline.read_history_file(history_path)

        # Register the save history at program's exit.
        atexit.register(save_history, path=history_path)

        # Main loop.
        while self.active:
            # If there is an open session, we include the path to the opened
            # file in the shell prompt.
            # TODO: perhaps this block should be moved into the session so that
            # the generation of the prompt is done only when the session's
            # status changes.
            prefix = ''
            if __project__.name:
                prefix = bold(cyan(__project__.name)) + ' '

            if __sessions__.is_set():
                stored = ''
                filename = ''
                if __sessions__.current.file:
                    filename = __sessions__.current.file.name
                    if not Database().find(key='sha256', value=__sessions__.current.file.sha256):
                        stored = magenta(' [not stored]', True)

                misp = ''
                if __sessions__.current.misp_event:
                    misp = '[MISP'
                    if __sessions__.current.misp_event.event.id:
                        misp += ' {}'.format(__sessions__.current.misp_event.event.id)
                    else:
                        misp += ' New Event'
                    if __sessions__.current.misp_event.off:
                        misp += ' (Offline)'
                    misp += ']'

                prompt = (prefix + cyan('viper ', True) +
                          white(filename, True) + blue(misp, True) + stored + cyan(' > ', True))
            # Otherwise display the basic prompt.
            else:
                prompt = prefix + cyan('viper > ', True)

            # Wait for input from the user.
            try:
                data = input(prompt).strip()
            except KeyboardInterrupt:
                print("")
            # Terminate on EOF.
            except EOFError:
                self.stop()
                print("")
                continue
            # Parse the input if the user provided any.
            else:
                # If there are recognized keywords, we replace them with
                # their respective value.
                data = self.keywords(data)
                # Skip if the input is empty.
                if not data:
                    continue

                # Check for output redirection
                # If there is a > in the string, we assume the user wants to output to file.
                if '>' in data:
                    data, console_output['filename'] = data.split('>')
                    print("Writing output to {0}".format(console_output['filename'].strip()))


                # If the input starts with an exclamation mark, we treat the
                # input as a bash command and execute it.
                # At this point the keywords should be replaced.
                if data.startswith('!'):
                    os.system(data[1:])
                    continue

                # Try to split commands by ; so that you can sequence multiple
                # commands at once.
                # For example:
                # viper > find name *.pdf; open --last 1; pdf id
                # This will automatically search for all PDF files, open the first entry
                # and run the pdf module against it.
                split_commands = data.split(';')
                for split_command in split_commands:
                    split_command = split_command.strip()
                    if not split_command:
                        continue

                    # If it's an internal command, we parse the input and split it
                    # between root command and arguments.
                    root, args = self.parse(split_command)

                    # Check if the command instructs to terminate.
                    if root in ('exit', 'quit'):
                        self.stop()
                        continue

                    try:
                        # If the root command is part of the embedded commands list we
                        # execute it.
                        if root in self.cmd.commands:
                            self.cmd.commands[root]['obj'](*args)
                            del(self.cmd.output[:])
                        # If the root command is part of loaded modules, we initialize
                        # the module and execute it.
                        elif root in __modules__:
                            module = __modules__[root]['obj']()
                            module.set_commandline(args)
                            module.run()

                            if cfg.modules.store_output and __sessions__.is_set():
                                try:
                                    Database().add_analysis(__sessions__.current.file.sha256, split_command, module.output)
                                except:
                                    pass
                            del(module.output[:])
                        else:
                            print("Command not recognized.")
                    except KeyboardInterrupt:
                        pass
                    except Exception:
                        print_error("The command {0} raised an exception:".format(bold(root)))
                        traceback.print_exc()

                console_output['filename'] = None   # reset output to stdout
Exemple #2
0
    def start(self):
        # log start
        log.info('Starting viper-cli')

        # Logo.
        logo()

        # Setup shell auto-complete.
        def complete(text, state):
            # filesystem path completion only makes sense for a few commands/modules
            fs_path_completion = False

            # clean up user input so far (no leading/trailing/duplicate spaces)
            line = " ".join(readline.get_line_buffer().split())
            words = line.split(" ")  # split words; e.g. store -f /tmp -> ['store', '-f', '/tmp']

            if words[0] in [i for i in self.cmd.commands]:
                # handle completion for commands

                # enable filesystem path completion for certain commands (e.g. export, store)
                if words[0] in [x for x in self.cmd.commands if self.cmd.commands[x]["fs_path_completion"]]:
                    fs_path_completion = True

                options = [key for key in self.cmd.commands[words[0]]["parser_args"]]

                # enable tab completion for projects --switch
                if words[0] == "projects":
                    if "--switch" in words or "-s" in words:
                        options += get_project_list()

                        # enable tab completion for copy (list projects)
                if words[0] == "copy":
                    options += get_project_list()

                completions = [i for i in options if i.startswith(text) and i not in words]

            elif words[0] in [i for i in __modules__]:
                # handle completion for modules
                if len(words) == 1:
                    # only the module name is give so far - present all args and the subparsers (if any)
                    options = [key for key in __modules__[words[0]]["parser_args"]]
                    options += [key for key in __modules__[words[0]]["subparser_args"]]

                elif len(words) == 2:
                    # 1 complete word and one either complete or incomplete that specifies the subparser or an arg
                    if words[1] in list(__modules__[words[0]]["parser_args"]):
                        # full arg for a module is given
                        options = [key for key in __modules__[words[0]]["parser_args"]]

                    elif words[1] in list(__modules__[words[0]]["subparser_args"]):
                        # subparser is specified - get all subparser args
                        options = [key for key in __modules__[words[0]]["subparser_args"][words[1]]]

                    else:
                        options = [key for key in __modules__[words[0]]["parser_args"]]
                        options += [key for key in __modules__[words[0]]["subparser_args"]]

                else:  # more that 2 words
                    if words[1] in list(__modules__[words[0]]["subparser_args"]):
                        # subparser is specified - get all subparser args
                        options = [key for key in __modules__[words[0]]["subparser_args"][words[1]]]
                    else:
                        options = [key for key in __modules__[words[0]]["parser_args"]]

                completions = [i for i in options if i.startswith(text) and i not in words]

            else:
                # initial completion for both commands and modules
                completions = [i for i in self.cmd.commands if i.startswith(text)]
                completions += [i for i in __modules__ if i.startswith(text)]

            if state < len(completions):
                return completions[state]

            if fs_path_completion:
                # completion for paths only if it makes sense
                if text.startswith("~"):
                    text = "{0}{1}".format(expanduser("~"), text[1:])
                return (glob.glob(text + '*') + [None])[state]

            return

        # Auto-complete on tabs.
        readline.set_completer_delims(' \t\n;')
        readline.parse_and_bind('tab: complete')
        readline.set_completer(complete)

        # Save commands in history file.
        def save_history(path):
            readline.write_history_file(path)

        # If there is an history file, read from it and load the history
        # so that they can be loaded in the shell.
        # Now we are storing the history file in the local project folder
        history_path = os.path.join(__project__.path, 'history')

        if os.path.exists(history_path):
            readline.read_history_file(history_path)

        readline.set_history_length(10000)

        # Register the save history at program's exit.
        atexit.register(save_history, path=history_path)

        # Main loop.
        while self.active:
            # If there is an open session, we include the path to the opened
            # file in the shell prompt.
            # TODO: perhaps this block should be moved into the session so that
            # the generation of the prompt is done only when the session's
            # status changes.
            prefix = ''
            if __project__.name:
                prefix = bold(cyan(__project__.name)) + ' '

            if __sessions__.is_set():
                stored = ''
                filename = ''
                if __sessions__.current.file:
                    filename = __sessions__.current.file.name
                    if not Database().find(key='sha256', value=__sessions__.current.file.sha256):
                        stored = magenta(' [not stored]', True)

                misp = ''
                if __sessions__.current.misp_event:
                    misp = ' [MISP'
                    if __sessions__.current.misp_event.event.id:
                        misp += ' {}'.format(__sessions__.current.misp_event.event.id)
                    else:
                        misp += ' New Event'
                    if __sessions__.current.misp_event.off:
                        misp += ' (Offline)'
                    misp += ']'

                prompt = (prefix + cyan('viper ', True) +
                          white(filename, True) + blue(misp, True) + stored + cyan(' > ', True))
            # Otherwise display the basic prompt.
            else:
                prompt = prefix + cyan('viper > ', True)

            # force str (Py3) / unicode (Py2) for prompt
            if sys.version_info <= (3, 0):
                prompt = prompt.encode('utf-8')
            else:
                prompt = str(prompt)

            # Wait for input from the user.
            try:
                data = input(prompt).strip()
            except KeyboardInterrupt:
                print("")
            # Terminate on EOF.
            except EOFError:
                self.stop()
                print("")
                continue
            # Parse the input if the user provided any.
            else:
                # If there are recognized keywords, we replace them with
                # their respective value.
                data = self.keywords(data)
                # Skip if the input is empty.
                if not data:
                    continue

                # Check for output redirection
                # If there is a > in the string, we assume the user wants to output to file.
                if '>' in data:
                    data, console_output['filename'] = data.split('>', 1)
                    if ';' in console_output['filename']:
                        console_output['filename'], more_commands = console_output['filename'].split(';', 1)
                        data = '{};{}'.format(data, more_commands)
                    print("Writing output to {0}".format(console_output['filename'].strip()))

                # If the input starts with an exclamation mark, we treat the
                # input as a bash command and execute it.
                # At this point the keywords should be replaced.
                if data.startswith('!'):
                    os.system(data[1:])
                    continue

                # Try to split commands by ; so that you can sequence multiple
                # commands at once.
                # For example:
                # viper > find name *.pdf; open --last 1; pdf id
                # This will automatically search for all PDF files, open the first entry
                # and run the pdf module against it.
                split_commands = data.split(';')
                for split_command in split_commands:
                    split_command = split_command.strip()
                    if not split_command:
                        continue

                    # If it's an internal command, we parse the input and split it
                    # between root command and arguments.
                    root, args = self.parse(split_command)

                    # Check if the command instructs to terminate.
                    if root in ('exit', 'quit'):
                        self.stop()
                        continue

                    try:
                        # If the root command is part of the embedded commands list we
                        # execute it.
                        if root in self.cmd.commands:
                            self.cmd.commands[root]['obj'](*args)
                            del(self.cmd.output[:])
                        # If the root command is part of loaded modules, we initialize
                        # the module and execute it.
                        elif root in __modules__:
                            module = __modules__[root]['obj']()
                            module.set_commandline(args)
                            module.run()

                            if cfg.modules.store_output and __sessions__.is_set():
                                try:
                                    Database().add_analysis(__sessions__.current.file.sha256, split_command, module.output)
                                except Exception:
                                    pass
                            del(module.output[:])
                        else:
                            print("Command not recognized.")
                    except KeyboardInterrupt:
                        pass
                    except Exception:
                        print_error("The command {0} raised an exception:".format(bold(root)))
                        traceback.print_exc()

                console_output['filename'] = None   # reset output to stdout
Exemple #3
0
    def start(self):
        # log start
        log.info('Starting viper-cli')

        # Logo.
        logo()

        # Setup shell auto-complete.
        def complete(text, state):
            # Try to autocomplete both commands and modules
            completions = list()
            completions += [i for i in self.cmd.commands if i.startswith(text)]
            completions += [i for i in __modules__ if i.startswith(text)]

            if state < len(completions):
                return completions[state]

            # Then autocomplete paths.
            if text.startswith("~"):
                text = "{0}{1}".format(expanduser("~"), text[1:])
            return (glob.glob(text + '*') + [None])[state]

        # Auto-complete on tabs.
        readline.set_completer_delims(' \t\n;')
        readline.parse_and_bind('tab: complete')
        readline.set_completer(complete)

        # Save commands in history file.
        def save_history(path):
            readline.write_history_file(path)

        # If there is an history file, read from it and load the history
        # so that they can be loaded in the shell.
        # Now we are storing the history file in the local project folder
        history_path = os.path.join(__project__.path, 'history')

        if os.path.exists(history_path):
            readline.read_history_file(history_path)

        # Register the save history at program's exit.
        atexit.register(save_history, path=history_path)

        # Main loop.
        while self.active:
            # If there is an open session, we include the path to the opened
            # file in the shell prompt.
            # TODO: perhaps this block should be moved into the session so that
            # the generation of the prompt is done only when the session's
            # status changes.
            prefix = ''
            if __project__.name:
                prefix = bold(cyan(__project__.name)) + ' '

            if __sessions__.is_set():
                stored = ''
                filename = ''
                if __sessions__.current.file:
                    filename = __sessions__.current.file.name
                    if not Database().find(
                            key='sha256',
                            value=__sessions__.current.file.sha256):
                        stored = magenta(' [not stored]', True)

                misp = ''
                if __sessions__.current.misp_event:
                    misp = '[MISP'
                    if __sessions__.current.misp_event.event.id:
                        misp += ' {}'.format(
                            __sessions__.current.misp_event.event.id)
                    else:
                        misp += ' New Event'
                    if __sessions__.current.misp_event.off:
                        misp += ' (Offline)'
                    misp += ']'

                prompt = (prefix + cyan('viper ', True) +
                          white(filename, True) + blue(misp, True) + stored +
                          cyan(' > ', True))
            # Otherwise display the basic prompt.
            else:
                prompt = prefix + cyan('viper > ', True)

            # Wait for input from the user.
            try:
                data = input(prompt).strip()
            except KeyboardInterrupt:
                print("")
            # Terminate on EOF.
            except EOFError:
                self.stop()
                print("")
                continue
            # Parse the input if the user provided any.
            else:
                # If there are recognized keywords, we replace them with
                # their respective value.
                data = self.keywords(data)
                # Skip if the input is empty.
                if not data:
                    continue

                # Check for output redirection
                # If there is a > in the string, we assume the user wants to output to file.
                if '>' in data:
                    data, console_output['filename'] = data.split('>')
                    print("Writing output to {0}".format(
                        console_output['filename'].strip()))

                # If the input starts with an exclamation mark, we treat the
                # input as a bash command and execute it.
                # At this point the keywords should be replaced.
                if data.startswith('!'):
                    os.system(data[1:])
                    continue

                # Try to split commands by ; so that you can sequence multiple
                # commands at once.
                # For example:
                # viper > find name *.pdf; open --last 1; pdf id
                # This will automatically search for all PDF files, open the first entry
                # and run the pdf module against it.
                split_commands = data.split(';')
                for split_command in split_commands:
                    split_command = split_command.strip()
                    if not split_command:
                        continue

                    # If it's an internal command, we parse the input and split it
                    # between root command and arguments.
                    root, args = self.parse(split_command)

                    # Check if the command instructs to terminate.
                    if root in ('exit', 'quit'):
                        self.stop()
                        continue

                    try:
                        # If the root command is part of the embedded commands list we
                        # execute it.
                        if root in self.cmd.commands:
                            self.cmd.commands[root]['obj'](*args)
                            del (self.cmd.output[:])
                        # If the root command is part of loaded modules, we initialize
                        # the module and execute it.
                        elif root in __modules__:
                            module = __modules__[root]['obj']()
                            module.set_commandline(args)
                            module.run()

                            if cfg.modules.store_output and __sessions__.is_set(
                            ):
                                try:
                                    Database().add_analysis(
                                        __sessions__.current.file.sha256,
                                        split_command, module.output)
                                except:
                                    pass
                            del (module.output[:])
                        else:
                            print("Command not recognized.")
                    except KeyboardInterrupt:
                        pass
                    except Exception:
                        print_error(
                            "The command {0} raised an exception:".format(
                                bold(root)))
                        traceback.print_exc()

                console_output['filename'] = None  # reset output to stdout