Exemplo n.º 1
0
def logo():
    print("""         _
        (_)
   _   _ _ ____  _____  ____
  | | | | |  _ \| ___ |/ ___)
   \ V /| | |_| | ____| |
    \_/ |_|  __/|_____)_| v{}
          |_|
    """.format(__version__))

    db = Database()
    count = db.get_sample_count()

    try:
        db.find('all')
    except Exception:
        print_error("You need to update your Viper database. Run 'python update.py -d'")
        sys.exit()

    if __project__.name:
        name = __project__.name
    else:
        name = 'default'

    print(magenta("You have " + bold(count)) +
          magenta(" files in your " + bold(name)) +
          magenta(" repository"))
Exemplo n.º 2
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if __sessions__.is_set():
            if not __sessions__.current.file.id:
                self.log(
                    'error',
                    "The opened file does not have an ID, have you stored it yet?"
                )
                return

            self.log(
                'info', "Current name is: {}".format(
                    bold(__sessions__.current.file.name)))

            new_name = input("New name: ")
            if not new_name:
                self.log('error', "File name can't  be empty!")
                return

            Database().rename(__sessions__.current.file.id, new_name)

            self.log('info', "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
        else:
            self.log(
                'error',
                "No open session. This command expects a file to be open.")
Exemplo n.º 3
0
    def cmd_help(self, *args):
        print(bold("Commands:"))

        rows = []
        for command_name, command_item in self.commands.items():
            rows.append([command_name, command_item['description']])

        print(table(['Command', 'Description'], rows))       
        print("")
        print(bold("Modules:"))

        rows = []
        for module_name, module_item in __modules__.items():
            rows.append([module_name, module_item['description']])

        print(table(['Command', 'Description'], rows))
Exemplo n.º 4
0
    def cmd_projects(self, *args):
        parser = argparse.ArgumentParser(
            prog='projects',
            description="Open a file",
            epilog="List or switch existing projects")
        group = parser.add_mutually_exclusive_group()
        group.add_argument('-l',
                           '--list',
                           action='store_true',
                           help="List all existing projects")
        group.add_argument('-s',
                           '--switch',
                           metavar='PROJECT NAME',
                           help="Switch to the specified project")

        try:
            args = parser.parse_args(args)
        except:
            return

        projects_path = os.path.join(expanduser("~"), '.viper', 'projects')

        if not os.path.exists(projects_path):
            self.log('info', "The projects directory does not exist yet")
            return

        if args.list:
            self.log('info', "Projects Available:")

            rows = []
            for project in os.listdir(projects_path):
                project_path = os.path.join(projects_path, project)
                if os.path.isdir(project_path):
                    current = ''
                    if __project__.name and project == __project__.name:
                        current = 'Yes'
                    rows.append([
                        project,
                        time.ctime(os.path.getctime(project_path)), current
                    ])

            self.log(
                'table',
                dict(header=['Project Name', 'Creation Time', 'Current'],
                     rows=rows))
        elif args.switch:
            if __sessions__.is_set():
                __sessions__.close()
                self.log('info', "Closed opened session")

            __project__.open(args.switch)
            self.log('info',
                     "Switched to project {0}".format(bold(args.switch)))

            # Need to re-initialize the Database to open the new SQLite file.
            self.db = Database()
        else:
            self.log('info', parser.print_usage())
Exemplo n.º 5
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if not __sessions__.is_set():
            self.log(
                'error',
                "No open session. This command expects a file to be open.")
            return

        db = Database()

        # check if the file is already stores, otherwise exit
        malware = db.find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log(
                'error',
                "The opened file doesn't appear to be in the database, have you stored it yet?"
            )
            return

        if args.list:
            # Retrieve all analysis for the currently opened file.

            analysis_list = malware[0].analysis
            if not analysis_list:
                self.log('info', "No analysis available for this file yet")
                return

            # Populate table rows.
            rows = [[analysis.id, analysis.cmd_line, analysis.stored_at]
                    for analysis in analysis_list]

            # Display list of existing results.
            self.log(
                'table',
                dict(header=['ID', 'Cmd Line', 'Saved On (UTC)'], rows=rows))

        elif args.view:
            # Retrieve analysis wth the specified ID and print it.
            result = db.get_analysis(args.view)
            if result:
                self.log('info', bold('Cmd Line: ') + result.cmd_line)
                for line in json.loads(result.results):
                    self.log(line['type'], line['data'])
            else:
                self.log('info',
                         "There is no analysis with ID {0}".format(args.view))

        elif args.delete:
            # Delete the analysis with the specified ID.
            db.delete_analysis(args.delete)
        else:
            self.parser.print_usage()
Exemplo n.º 6
0
 def cmd_new(self, *args):
     title = input("Enter a title for the new file: ")
     # Create a new temporary file.
     tmp = tempfile.NamedTemporaryFile(delete=False)
     # Open the temporary file with the default editor, or with nano.
     os.system('"${EDITOR:-nano}" ' + tmp.name)
     __sessions__.new(tmp.name)
     __sessions__.current.file.name = title
     self.log(
         'info',
         "New file with title \"{0}\" added to the current session".format(
             bold(title)))
Exemplo n.º 7
0
def logo():
    print("""         _
        (_)
   _   _ _ ____  _____  ____
  | | | | |  _ \\| ___ |/ ___)
   \\ V /| | |_| | ____| |
    \\_/ |_|  __/|_____)_| v{}
          |_|
    """.format(__version__))

    db = Database()
    count = db.get_sample_count()

    try:
        db.find("all")
    except Exception:
        sys.exit()

    if __project__.name:
        name = __project__.name
    else:
        name = "default"

    print(
        magenta("You have " + bold(count)) +
        magenta(" files in your " + bold(name)) + magenta(" repository."))

    modules_count = len(__modules__)
    if modules_count == 0:
        print("")
        print(red(bold("You do not have any modules installed!")))
        print(
            red("If you wish to download community modules from GitHub run:"))
        print(red(bold("    update-modules")))
    else:
        print(
            magenta("You have " + bold(modules_count)) +
            magenta(" modules installed."))
Exemplo n.º 8
0
    def cmd_projects(self, *args):
        parser = argparse.ArgumentParser(prog='projects', description="Open a file", epilog="List or switch existing projects")
        group = parser.add_mutually_exclusive_group()
        group.add_argument('-l', '--list', action='store_true', help="List all existing projects")
        group.add_argument('-s', '--switch', metavar='PROJECT NAME', help="Switch to the specified project")

        try:
            args = parser.parse_args(args)
        except:
            return

        cfg = Config()
        if cfg.paths.storage_path:
            base_path = cfg.paths.storage_path
        else:
            base_path = os.path.join(expanduser("~"), '.viper')

        projects_path = os.path.join(base_path, 'projects')
        
        if not os.path.exists(projects_path):
            self.log('info', "The projects directory does not exist yet")
            return

        if args.list:
            self.log('info', "Projects Available:")

            rows = []
            for project in os.listdir(projects_path):
                project_path = os.path.join(projects_path, project)
                if os.path.isdir(project_path):
                    current = ''
                    if __project__.name and project == __project__.name:
                        current = 'Yes'
                    rows.append([project, time.ctime(os.path.getctime(project_path)), current])

            self.log('table', dict(header=['Project Name', 'Creation Time', 'Current'], rows=rows))
        elif args.switch:
            if __sessions__.is_set():
                __sessions__.close()
                self.log('info', "Closed opened session")

            __project__.open(args.switch)
            self.log('info', "Switched to project {0}".format(bold(args.switch)))

            # Need to re-initialize the Database to open the new SQLite file.
            self.db = Database()
        else:
            self.log('info', parser.print_usage())
Exemplo n.º 9
0
    def cmd_analysis(self, *args):
        parser = argparse.ArgumentParser(prog="analysis", description="Show stored module results")
        group = parser.add_mutually_exclusive_group()
        group.add_argument('-l', '--list', action='store_true',
                           help="List all module results available for the current file")
        group.add_argument('-v', '--view', metavar='ANALYSIS ID', type=int, help="View the specified analysis")
        group.add_argument('-d', '--delete', metavar='ANALYSIS ID', type=int, help="Delete an existing analysis")

        try:
            args = parser.parse_args(args)
        except:
            return

        if not __sessions__.is_set():
            self.log('error', "No open session")
            return

        # check if the file is already stores, otherwise exit
        malware = Database().find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log('error', "The opened file doesn't appear to be in the database, have you stored it yet?")
            return

        if args.list:
            # Retrieve all analysis for the currently opened file.

            analysis_list = malware[0].analysis
            if not analysis_list:
                self.log('info', "No analysis available for this file yet")
                return

            # Populate table rows.
            rows = [[analysis.id, analysis.cmd_line, analysis.stored_at] for analysis in analysis_list]

            # Display list of existing results.
            self.log('table', dict(header=['ID', 'Cmd Line', 'Saved On'], rows=rows))

        elif args.view:
            # Retrieve analysis wth the specified ID and print it.
            result = Database().get_analysis(args.view)
            if result:
                self.log('info', bold('Cmd Line: ') + result.cmd_line)
                for line in json.loads(result.results):
                    self.log(line['type'], line['data'])
            else:
                self.log('info', "There is no analysis with ID {0}".format(args.view))
Exemplo n.º 10
0
    def cmd_analysis(self, *args):
        parser = argparse.ArgumentParser(prog="analysis", description="Show stored module results")
        group = parser.add_mutually_exclusive_group()
        group.add_argument('-l', '--list', action='store_true',
                           help="List all module results available for the current file")
        group.add_argument('-v', '--view', metavar='ANALYSIS ID', type=int, help="View the specified analysis")
        group.add_argument('-d', '--delete', metavar='ANALYSIS ID', type=int, help="Delete an existing analysis")

        try:
            args = parser.parse_args(args)
        except:
            return

        if not __sessions__.is_set():
            self.log('error', "No open session")
            return

        # check if the file is already stores, otherwise exit
        malware = Database().find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log('error', "The opened file doesn't appear to be in the database, have you stored it yet?")
            return

        if args.list:
            # Retrieve all analysis for the currently opened file.

            analysis_list = malware[0].analysis
            if not analysis_list:
                self.log('info', "No analysis available for this file yet")
                return

            # Populate table rows.
            rows = [[analysis.id, analysis.cmd_line, analysis.stored_at] for analysis in analysis_list]

            # Display list of existing results.
            self.log('table', dict(header=['ID', 'Cmd Line', 'Saved On'], rows=rows))

        elif args.view:
            # Retrieve analysis wth the specified ID and print it.
            result = Database().get_analysis(args.view)
            if result:
                self.log('info', bold('Cmd Line: ') + result.cmd_line)
                for line in json.loads(result.results):
                    self.log(line['type'], line['data'])
            else:
                self.log('info', "There is no analysis with ID {0}".format(args.view))
Exemplo n.º 11
0
    def cmd_rename(self, *args):
        if __sessions__.is_set():
            if not __sessions__.current.file.id:
                self.log('error', "The opened file does not have an ID, have you stored it yet?")
                return

            self.log('info', "Current name is: {}".format(bold(__sessions__.current.file.name)))

            new_name = input("New name: ")
            if not new_name:
                self.log('error', "File name can't  be empty!")
                return

            self.db.rename(__sessions__.current.file.id, new_name)

            self.log('info', "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
        else:
            self.log('error', "No open session")
Exemplo n.º 12
0
    def cmd_rename(self, *args):
        if __sessions__.is_set():
            if not __sessions__.current.file.id:
                self.log('error', "The opened file does not have an ID, have you stored it yet?")
                return

            self.log('info', "Current name is: {}".format(bold(__sessions__.current.file.name)))
            
            new_name = input("New name: ")
            if not new_name:
                self.log('error', "File name can't  be empty!")
                return

            self.db.rename(__sessions__.current.file.id, new_name)

            self.log('info', "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
        else:
            self.log('error', "No open session")
Exemplo n.º 13
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if cfg.get('paths').storage_path:
            base_path = cfg.get('paths').storage_path
        else:
            base_path = os.path.join(expanduser("~"), '.viper')

        projects_path = os.path.join(base_path, 'projects')

        if args.list:
            if not os.path.exists(projects_path):
                self.log('info', "The projects directory does not exist yet")
                return

            self.log('info', "Projects Available:")

            rows = []
            for project in os.listdir(projects_path):
                project_path = os.path.join(projects_path, project)
                if os.path.isdir(project_path):
                    current = ''
                    if __project__.name and project == __project__.name:
                        current = 'Yes'
                    rows.append([project, time.ctime(os.path.getctime(project_path)), current])

            self.log('table', dict(header=['Project Name', 'Creation Time', 'Current'], rows=rows))
        elif args.switch:
            if __sessions__.is_set():
                __sessions__.close()
                self.log('info', "Closed opened session")

            __project__.open(args.switch)
            self.log('info', "Switched to project {0}".format(bold(args.switch)))

            # Need to re-initialize the Database to open the new SQLite file.
            db.__init__()
        else:
            self.log('info', self.parser.print_usage())
Exemplo n.º 14
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if not __sessions__.is_set():
            self.log('error', "No open session. This command expects a file to be open.")
            return

        db = Database()

        # check if the file is already stores, otherwise exit
        malware = db.find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log('error', "The opened file doesn't appear to be in the database, have you stored it yet?")
            return

        if args.list:
            # Retrieve all analysis for the currently opened file.

            analysis_list = malware[0].analysis
            if not analysis_list:
                self.log('info', "No analysis available for this file yet")
                return

            # Populate table rows.
            rows = [[analysis.id, analysis.cmd_line, analysis.stored_at] for analysis in analysis_list]

            # Display list of existing results.
            self.log('table', dict(header=['ID', 'Cmd Line', 'Saved On (UTC)'], rows=rows))

        elif args.view:
            # Retrieve analysis wth the specified ID and print it.
            result = db.get_analysis(args.view)
            if result:
                self.log('info', bold('Cmd Line: ') + result.cmd_line)
                for line in json.loads(result.results):
                    self.log(line['type'], line['data'])
            else:
                self.log('info', "There is no analysis with ID {0}".format(args.view))
Exemplo n.º 15
0
def print_info(message):
    print(bold(cyan("[*]")) + " {0}".format(message))
Exemplo n.º 16
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if not __sessions__.is_set():
            self.log('error', "No open session")
            return

        # check if the file is already stores, otherwise exit as no notes command will work if the file is not stored in the database
        malware = db.find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log('error', "The opened file doesn't appear to be in the database, have you stored it yet?")
            return

        if args.list:
            # Retrieve all notes for the currently opened file.

            notes = malware[0].note
            if not notes:
                self.log('info', "No notes available for this file yet")
                return

            # Populate table rows.
            rows = [[note.id, note.title] for note in notes]

            # Display list of existing notes.
            self.log('table', dict(header=['ID', 'Title'], rows=rows))

        elif args.add:
            title = input("Enter a title for the new note: ")

            # Create a new temporary file.
            with tempfile.NamedTemporaryFile(mode='w+') as tmp:
                # Open the temporary file with the default editor, or with nano.
                os.system('"${EDITOR:-nano}" ' + tmp.name)
                # Once the user is done editing, we need to read the content and
                # store it in the database.
                body = tmp.read()
                db.add_note(__sessions__.current.file.sha256, title, body)

            self.log('info', 'New note with title "{0}" added to the current file'.format(bold(title)))

        elif args.view:
            # Retrieve note wth the specified ID and print it.
            note = db.get_note(args.view)
            if note:
                self.log('info', bold('Title: ') + note.title)
                if isinstance(note.body, bytes):
                    # OLD: Old style, the content is stored as bytes
                    # This is fixed when the user edits the old note.
                    body = note.body.decode()
                else:
                    body = note.body
                self.log('info', '{}\n{}'.format(bold('Body:'), body))
            else:
                self.log('info', "There is no note with ID {0}".format(args.view))

        elif args.edit:
            # Retrieve note with the specified ID.
            note = db.get_note(args.edit)
            if note:
                # Create a new temporary file.
                with tempfile.NamedTemporaryFile(mode='w+') as tmp:
                    # Write the old body to the temporary file.
                    if isinstance(note.body, bytes):
                        # OLD: Old style, the content is stored as bytes
                        body = note.body.decode()
                    else:
                        body = note.body
                    tmp.write(body)
                    tmp.flush()
                    tmp.seek(0)
                    # Open the old body with the text editor.
                    os.system('"${EDITOR:-nano}" ' + tmp.name)
                    # Read the new body from the temporary file.
                    body = tmp.read()
                    # Update the note entry with the new body.
                    db.edit_note(args.edit, body)

                self.log('info', "Updated note with ID {0}".format(args.edit))

        elif args.delete:
            # Delete the note with the specified ID.
            db.delete_note(args.delete)
        else:
            self.parser.print_usage()
Exemplo n.º 17
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        title = input("Enter a title for the new file: ")
        # Create a new temporary file.
        tmp = tempfile.NamedTemporaryFile(delete=False)
        # Open the temporary file with the default editor, or with nano.
        os.system('"${EDITOR:-nano}" ' + tmp.name)
        __sessions__.new(tmp.name)
        __sessions__.current.file.name = title
        self.log('info', "New file with title \"{0}\" added to the current session".format(bold(title)))
Exemplo n.º 18
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
Exemplo n.º 19
0
    def start(self):
        # Setup shell auto-complete.
        def complete(text, state):
            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.
        history_path = os.path.expanduser('~/.viperhistory')
        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.
            if __session__.is_set():
                prompt = cyan('shell ') + white(__session__.file.name) + cyan(' > ')
            # Otherwise display the basic prompt.
            else:
                prompt = cyan('shell > ')

            # Wait for input from the user.
            try:
                data = raw_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

                # 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

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

                # 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)
                    # 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_args(args)
                        module.run()
                    else:
                        print("Command not recognized.")
                except KeyboardInterrupt:
                    pass
                except Exception as e:
                    print_error("The command {0} raised an exception:".format(bold(root)))
                    traceback.print_exc()
Exemplo n.º 20
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
Exemplo n.º 21
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if not __sessions__.is_set():
            self.log(
                'error',
                "No open session. This command expects a file to be open.")
            return

        db = Database()

        # check if the file is already stores, otherwise exit as no notes command will work if the file is not stored in the database
        malware = db.find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log(
                'error',
                "The opened file doesn't appear to be in the database, have you stored it yet?"
            )
            return

        if args.list:
            # Retrieve all notes for the currently opened file.

            notes = malware[0].note
            if not notes:
                self.log('info', "No notes available for this file yet")
                return

            # Populate table rows.
            rows = [[note.id, note.title] for note in notes]

            # Display list of existing notes.
            self.log('table', dict(header=['ID', 'Title'], rows=rows))

        elif args.add:
            title = input("Enter a title for the new note: ")

            # Create a new temporary file.
            with tempfile.NamedTemporaryFile(mode='w+') as tmp:
                # Open the temporary file with the default editor, or with nano.
                os.system('"${EDITOR:-nano}" ' + tmp.name)
                # Once the user is done editing, we need to read the content and
                # store it in the database.
                body = tmp.read()
                db.add_note(__sessions__.current.file.sha256, title, body)

            self.log(
                'info',
                'New note with title "{0}" added to the current file'.format(
                    bold(title)))

        elif args.view:
            # Retrieve note wth the specified ID and print it.
            note = db.get_note(args.view)
            if note:
                self.log('info', bold('Title: ') + note.title)
                if isinstance(note.body, bytes):
                    # OLD: Old style, the content is stored as bytes
                    # This is fixed when the user edits the old note.
                    body = note.body.decode()
                else:
                    body = note.body
                self.log('info', '{}\n{}'.format(bold('Body:'), body))
            else:
                self.log('info',
                         "There is no note with ID {0}".format(args.view))

        elif args.edit:
            # Retrieve note with the specified ID.
            note = db.get_note(args.edit)
            if note:
                # Create a new temporary file.
                with tempfile.NamedTemporaryFile(mode='w+') as tmp:
                    # Write the old body to the temporary file.
                    if isinstance(note.body, bytes):
                        # OLD: Old style, the content is stored as bytes
                        body = note.body.decode()
                    else:
                        body = note.body
                    tmp.write(body)
                    tmp.flush()
                    tmp.seek(0)
                    # Open the old body with the text editor.
                    os.system('"${EDITOR:-nano}" ' + tmp.name)
                    # Read the new body from the temporary file.
                    body = tmp.read()
                    # Update the note entry with the new body.
                    db.edit_note(args.edit, body)

                self.log('info', "Updated note with ID {0}".format(args.edit))

        elif args.delete:
            # Delete the note with the specified ID.
            db.delete_note(args.delete)
        else:
            self.parser.print_usage()
Exemplo n.º 22
0
def print_success(message):
    print(bold(green("[+]")) + " {0}".format(message))
Exemplo n.º 23
0
def print_error(message):
    print(bold(red("[!]")) + " {0}".format(message))
Exemplo n.º 24
0
    def cmd_notes(self, *args):
        parser = argparse.ArgumentParser(
            prog="notes", description="Show information on the opened file")
        group = parser.add_mutually_exclusive_group()
        group.add_argument(
            '-l',
            '--list',
            action='store_true',
            help="List all notes available for the current file")
        group.add_argument('-a',
                           '--add',
                           action='store_true',
                           help="Add a new note to the current file")
        group.add_argument('-v',
                           '--view',
                           metavar='NOTE ID',
                           type=int,
                           help="View the specified note")
        group.add_argument('-e',
                           '--edit',
                           metavar='NOTE ID',
                           type=int,
                           help="Edit an existing note")
        group.add_argument('-d',
                           '--delete',
                           metavar='NOTE ID',
                           type=int,
                           help="Delete an existing note")

        try:
            args = parser.parse_args(args)
        except:
            return

        if not __sessions__.is_set():
            self.log('error', "No open session")
            return

        # check if the file is already stores, otherwise exit as no notes command will work if the file is not stored in the database
        malware = Database().find(key='sha256',
                                  value=__sessions__.current.file.sha256)
        if not malware:
            self.log(
                'error',
                "The opened file doesn't appear to be in the database, have you stored it yet?"
            )
            return

        if args.list:
            # Retrieve all notes for the currently opened file.

            notes = malware[0].note
            if not notes:
                self.log('info', "No notes available for this file yet")
                return

            # Populate table rows.
            rows = [[note.id, note.title] for note in notes]

            # Display list of existing notes.
            self.log('table', dict(header=['ID', 'Title'], rows=rows))

        elif args.add:
            title = input("Enter a title for the new note: ")

            # Create a new temporary file.
            tmp = tempfile.NamedTemporaryFile(delete=False)
            # Open the temporary file with the default editor, or with nano.
            os.system('"${EDITOR:-nano}" ' + tmp.name)
            # Once the user is done editing, we need to read the content and
            # store it in the database.
            body = tmp.read()
            Database().add_note(__sessions__.current.file.sha256, title, body)
            # Finally, remove the temporary file.
            os.remove(tmp.name)

            self.log(
                'info',
                "New note with title \"{0}\" added to the current file".format(
                    bold(title)))

        elif args.view:
            # Retrieve note wth the specified ID and print it.
            note = Database().get_note(args.view)
            if note:
                self.log('info', bold('Title: ') + note.title)
                self.log('info', bold('Body:') + '\n' + note.body)
            else:
                self.log('info',
                         "There is no note with ID {0}".format(args.view))

        elif args.edit:
            # Retrieve note with the specified ID.
            note = Database().get_note(args.edit)
            if note:
                # Create a new temporary file.
                tmp = tempfile.NamedTemporaryFile(delete=False)
                # Write the old body to the temporary file.
                tmp.write(note.body)
                tmp.close()
                # Open the old body with the text editor.
                os.system('"${EDITOR:-nano}" ' + tmp.name)
                # Read the new body from the temporary file.
                body = open(tmp.name, 'r').read()
                # Update the note entry with the new body.
                Database().edit_note(args.edit, body)
                # Remove the temporary file.
                os.remove(tmp.name)

                self.log('info', "Updated note with ID {0}".format(args.edit))

        elif args.delete:
            # Delete the note with the specified ID.
            Database().delete_note(args.delete)
        else:
            parser.print_usage()
Exemplo n.º 25
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
Exemplo n.º 26
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if __config__.get('paths').storage_path:
            base_path = __config__.get('paths').storage_path
        else:
            base_path = os.path.join(expanduser("~"), '.viper')

        projects_path = os.path.join(base_path, 'projects')

        if args.list:
            if not os.path.exists(projects_path):
                self.log('info', "The projects directory does not exist yet")
                return

            self.log('info', "Projects Available:")

            rows = []
            for project in os.listdir(projects_path):
                project_path = os.path.join(projects_path, project)
                if os.path.isdir(project_path):
                    current = ''
                    if __project__.name and project == __project__.name:
                        current = 'Yes'
                    rows.append([project, time.ctime(os.path.getctime(project_path)), current])

            self.log('table', dict(header=['Project Name', 'Creation Time', 'Current'], rows=rows))
        elif args.switch:
            if __sessions__.is_set():
                __sessions__.close()
                self.log('info', "Closed opened session")

            __project__.open(args.switch)
            self.log('info', "Switched to project {0}".format(bold(args.switch)))

            # Need to re-initialize the Database to open the new SQLite file.
            Database().__init__()
        elif args.close:
            if __project__.name != "default":
                if __sessions__.is_set():
                    __sessions__.close()

                __project__.close()
        elif args.delete:
            project_to_delete = args.delete
            if project_to_delete == "default":
                self.log('error', "You can't delete the \"default\" project")
                return

            # If it's the currently opened project, we close it.
            if project_to_delete == __project__.name:
                # We close any opened session.
                if __sessions__.is_set():
                    __sessions__.close()

                __project__.close()

            project_path = os.path.join(projects_path, project_to_delete)
            if not os.path.exists(project_path):
                self.log('error', "The folder for project \"{}\" does not seem to exist".format(project_to_delete))
                return

            self.log('info', "You asked to delete project with name \"{}\" located at \"{}\"".format(project_to_delete, project_path))

            confirm = input("Are you sure you want to delete the project? You will permanently delete all associated files! [y/N] ")
            if confirm.lower() != 'y':
                return

            try:
                shutil.rmtree(project_path)
            except Exception as e:
                self.log('error', "Something failed while trying to delete folder: {}".format(e))
                return

            self.log('info', "Project \"{}\" was delete successfully".format(project_to_delete))
        else:
            self.log('info', self.parser.print_usage())
Exemplo n.º 27
0
    def run(self, *args):
        try:
            args = self.parser.parse_args(args)
        except SystemExit:
            return

        if __config__.get("paths").storage_path:
            base_path = __config__.get("paths").storage_path
        else:
            base_path = os.path.join(expanduser("~"), ".viper")

        projects_path = os.path.join(base_path, "projects")

        if args.list:
            if not os.path.exists(projects_path):
                self.log("info", "No projects have been created yet")
                return

            self.log("info", "Projects Available:")

            rows = []
            for project in os.listdir(projects_path):
                project_path = os.path.join(projects_path, project)
                if os.path.isdir(project_path):
                    current = ""
                    if __project__.name and project == __project__.name:
                        current = "Yes"
                    rows.append([
                        project,
                        time.ctime(os.path.getctime(project_path)), current
                    ])

            self.log(
                "table",
                dict(header=["Project Name", "Creation Time", "Current"],
                     rows=rows))
        elif args.switch:
            if __sessions__.is_set():
                __sessions__.close()
                self.log("info", "Closed opened session")

            __project__.open(args.switch)
            self.log("info",
                     "Switched to project {0}".format(bold(args.switch)))

            # Need to re-initialize the Database to open the new SQLite file.
            Database().__init__()
        elif args.close:
            if __project__.name != "default":
                if __sessions__.is_set():
                    __sessions__.close()

                __project__.close()
        elif args.delete:
            project_to_delete = args.delete
            if project_to_delete == "default":
                self.log("error", "You can't delete the \"default\" project")
                return

            # If it"s the currently opened project, we close it.
            if project_to_delete == __project__.name:
                # We close any opened session.
                if __sessions__.is_set():
                    __sessions__.close()

                __project__.close()

            project_path = os.path.join(projects_path, project_to_delete)
            if not os.path.exists(project_path):
                self.log(
                    "error",
                    "The folder for project \"{}\" does not seem to exist".
                    format(project_to_delete))
                return

            self.log(
                "info",
                "You asked to delete project with name \"{}\" located at \"{}\""
                .format(project_to_delete, project_path))

            confirm = input(
                "Are you sure you want to delete the project? You will permanently delete all associated files! [y/N] "
            )
            if confirm.lower() != "y":
                return

            try:
                shutil.rmtree(project_path)
            except Exception as e:
                self.log(
                    "error",
                    "Something failed while trying to delete folder: {}".
                    format(e))
                return

            self.log(
                "info", "Project \"{}\" was delete successfully".format(
                    project_to_delete))
        else:
            self.log("info", self.parser.print_usage())
Exemplo n.º 28
0
    def start(self, sha256):
        # 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(os.getenv("HOME"), 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(os.getenv("HOME"), '.viperHistory')

        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:
            # It's a prompt. There it is.
            prompt = 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:
                # 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.
                filename = False
                if '>' in data:
                    data, filename = data.split('>')

                # 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

                # !!!!THIS IS THE LAZY COMMAND
                # If the input starts with a period it's an API call
                # so we shell out(this is a client, who gives a f**k) 
                # to curl and jq in this format: viper > .find tag=elf
                # Also the trigger to switch hashes: .use sha256hashhere
                if data.startswith('.'):
                    if data[1:].find('find') != -1:
                        tag = data.split(' ')
                        os.system('curl -F ' + str(tag[1]) + ' http://' + host + ':' + port + '/file/find | jq .')
                    if data[1:].find('use') != -1:
                        sha256 = data.split(' ')[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

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

                    try:
                        # call the Viper API POST method for cmdline
                        viperCommand(sha256=sha256, command=split_command)

                    except KeyboardInterrupt:
                        pass
                    except Exception:
                        print_error("The command {0} raised an exception:".format(bold(root)))
                        traceback.print_exc()
Exemplo n.º 29
0
    def run(self):
        if not __session__.is_set():
            print_error("No session opened")
            return

        if not HAVE_PYDEEP:
            print_error("Missing dependency, install pydeep (`pip install pydeep`)")
            return

        if not __session__.file.ssdeep:
            print_error("No ssdeep hash available for opened file")
            return

        def usage():
            print("usage: fuzzy [-v]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print("\t--verbose (-v)\tPrints verbose logging")
            print("")

        arg_verbose = False

        try:
            opts, argv = getopt.getopt(self.args[0:], 'hv', ['help', 'verbose'])
        except getopt.GetoptError as e:
            print(e)
            return

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-v', '--verbose'):
                arg_verbose = True

        db = Database()
        samples = db.find(key='all')

        matches = []
        for sample in samples:
            if sample.sha256 == __session__.file.sha256:
                continue

            if not sample.ssdeep:
                continue

            score = pydeep.compare(__session__.file.ssdeep, sample.ssdeep)
            if score > 40:
                matches.append(['{0}%'.format(score), sample.name, sample.sha256])

            if arg_verbose:
                print("Match {0}%: {2} [{1}]".format(score, sample.name, sample.sha256))

        print_info("{0} relevant matches found".format(bold(len(matches))))

        if len(matches) > 0:
            print(table(header=['Score', 'Name', 'SHA256'], rows=matches))
Exemplo n.º 30
0
    def cmd_notes(self, *args):
        parser = argparse.ArgumentParser(prog="notes", description="Show information on the opened file")
        group = parser.add_mutually_exclusive_group()
        group.add_argument('-l', '--list', action='store_true', help="List all notes available for the current file")
        group.add_argument('-a', '--add', action='store_true', help="Add a new note to the current file")
        group.add_argument('-v', '--view', metavar='NOTE ID', type=int, help="View the specified note")
        group.add_argument('-e', '--edit', metavar='NOTE ID', type=int, help="Edit an existing note")
        group.add_argument('-d', '--delete', metavar='NOTE ID', type=int, help="Delete an existing note")

        try:
            args = parser.parse_args(args)
        except:
            return

        if not __sessions__.is_set():
            self.log('error', "No open session")
            return

        # check if the file is already stores, otherwise exit as no notes command will work if the file is not stored in the database
        malware = Database().find(key='sha256', value=__sessions__.current.file.sha256)
        if not malware:
            self.log('error', "The opened file doesn't appear to be in the database, have you stored it yet?")
            return

        if args.list:
            # Retrieve all notes for the currently opened file.

            notes = malware[0].note
            if not notes:
                self.log('info', "No notes available for this file yet")
                return

            # Populate table rows.
            rows = [[note.id, note.title] for note in notes]

            # Display list of existing notes.
            self.log('table', dict(header=['ID', 'Title'], rows=rows))

        elif args.add:
            title = input("Enter a title for the new note: ")

            # Create a new temporary file.
            tmp = tempfile.NamedTemporaryFile(delete=False)
            # Open the temporary file with the default editor, or with nano.
            os.system('"${EDITOR:-nano}" ' + tmp.name)
            # Once the user is done editing, we need to read the content and
            # store it in the database.
            body = tmp.read()
            Database().add_note(__sessions__.current.file.sha256, title, body)
            # Finally, remove the temporary file.
            os.remove(tmp.name)

            self.log('info', "New note with title \"{0}\" added to the current file".format(bold(title)))

        elif args.view:
            # Retrieve note wth the specified ID and print it.
            note = Database().get_note(args.view)
            if note:
                self.log('info', bold('Title: ') + note.title)
                self.log('info', bold('Body:') + '\n' + note.body)
            else:
                self.log('info', "There is no note with ID {0}".format(args.view))

        elif args.edit:
            # Retrieve note with the specified ID.
            note = Database().get_note(args.edit)
            if note:
                # Create a new temporary file.
                tmp = tempfile.NamedTemporaryFile(delete=False)
                # Write the old body to the temporary file.
                tmp.write(note.body)
                tmp.close()
                # Open the old body with the text editor.
                os.system('"${EDITOR:-nano}" ' + tmp.name)
                # Read the new body from the temporary file.
                body = open(tmp.name, 'r').read()
                # Update the note entry with the new body.
                Database().edit_note(args.edit, body)
                # Remove the temporary file.
                os.remove(tmp.name)

                self.log('info', "Updated note with ID {0}".format(args.edit))

        elif args.delete:
            # Delete the note with the specified ID.
            Database().delete_note(args.delete)
        else:
            parser.print_usage()
Exemplo n.º 31
0
def print_warning(message):
    print(bold(yellow("[!]")) + " {0}".format(message))