Esempio n. 1
0
    def cmd_tags(self, *args):
        parser = argparse.ArgumentParser(
            prog='tags', description="Modify tags of the opened file")
        parser.add_argument(
            '-a',
            '--add',
            metavar='TAG',
            help="Add tags to the opened file (comma separated)")
        parser.add_argument('-d',
                            '--delete',
                            metavar='TAG',
                            help="Delete a tag from the opened file")
        try:
            args = parser.parse_args(args)
        except:
            return

        # This command requires a session to be opened.
        if not __sessions__.is_set():
            self.log('error', "No open session")
            parser.print_usage()
            return

        # If no arguments are specified, there's not much to do.
        # However, it could make sense to also retrieve a list of existing
        # tags from this command, and not just from the "find" command alone.
        if args.add is None and args.delete is None:
            parser.print_usage()
            return

        # TODO: handle situation where addition or deletion of a tag fail.

        db = Database()
        if not db.find(key='sha256', value=__sessions__.current.file.sha256):
            self.log(
                'error', "The opened file is not stored in the database. "
                "If you want to add it use the `store` command.")
            return

        if args.add:
            # Add specified tags to the database's entry belonging to
            # the opened file.
            db.add_tags(__sessions__.current.file.sha256, args.add)
            self.log('info', "Tags added to the currently opened file")

            # We refresh the opened session to update the attributes.
            # Namely, the list of tags returned by the 'info' command
            # needs to be re-generated, or it wouldn't show the new tags
            # until the existing session is closed a new one is opened.
            self.log('info', "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)

        if args.delete:
            # Delete the tag from the database.
            db.delete_tag(args.delete, __sessions__.current.file.sha256)
            # Refresh the session so that the attributes of the file are
            # updated.
            self.log('info', "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
Esempio n. 2
0
    def cmd_tags(self, *args):
        parser = argparse.ArgumentParser(prog="tags", description="Modify tags of the opened file")
        parser.add_argument("-a", "--add", metavar="TAG", help="Add tags to the opened file (comma separated)")
        parser.add_argument("-d", "--delete", metavar="TAG", help="Delete a tag from the opened file")
        try:
            args = parser.parse_args(args)
        except:
            return

        # This command requires a session to be opened.
        if not __sessions__.is_set():
            self.log("error", "No session opened")
            parser.print_usage()
            return

        # If no arguments are specified, there's not much to do.
        # However, it could make sense to also retrieve a list of existing
        # tags from this command, and not just from the "find" command alone.
        if args.add is None and args.delete is None:
            parser.print_usage()
            return

        # TODO: handle situation where addition or deletion of a tag fail.

        db = Database()
        if not db.find(key="sha256", value=__sessions__.current.file.sha256):
            self.log(
                "error",
                "The opened file is not stored in the database. " "If you want to add it use the `store` command.",
            )
            return

        if args.add:
            # Add specified tags to the database's entry belonging to
            # the opened file.
            db.add_tags(__sessions__.current.file.sha256, args.add)
            self.log("info", "Tags added to the currently opened file")

            # We refresh the opened session to update the attributes.
            # Namely, the list of tags returned by the 'info' command
            # needs to be re-generated, or it wouldn't show the new tags
            # until the existing session is closed a new one is opened.
            self.log("info", "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)

        if args.delete:
            # Delete the tag from the database.
            db.delete_tag(args.delete, __sessions__.current.file.sha256)
            # Refresh the session so that the attributes of the file are
            # updated.
            self.log("info", "Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
Esempio n. 3
0
def tags(tag_action=False):
    # Set DB
    db = Database()

    # Search or Delete
    if request.method == 'GET':
        action = request.query.action
        value = request.query.value.strip()

        if value:
            if action == 'search':
                # This will search all projects
                # Get project list
                projects = project_list()
                # Add Main db to list.
                projects.append('../')
                # Search All projects
                p_list = []
                results = {}
                for project in projects:
                    __project__.open(project)
                    # Init DB
                    db = Database()
                    #get results
                    proj_results = []
                    rows = db.find(key='tag', value=value)
                    for row in rows:
                        if project == '../':
                            project = 'Main'
                        proj_results.append([row.name, row.sha256])
                    results[project] = proj_results
                    p_list.append(project)
                # Return the search template
                return template('search.tpl', projects=p_list, results=results)
            else:
                return template(
                    'error.tpl',
                    error="'{0}' Is not a valid tag action".format(action))

    # Add / Delete
    if request.method == 'POST':
        file_hash = request.forms.get('sha256')
        project = request.forms.get('project')
        tag_name = request.forms.get('tag')
        if tag_action == 'add':
            if file_hash and project:
                tags = request.forms.get('tags')
                db.add_tags(file_hash, tags)
        if tag_action == 'del':
            if file_hash and tag_name:
                db.delete_tag(tag_name, file_hash)
        redirect('/file/{0}/{1}'.format(project, file_hash))
Esempio n. 4
0
def tags(tag_action=False):
    # Set DB
    db = Database()
    
    # Search or Delete
    if request.method == 'GET':
        action = request.query.action
        value = request.query.value.strip()
        
        if value:
            if action == 'search':
                # This will search all projects
                # Get project list
                projects = project_list()
                # Add Main db to list.
                projects.append('../')
                # Search All projects
                p_list = []
                results = {}
                for project in projects:
                    __project__.open(project)
                    # Init DB
                    db = Database()
                    #get results
                    proj_results = []
                    rows = db.find(key='tag', value=value)
                    for row in rows:
                        if project == '../':
                            project = 'Main'
                        proj_results.append([row.name, row.sha256])
                    results[project] = proj_results
                    p_list.append(project)
                # Return the search template
                return template('search.tpl', projects=p_list, results=results)
            else:
                return template('error.tpl', error="'{0}' Is not a valid tag action".format(action))
                             
    # Add / Delete                        
    if request.method == 'POST':
        file_hash = request.forms.get('sha256')
        project = request.forms.get('project')
        tag_name = request.forms.get('tag')
        if tag_action == 'add':
            if file_hash and project:
                tags = request.forms.get('tags')
                db.add_tags(file_hash, tags)
        if tag_action == 'del':
            if file_hash and tag_name:
                db.delete_tag(tag_name, file_hash)
        redirect('/file/{0}/{1}'.format(project, file_hash))
Esempio n. 5
0
def tags(tag_action=False):
    # Set DB
    db = Database()

    # Search or Delete
    if request.method == "GET":
        action = request.query.action
        value = request.query.value.strip()

        if value:
            if action == "search":
                # This will search all projects
                # Get project list
                projects = project_list()
                # Add Main db to list.
                projects.append("../")
                # Search All projects
                p_list = []
                results = {}
                for project in projects:
                    __project__.open(project)
                    # Init DB
                    db = Database()
                    # get results
                    proj_results = []
                    rows = db.find(key="tag", value=value)
                    for row in rows:
                        if project == "../":
                            project = "Main"
                        proj_results.append([row.name, row.sha256])
                    results[project] = proj_results
                    p_list.append(project)
                # Return the search template
                return template("search.tpl", projects=p_list, results=results)
            else:
                return template("error.tpl", error="'{0}' Is not a valid tag action".format(action))

    # Add / Delete
    if request.method == "POST":
        file_hash = request.forms.get("sha256")
        project = request.forms.get("project")
        tag_name = request.forms.get("tag")
        if tag_action == "add":
            if file_hash and project:
                tags = request.forms.get("tags")
                db.add_tags(file_hash, tags)
        if tag_action == "del":
            if file_hash and tag_name:
                db.delete_tag(tag_name, file_hash)
        redirect("/file/{0}/{1}".format(project, file_hash))
Esempio n. 6
0
File: api.py Progetto: blaquee/viper
def add_tags():
    tags = request.forms.get('tags')
    for entry in ['md5', 'sha256', 'ssdeep', 'tag', 'name', 'all']:
        value = request.forms.get(entry)
        if value:
            key = entry
            break
    db = Database()
    rows = db.find(key=key, value=value)
    
    if not rows:
        raise HTTPError(404, 'File not found in the database')
          
    for row in rows:
        malware_sha256=row.sha256
        db.add_tags(malware_sha256, tags)

    return jsonize({'message' : 'added'})
Esempio n. 7
0
def add_tags():
    tags = request.forms.get('tags')
    for entry in ['md5', 'sha256', 'ssdeep', 'tag', 'name', 'all']:
        value = request.forms.get(entry)
        if value:
            key = entry
            break
    db = Database()
    rows = db.find(key=key, value=value)

    if not rows:
        raise HTTPError(404, 'File not found in the database')

    for row in rows:
        malware_sha256 = row.sha256
        db.add_tags(malware_sha256, tags)

    return jsonize({'message': 'added'})
Esempio n. 8
0
    def run(self):
        super(Triage, self).run()
        db = Database()

        if self.args and self.args.all:
            samples = db.find(key='all')

            for sample in samples:
                tags = []
                tags.extend(self._triage_file_type(sample))

                db.add_tags(sample.sha256, tags)
        # We're running against the already opened file.
        else:
            if not __sessions__.is_set():
                self.log('error', "No open session. This command expects a file to be open.")
                return

            tags = []
            tags.extend(self._triage_file_type(__sessions__.current.file))

            db.add_tags(__sessions__.current.file.sha256, tags)
Esempio n. 9
0
    def run(self):
        super(Triage, self).run()
        db = Database()

        if self.args and self.args.all:
            samples = db.find(key='all')

            for sample in samples:
                tags = []
                tags.extend(self._triage_file_type(sample))

                db.add_tags(sample.sha256, tags)
        # We're running against the already opened file.
        else:
            if not __sessions__.is_set():
                self.log('error', "No open session")
                return

            tags = []
            tags.extend(self._triage_file_type(__sessions__.current.file))

            db.add_tags(__sessions__.current.file.sha256, tags)
Esempio n. 10
0
    def scan(self):
        arg_rule = self.args.rule
        arg_scan_all = self.args.all
        arg_tag = self.args.tag
        arg_verbose = self.args.verbose

        externals = {'filename': '', 'filepath': '', 'extension': '', 'filetype': ''}

        # If a rule file is specified we compile that, otherwise all
        # the rules we have stored locally.
        if arg_rule:
            # Check if the selected ruleset actually exists.
            if not os.path.exists(arg_rule):
                self.log('error', "The specified file does not exist at path {0}".format(arg_rule))
                return

            rules = yara.compile(arg_rule, externals=externals)
        # Otherwise, we get all the rules that are stored locally and we
        # load them in different namespaces.
        else:
            filepaths = dict()
            for rule in self._get_rules():
                filepaths['namespace' + str(rule[0])] = rule[1]

            rules = yara.compile(filepaths=filepaths, externals=externals, includes=False)

        # Files to scan.
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            self.log('info', "Scanning all stored files (in the current project)...")

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

            for sample in samples:
                files.append(sample)

        # Loop through all files to be scanned.
        for entry in files:
            if entry.size == 0:
                continue

            self.log('info', "Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, 'path'):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            # Check if the file exists before running the yara scan.
            if not os.path.exists(entry_path):
                self.log('error', "The file does not exist at path {0}".format(entry_path))
                return

            rows = []
            tag_list = []
            found = False

            # We need this just for some Yara rules.
            try:
                ext = os.path.splitext(entry.name)[1]
            except:
                ext = ''

            for match in rules.match(entry_path, externals={'filename': entry.name, 'filepath': entry_path, 'extension': ext, 'filetype': entry.type}):
                found = True
                # Add a row for each string matched by the rule.
                if arg_verbose:
                    for match_string in match.strings:
                        rows.append([
                            match.rule,
                            string_printable(match_string[1]),
                            string_printable(match_string[0]),
                            string_printable(match_string[2])]
                        )
                else:
                    self.log('item', match.rule)
                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get('tags')
                # If not, use the rule name.
                # TODO: as we add more and more yara rules, we might remove
                # this option and only tag the file with rules that had
                # tags specified in them.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if arg_verbose and rows:
                header = [
                    'Rule',
                    'String',
                    'Offset',
                    'Content'
                ]
                self.log('table', dict(header=header, rows=rows))
            # If we selected to add tags do that now.
            if found and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    self.log('info', "Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 11
0
    def cmd_tags(self, *args):
        def usage():
            print("usage: tags [-h] [-a=tags] [-d=tag]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print(
                "\t--add (-a)\tAdd tags to the opened file (comma separated)")
            print("\t--delete (-d)\tDelete a tag from the opened file")
            print("")

        try:
            opts, argv = getopt.getopt(args, 'ha:d:',
                                       ['help', 'add=', 'delete='])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_add = None
        arg_delete = None

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-a', '--add'):
                arg_add = value
            elif opt in ('-d', '--delete'):
                arg_delete = value

        # This command requires a session to be opened.
        if not __sessions__.is_set():
            print_error("No session opened")
            return

        # If no arguments are specified, there's not much to do.
        # However, it could make sense to also retrieve a list of existing
        # tags from this command, and not just from the "find" command alone.
        if not arg_add and not arg_delete:
            usage()
            return

        # TODO: handle situation where addition or deletion of a tag fail.

        if arg_add:
            # Add specified tags to the database's entry belonging to
            # the opened file.
            db = Database()
            db.add_tags(__sessions__.current.file.sha256, arg_add)
            print_info("Tags added to the currently opened file")

            # We refresh the opened session to update the attributes.
            # Namely, the list of tags returned by the "info" command
            # needs to be re-generated, or it wouldn't show the new tags
            # until the existing session is closed a new one is opened.
            print_info("Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)

        if arg_delete:
            # Delete the tag from the database.
            Database().delete_tag(arg_delete)
            # Refresh the session so that the attributes of the file are
            # updated.
            print_info("Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
Esempio n. 12
0
    def scan(self):
        def string_printable(line):
            line = str(line)
            new_line = ''
            for c in line:
                if c in printstring.printable:
                    new_line += c
                else:
                    new_line += '\\x' + c.encode('hex')
            return new_line

        # This means users can just drop or remove rule files without
        # having to worry about maintaining the index.
        # TODO: make paths absolute.
        # TODO: this regenerates the file at every run, perhaps we
        # could find a way to optimize this.
        def rule_index():
            tmp_path = os.path.join(tempfile.gettempdir(), 'index.yara')
            with open(tmp_path, 'w') as rules_index:
                for rule_file in os.listdir(self.rule_path):
                    # Skip if the extension is not right, could cause problems.
                    if not rule_file.endswith(
                            '.yar') and not rule_file.endswith('.yara'):
                        continue
                    # Skip if it's the index itself.
                    if rule_file == 'index.yara':
                        continue

                    # Add the rule to the index.
                    line = 'include "{0}"\n'.format(
                        os.path.join(self.rule_path, rule_file))
                    rules_index.write(line)

            return tmp_path

        arg_rule = self.args.rule
        arg_scan_all = self.args.all
        arg_tag = self.args.tag
        arg_verbose = self.args.verbose

        # If no custom ruleset is specified, we use the default one.
        if not arg_rule:
            arg_rule = rule_index()

        # Check if the selected ruleset actually exists.
        if not os.path.exists(arg_rule):
            self.log('error', "No valid Yara ruleset at {0}".format(arg_rule))
            return

        # Compile all rules from given ruleset.
        rules = yara.compile(arg_rule)
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            self.log('info', "Scanning all stored files...")

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

            for sample in samples:
                files.append(sample)

        for entry in files:
            if entry.size == 0:
                continue

            self.log('info',
                     "Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, 'path'):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            # Check if the file exists before running the yara scan.
            if not os.path.exists(entry_path):
                self.log(
                    'error',
                    "The file does not exist at path {0}".format(entry_path))
                return

            rows = []
            tag_list = []
            found = False
            for match in rules.match(entry_path):
                found = True
                # Add a row for each string matched by the rule.
                if arg_verbose:
                    for string in match.strings:
                        rows.append([
                            match.rule,
                            string_printable(string[1]),
                            string_printable(string[0]),
                            string_printable(string[2])
                        ])
                else:
                    self.log('item', match.rule)
                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get('tags')
                # If not, use the rule name.
                # TODO: as we add more and more yara rules, we might remove
                # this option and only tag the file with rules that had
                # tags specified in them.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if arg_verbose and rows:
                header = ['Rule', 'String', 'Offset', 'Content']
                self.log('table', dict(header=header, rows=rows))
            # If we selected to add tags do that now.
            if found and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    self.log('info',
                             "Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 13
0
    def scan(self):
        def usage():
            print("usage: yara scan [-a]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print("\t--rule (-r)\tSpecify a ruleset file path (default will run data/yara/index.yara)")
            print("\t--all (-a)\tScan all stored files (default if no session is open)")
            print("\t--tag (-t)\tTag Files with Rule Name (default is not to)")
            print("")

        def string_printable(line):
            line = str(line)
            new_line = ''
            for c in line:
                if c in printstring.printable:
                    new_line += c
                else:
                    new_line += '\\x'+c.encode('hex')
            return new_line


        arg_rule = ''
        arg_scan_all = False
        arg_tag = False

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hr:at', ['help', 'rule=', 'all', 'tag'])
        except getopt.GetoptError as e:
            print(e)
            return

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            if opt in ('-t', '--tag'):
                arg_tag = True
            elif opt in ('-r', '--rule'):
                arg_rule = value
            elif opt in ('-a', '--all'):
                arg_scan_all = True


        # If no custom ruleset is specified, we use the default one.
        if not arg_rule:
            arg_rule = 'data/yara/index.yara'

        # Check if the selected ruleset actually exists.
        if not os.path.exists(arg_rule):
            print_error("No valid Yara ruleset at {0}".format(arg_rule))
            return

        # Compile all rules from given ruleset.
        rules = yara.compile(arg_rule)
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            print_info("Scanning all stored files...")

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

            for sample in samples:
                files.append(sample)

        for entry in files:
            print_info("Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, 'path'):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            rows = []
            tag_list = []
            for match in rules.match(entry_path):
                # Add a row for each string matched by the rule.
                for string in match.strings:
                    rows.append([match.rule, string_printable(string[1]), string_printable(string[0]), string_printable(string[2])])
                
                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get('tags')
                # If not, use the rule name.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if rows:
                header = [
                    'Rule',
                    'String',
                    'Offset',
                    'Content'
                ]
                print(table(header=header, rows=rows))

            # If we selected to add tags do that now.
            if rows and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    print_info("Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 14
0
    def scan(self):
        def string_printable(line):
            line = str(line)
            new_line = ""
            for c in line:
                if c in printstring.printable:
                    new_line += c
                else:
                    new_line += "\\x" + c.encode("hex")
            return new_line

        # This means users can just drop or remove rule files without
        # having to worry about maintaining the index.
        # TODO: make paths absolute.
        # TODO: this regenerates the file at every run, perhaps we
        # could find a way to optimize this.
        def rule_index():
            tmp_path = os.path.join(tempfile.gettempdir(), "index.yara")
            with open(tmp_path, "w") as rules_index:
                for rule_file in os.listdir(self.rule_path):
                    # Skip if the extension is not right, could cause problems.
                    if not rule_file.endswith(".yar") and not rule_file.endswith(".yara"):
                        continue
                    # Skip if it's the index itself.
                    if rule_file == "index.yara":
                        continue

                    # Add the rule to the index.
                    line = 'include "{0}"\n'.format(os.path.join(self.rule_path, rule_file))
                    rules_index.write(line)

            return tmp_path

        arg_rule = self.args.rule
        arg_scan_all = self.args.all
        arg_tag = self.args.tag

        # If no custom ruleset is specified, we use the default one.
        if not arg_rule:
            arg_rule = rule_index()

        # Check if the selected ruleset actually exists.
        if not os.path.exists(arg_rule):
            self.log("error", "No valid Yara ruleset at {0}".format(arg_rule))
            return

        # Compile all rules from given ruleset.
        rules = yara.compile(arg_rule)
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            self.log("info", "Scanning all stored files...")

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

            for sample in samples:
                files.append(sample)

        for entry in files:
            if entry.size == 0:
                continue

            self.log("info", "Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, "path"):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            # Check if the file exists before running the yara scan.
            if not os.path.exists(entry_path):
                self.log("error", "The file does not exist at path {0}".format(entry_path))
                return

            rows = []
            tag_list = []
            for match in rules.match(entry_path):
                # Add a row for each string matched by the rule.
                for string in match.strings:
                    rows.append(
                        [
                            match.rule,
                            string_printable(string[1]),
                            string_printable(string[0]),
                            string_printable(string[2]),
                        ]
                    )

                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get("tags")
                # If not, use the rule name.
                # TODO: as we add more and more yara rules, we might remove
                # this option and only tag the file with rules that had
                # tags specified in them.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if rows:
                header = ["Rule", "String", "Offset", "Content"]
                self.log("table", dict(header=header, rows=rows))

            # If we selected to add tags do that now.
            if rows and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    self.log("info", "Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 15
0
class ClamAV(Module):
    cmd = 'clamav'
    description = 'Scan file from local ClamAV daemon'
    authors = ['neriberto']

    def __init__(self):
        super(ClamAV, self).__init__()
        self.parser.add_argument(
            '-s',
            '--socket',
            help='Specify an unix socket (default: Clamd Unix Socket)')
        self.parser.add_argument('-a',
                                 '--all',
                                 action='store_true',
                                 help='Scan all files')
        self.parser.add_argument(
            '-t',
            '--tag',
            action='store_true',
            help='Tag file(s) with the signature name when detect as malware')
        self.db = Database()

    def run(self):
        super(ClamAV, self).run()
        if self.args is None:
            return

        if not HAVE_CLAMD:
            self.log(
                'error',
                "Missing dependency, install pyclamd (`pip install pyclamd`)")
            return

        if not self.Connect():
            self.log('error', 'Daemon is not responding!')
            return

        if self.args.all:
            self.ScanAll()
        elif __sessions__.is_set():
            self.ScanFile(__sessions__.current.file)
        else:
            self.log('error', 'No open session')

    def ScanAll(self):
        samples = self.db.find(key='all')
        for sample in samples:
            if sample.size == 0:
                continue
            self.ScanFile(sample)

    def Connect(self):
        self.daemon = None
        self.socket = self.args.socket
        try:
            if self.socket is not None:
                self.daemon = pyclamd.ClamdUnixSocket(self.socket)
                self.log('info',
                         'Using socket {0} to scan'.format(self.socket))
            else:
                self.daemon = pyclamd.ClamdUnixSocket()
                self.socket = 'Clamav'

            return self.daemon.ping()
        except Exception as ex:
            msg = 'Daemon connection failure, {0}'.format(ex)
            self.log('error,', msg)
            return False

    def ScanFile(self, sample):

        if isinstance(sample, Malware):
            sample_path = get_sample_path(sample.sha256)
        else:
            sample_path = sample.path
        if not os.path.exists(sample_path):
            self.log(
                'error',
                'The file does not exists at path {0}'.format(sample_path))
            return

        try:
            if self.daemon.ping():
                with open(sample_path, 'rb') as fd:
                    results = self.daemon.scan_stream(fd.read())
            else:
                self.log('error', "Unable to connect to the daemon")
        except Exception as ex:
            msg = 'Unable to scan file {0} with antivirus daemon, {1}'.format(
                sample.sha256, ex)
            self.log('error', msg)
            return

        found = None
        name = None

        if results:
            for item in results:
                found = results[item][0]
                name = results[item][1]

        if found == 'ERROR':
            self.log(
                'error',
                "Check permissions of the binary folder, {0}".format(name))
        else:
            if name is not None:
                if self.args.tag:
                    self.db.add_tags(sample.sha256, name)
            else:
                name = 'Threat not found!'

            self.log(
                'info',
                "{0} identify {1} as : {2}".format(self.socket, sample.sha256,
                                                   name))
Esempio n. 16
0
class ClamAV(Module):
    cmd = 'clamav'
    description = 'Scan file from local ClamAV daemon'
    authors = ['neriberto']

    def __init__(self):
        super(ClamAV, self).__init__()
        self.parser.add_argument('-s', '--socket', help='Specify an unix socket (default: Clamd Unix Socket)')
        self.parser.add_argument('-a', '--all', action='store_true', help='Scan all files')
        self.parser.add_argument('-t', '--tag', action='store_true', help='Tag file(s) with the signature name when detect as malware')
        self.db = Database()

    def run(self):
        super(ClamAV, self).run()
        if self.args is None:
            return

        if not HAVE_CLAMD:
            self.log('error', "Missing dependency, install pyclamd (`pip install pyclamd`)")
            return

        if not self.Connect():
            self.log('error', 'Daemon is not responding!')
            return

        if not __sessions__.is_set():
            if self.args.all:
                self.ScanAll()
            else:
                self.log('error', 'No open session')
        else:
            self.ScanFile(__sessions__.current.file.sha256)

    def ScanAll(self):
        samples = self.db.find(key='all')
        for sample in samples:
            if sample.size == 0:
                continue
            self.ScanFile(sample.sha256)

    def Connect(self):
        self.daemon = None
        self.socket = self.args.socket
        try:
            if self.socket is not None:
                self.daemon = pyclamd.ClamdUnixSocket(self.socket)
                self.log('info', 'Using socket {0} to scan'.format(self.socket))
            else:
                self.daemon = pyclamd.ClamdUnixSocket()
                self.socket = 'Clamav'

            return self.daemon.ping()
        except Exception as ex:
            msg = 'Daemon connection failure, {0}'.format(ex)
            self.log('error,', msg)
            return False

    def ScanFile(self, sha256):
        if sha256 is not None:
            filepath = get_sample_path(sha256)

        if not os.path.exists(filepath):
            self.log('error', 'The file does not exists at path {0}'.format(filepath))
            return

        try:
            if self.daemon.ping():
                with open(filepath, 'r') as fd:
                    results = self.daemon.scan_stream(fd.read())
            else:
                self.log('error', "Unable to connect to the daemon")
        except Exception as ex:
            msg = 'Unable to scan file {0} with antivirus daemon, {1}'.format(sha256, ex)
            self.log('error', msg)
            return

        found = None
        name = None

        if results:
            for item in results:
                found = results[item][0]
                name = results[item][1]

        if found == 'ERROR':
            self.log('error', "Check permissions of the binary folder, {0}".format(name))
        else:
            if name is not None:
                if self.args.tag:
                    self.db.add_tags(sha256, name)
            else:
                name = 'Threat not found!'

            self.log('info', "{0} identify {1} as : {2}".format(self.socket, sha256, name))
Esempio n. 17
0
    def scan(self):
        def usage():
            print("usage: yara scan [-a]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print(
                "\t--rule (-r)\tSpecify a ruleset file path (default will run data/yara/index.yara)"
            )
            print(
                "\t--all (-a)\tScan all stored files (default if no session is open)"
            )
            print("\t--tag (-t)\tTag Files with Rule Name (default is not to)")
            print("")

        def string_printable(line):
            line = str(line)
            new_line = ''
            for c in line:
                if c in printstring.printable:
                    new_line += c
                else:
                    new_line += '\\x' + c.encode('hex')
            return new_line

        # This means users can just drop or remove rule files without
        # having to worry about maintaining the index.
        # TODO: make paths absolute.
        # TODO: this regenerates the file at every run, perhaps we
        # could find a way to optimize this.
        def rule_index():
            with open('data/yara/index.yara', 'w') as rules_index:
                for rule_file in os.listdir('data/yara'):
                    # Skip if the extension is not right, could cause problems.
                    if not rule_file.endswith(
                            '.yar') and not rule_file.endswith('.yara'):
                        continue
                    # Skip if it's the index itself.
                    if rule_file == 'index.yara':
                        continue

                    # Add the rule to the index.
                    line = 'include "{0}"\n'.format(rule_file)
                    rules_index.write(line)

            return 'data/yara/index.yara'

        arg_rule = ''
        arg_scan_all = False
        arg_tag = False

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hr:at',
                                       ['help', 'rule=', 'all', 'tag'])
        except getopt.GetoptError as e:
            print(e)
            return

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            if opt in ('-t', '--tag'):
                arg_tag = True
            elif opt in ('-r', '--rule'):
                arg_rule = value
            elif opt in ('-a', '--all'):
                arg_scan_all = True

        # If no custom ruleset is specified, we use the default one.
        if not arg_rule:
            arg_rule = rule_index()

        # Check if the selected ruleset actually exists.
        if not os.path.exists(arg_rule):
            print_error("No valid Yara ruleset at {0}".format(arg_rule))
            return

        # Compile all rules from given ruleset.
        rules = yara.compile(arg_rule)
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            print_info("Scanning all stored files...")

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

            for sample in samples:
                files.append(sample)

        for entry in files:
            if entry.size == 0: continue
            print_info("Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, 'path'):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            rows = []
            tag_list = []
            for match in rules.match(entry_path):
                # Add a row for each string matched by the rule.
                for string in match.strings:
                    rows.append([
                        match.rule,
                        string_printable(string[1]),
                        string_printable(string[0]),
                        string_printable(string[2])
                    ])

                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get('tags')
                # If not, use the rule name.
                # TODO: as we add more and more yara rules, we might remove
                # this option and only tag the file with rules that had
                # tags specified in them.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if rows:
                header = ['Rule', 'String', 'Offset', 'Content']
                print(table(header=header, rows=rows))

            # If we selected to add tags do that now.
            if rows and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    print_info("Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 18
0
    def cmd_tags(self, *args):
        def usage():
            print("usage: tags [-h] [-a=tags] [-d=tag]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print("\t--add (-a)\tAdd tags to the opened file (comma separated)")
            print("\t--delete (-d)\tDelete a tag from the opened file")
            print("")

        try:
            opts, argv = getopt.getopt(args, "ha:d:", ["help", "add=", "delete="])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_add = None
        arg_delete = None

        for opt, value in opts:
            if opt in ("-h", "--help"):
                help()
                return
            elif opt in ("-a", "--add"):
                arg_add = value
            elif opt in ("-d", "--delete"):
                arg_delete = value

        # This command requires a session to be opened.
        if not __sessions__.is_set():
            print_error("No session opened")
            return

        # If no arguments are specified, there's not much to do.
        # However, it could make sense to also retrieve a list of existing
        # tags from this command, and not just from the "find" command alone.
        if not arg_add and not arg_delete:
            usage()
            return

        # TODO: handle situation where addition or deletion of a tag fail.

        if arg_add:
            # Add specified tags to the database's entry belonging to
            # the opened file.
            db = Database()
            db.add_tags(__sessions__.current.file.sha256, arg_add)
            print_info("Tags added to the currently opened file")

            # We refresh the opened session to update the attributes.
            # Namely, the list of tags returned by the "info" command
            # needs to be re-generated, or it wouldn't show the new tags
            # until the existing session is closed a new one is opened.
            print_info("Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)

        if arg_delete:
            # Delete the tag from the database.
            Database().delete_tag(arg_delete)
            # Refresh the session so that the attributes of the file are
            # updated.
            print_info("Refreshing session to update attributes...")
            __sessions__.new(__sessions__.current.file.path)
Esempio n. 19
0
    def scan(self):
        def usage():
            self.log('', "usage: yara scan [-a]")

        def help():
            usage()
            self.log('', "")
            self.log('', "Options:")
            self.log('', "\t--help (-h)\tShow this help message")
            self.log('', "\t--rule (-r)\tSpecify a ruleset file path (default will run data/yara/index.yara)")
            self.log('', "\t--all (-a)\tScan all stored files (default if no session is open)")
            self.log('', "\t--tag (-t)\tTag Files with Rule Name (default is not to)")
            self.log('', "")

        def string_printable(line):
            line = str(line)
            new_line = ''
            for c in line:
                if c in printstring.printable:
                    new_line += c
                else:
                    new_line += '\\x'+c.encode('hex')
            return new_line

        # This means users can just drop or remove rule files without
        # having to worry about maintaining the index.
        # TODO: make paths absolute.
        # TODO: this regenerates the file at every run, perhaps we
        # could find a way to optimize this.
        def rule_index():
            with open('data/yara/index.yara', 'w') as rules_index:
                for rule_file in os.listdir('data/yara'):
                    # Skip if the extension is not right, could cause problems.
                    if not rule_file.endswith('.yar') and not rule_file.endswith('.yara'):
                        continue
                    # Skip if it's the index itself.
                    if rule_file == 'index.yara':
                        continue

                    # Add the rule to the index.
                    line = 'include "{0}"\n'.format(rule_file)
                    rules_index.write(line)

            return 'data/yara/index.yara'

        arg_rule = ''
        arg_scan_all = False
        arg_tag = False

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hr:at', ['help', 'rule=', 'all', 'tag'])
        except getopt.GetoptError as e:
            self.log('', e)
            return

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            if opt in ('-t', '--tag'):
                arg_tag = True
            elif opt in ('-r', '--rule'):
                arg_rule = value
            elif opt in ('-a', '--all'):
                arg_scan_all = True


        # If no custom ruleset is specified, we use the default one.
        if not arg_rule:
            arg_rule = rule_index()

        # Check if the selected ruleset actually exists.
        if not os.path.exists(arg_rule):
            self.log('error', "No valid Yara ruleset at {0}".format(arg_rule))
            return

        # Compile all rules from given ruleset.
        rules = yara.compile(arg_rule)
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            self.log('info', "Scanning all stored files...")

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

            for sample in samples:
                files.append(sample)

        for entry in files:
            if entry.size == 0: continue
            self.log('info', "Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, 'path'):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            rows = []
            tag_list = []
            for match in rules.match(entry_path):
                # Add a row for each string matched by the rule.
                for string in match.strings:
                    rows.append([match.rule, string_printable(string[1]), string_printable(string[0]), string_printable(string[2])])

                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get('tags')
                # If not, use the rule name.
                # TODO: as we add more and more yara rules, we might remove
                # this option and only tag the file with rules that had
                # tags specified in them.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if rows:
                header = [
                    'Rule',
                    'String',
                    'Offset',
                    'Content'
                ]
                self.log('table', dict(header=header, rows=rows))

            # If we selected to add tags do that now.
            if rows and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    self.log('info', "Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 20
0
    def scan(self):
        arg_rule = self.args.rule
        arg_scan_all = self.args.all
        arg_tag = self.args.tag
        arg_verbose = self.args.verbose

        externals = {'filename': '', 'filepath': '', 'extension': '', 'filetype': ''}

        # If a rule file is specified we compile that, otherwise all
        # the rules we have stored locally.
        if arg_rule:
            # Check if the selected ruleset actually exists.
            if not os.path.exists(arg_rule):
                self.log('error', "The specified file does not exist at path {0}".format(arg_rule))
                return

            rules = yara.compile(arg_rule, externals=externals)
        # Otherwise, we get all the rules that are stored locally and we
        # load them in different namespaces.
        else:
            filepaths = dict()
            for rule in self._get_rules():
                # TODO: We pre-compile all rules individually to check whether they are
                # loadable or not. This is pretty hacky, there must be a better way.
                try:
                    yara.compile(rule[1], externals=externals)
                except yara.SyntaxError as e:
                    self.log('warning', "Unable to compile rule {0}: {1}".format(rule[1], e))
                    continue

                filepaths['namespace' + str(rule[0])] = rule[1]

            rules = yara.compile(filepaths=filepaths, externals=externals, includes=False)

        # Files to scan.
        files = []

        # If there is a session open and the user didn't specifically
        # request to scan the full repository, we just add the currently
        # opened file's path.
        if __sessions__.is_set() and not arg_scan_all:
            files.append(__sessions__.current.file)
        # Otherwise we loop through all files in the repository and queue
        # them up for scan.
        else:
            self.log('info', "Scanning all stored files (in the current project)...")

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

            for sample in samples:
                files.append(sample)

        # Loop through all files to be scanned.
        for entry in files:
            if entry.size == 0:
                continue

            self.log('info', "Scanning {0} ({1})".format(entry.name, entry.sha256))

            # Check if the entry has a path attribute. This happens when
            # there is a session open. We need to distinguish this just for
            # the cases where we're scanning an opened file which has not been
            # stored yet.
            if hasattr(entry, 'path'):
                entry_path = entry.path
            # This should be triggered only when scanning the full repository.
            else:
                entry_path = get_sample_path(entry.sha256)

            # Check if the file exists before running the yara scan.
            if not os.path.exists(entry_path):
                self.log('error', "The file does not exist at path {0}".format(entry_path))
                continue

            rows = []
            tag_list = []
            found = False

            # We need this just for some Yara rules.
            try:
                ext = os.path.splitext(entry.name)[1]
            except Exception:
                ext = ''

            try:
                matches = rules.match(entry_path, externals={'filename': entry.name, 'filepath': entry_path, 'extension': ext, 'filetype': entry.type})
            except yara.Error as e:
                self.log('error', "Yara scan for file {} ({}) failed: {}".format(entry.name, entry.sha256, e))
                continue

            for match in matches:
                found = True
                # Add a row for each string matched by the rule.
                if arg_verbose:
                    for match_string in match.strings:
                        rows.append([
                            match.rule,
                            string_printable(match_string[1]),
                            string_printable(match_string[0]),
                            string_printable(match_string[2])]
                        )
                else:
                    self.log('item', match.rule)
                # Add matching rules to our list of tags.
                # First it checks if there are tags specified in the metadata
                # of the Yara rule.
                match_tags = match.meta.get('tags')
                # If not, use the rule name.
                # TODO: as we add more and more yara rules, we might remove
                # this option and only tag the file with rules that had
                # tags specified in them.
                if not match_tags:
                    match_tags = match.rule

                # Add the tags to the list.
                tag_list.append([entry.sha256, match_tags])

            if arg_verbose and rows:
                header = [
                    'Rule',
                    'String',
                    'Offset',
                    'Content'
                ]
                self.log('table', dict(header=header, rows=rows))
            # If we selected to add tags do that now.
            if found and arg_tag:
                db = Database()
                for tag in tag_list:
                    db.add_tags(tag[0], tag[1])

                # If in a session reset the session to see tags.
                if __sessions__.is_set() and not arg_scan_all:
                    self.log('info', "Refreshing session to update attributes...")
                    __sessions__.new(__sessions__.current.file.path)
Esempio n. 21
0
    def cmd_tags(self, *args):
        def usage():
            print("usage: tags [-h] [-a=tags] [-d=tag]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print("\t--add (-a)\tAdd tags to the opened file (comma separated)")
            print("\t--delete (-d)\tDelete a tag from the opened file")
            print("")

        try:
            opts, argv = getopt.getopt(args, 'ha:d:', ['help', 'add=', 'delete='])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_add = None
        arg_delete = None

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-a', '--add'):
                arg_add = value
            elif opt in ('-d', '--delete'):
                arg_delete = value

        # This command requires a session to be opened.
        if not __session__.is_set():
            print_error("No session opened")
            return

        # If no arguments are specified, there's not much to do.
        # However, it could make sense to also retrieve a list of existing
        # tags from this command, and not just from the "find" command alone.
        if not arg_add and not arg_delete:
            print_error("You need to specify an option, either add or delete")
            return

        if arg_add:
            # Add specified tags to the database's entry belonging to
            # the opened file.
            db = Database()
            db.add_tags(__session__.file.sha256, arg_add)
            print_info("Tags added to the currently opened file")

            # We refresh the opened session to update the attributes.
            # Namely, the list of tags returned by the "info" command
            # needs to be re-generated, or it wouldn't show the new tags
            # until the existing session is closed a new one is opened.
            print_info("Refreshing session to update attributes...")
            __session__.set(__session__.file.path)

        if arg_delete:
            # TODO
            pass