Exemple #1
0
def update_available(**_):  # pylint: disable=W0613
    """
    Check if updated signatures are.

    Variables:
    None

    Arguments:
    last_update        => Epoch time of last update.

    Data Block:
    None

    Result example:
    { "update_available" : true }      # If updated rules are available.
    """
    last_update = iso_to_epoch(request.args.get('last_update'))
    last_modified = iso_to_epoch(STORAGE.get_signatures_last_modified())

    return make_api_response({"update_available": last_modified > last_update})
Exemple #2
0
def download_signatures(**kwargs):
    """
    Download signatures from the system.
    
    Variables:
    None 
    
    Arguments: 
    query       => SOLR query to filter the signatures
                   Default: All deployed signatures
    safe        => Get a ruleset that will work in yara
                   Default: False
    
    Data Block:
    None
    
    Result example:
    <A .YAR SIGNATURE FILE>
    """
    user = kwargs['user']
    query = request.args.get('query', 'meta.al_status:DEPLOYED')

    safe = request.args.get('safe', "false")
    if safe.lower() == 'true':
        safe = True
    else:
        safe = False

    access = user['access_control']
    last_modified = STORAGE.get_signatures_last_modified()

    query_hash = md5(query + access + last_modified).hexdigest() + ".yar"

    signature_cache = TransportLocal(
        base=os.path.join(config.system.root, 'var', 'cache', 'signatures')
    )

    response = _get_cached_signatures(
        signature_cache, last_modified, query_hash
    )

    if response:
        return response

    with ExclusionWindow(query_hash, 30):
        response = _get_cached_signatures(
            signature_cache, last_modified, query_hash
        )
        if response:
            return response

        keys = STORAGE.list_filtered_signature_keys(query, access_control=access)
        signature_list = STORAGE.get_signatures(keys)
    
        # Sort rules to satisfy dependencies
        duplicate_rules = []
        error_rules = []
        global_rules = []
        private_rules_no_dep = []
        private_rules_dep = []
        rules_no_dep = []
        rules_dep = []

        if safe:
            rules_map = {}
            for s in signature_list:
                name = s.get('name', None)
                if not name:
                    continue

                version = int(s.get('meta', {}).get('rule_version', '1'))

                p = rules_map.get(name, {})
                pversion = int(p.get('meta', {}).get('rule_version', '0'))

                if version < pversion:
                    duplicate_rules.append(name)
                    continue
 
                rules_map[name] = s
            signature_list = rules_map.values()

        name_map = {}
        for s in signature_list:
            if s['type'].startswith("global"):
                global_rules.append(s)
                name_map[s['name']] = True
            elif s['type'].startswith("private"):
                if s['depends'] is None or len(s['depends']) == 0:
                    private_rules_no_dep.append(s)
                    name_map[s['name']] = True
                else:
                    private_rules_dep.append(s)
            else:
                if s['depends'] is None or len(s['depends']) == 0:
                    rules_no_dep.append(s)
                    name_map[s['name']] = True
                else:
                    rules_dep.append(s)

        global_rules = sorted(global_rules, key=lambda k: k['meta']['id'])
        private_rules_no_dep = sorted(private_rules_no_dep, key=lambda k: k['meta']['id'])
        rules_no_dep = sorted(rules_no_dep, key=lambda k: k['meta']['id'])
        private_rules_dep = sorted(private_rules_dep, key=lambda k: k['meta']['id'])
        rules_dep = sorted(rules_dep, key=lambda k: k['meta']['id'])
    
        signature_list = global_rules + private_rules_no_dep
        while private_rules_dep:
            new_private_rules_dep = []
            for r in private_rules_dep:
                found = False
                for d in r['depends']:
                    if not name_map.get(d, False):
                        new_private_rules_dep.append(r)
                        found = True
                        break
                if not found:
                    name_map[r['name']] = True
                    signature_list.append(r)
            
            if private_rules_dep == new_private_rules_dep:
                for x in private_rules_dep:
                    error_rules += [d for d in x["depends"]]

                if not safe:
                    for s in private_rules_dep:
                        name_map[s['name']] = True
                    signature_list += private_rules_dep

                new_private_rules_dep = []
            
            private_rules_dep = new_private_rules_dep

        signature_list += rules_no_dep
        while rules_dep:
            new_rules_dep = []
            for r in rules_dep:
                found = False
                for d in r['depends']:
                    if not name_map.get(d, False):
                        new_rules_dep.append(r)
                        found = True
                        break
                if not found:
                    name_map[r['name']] = True
                    signature_list.append(r)
        
            if rules_dep == new_rules_dep:
                error_rules += [x["name"] for x in rules_dep]
                if not safe:
                    for s in rules_dep:
                        name_map[s['name']] = True
                    signature_list += rules_dep

                new_rules_dep = []

            rules_dep = new_rules_dep    
        # End of sort
    
        error = ""
        if duplicate_rules:
            if safe:
                err_txt = "were skipped"
            else:
                err_txt = "exist"
            error += dedent("""\
            
                // [ERROR] Duplicates rules {msg}:
                //
                //	{rules}
                //
                """).format(msg=err_txt, rules="\n//\t".join(duplicate_rules))
        if error_rules:
            if safe:
                err_txt = "were skipped due to"
            else:
                err_txt = "are"
            error += dedent("""\
            
                // [ERROR] Some rules {msg} missing dependencies:
                //
                //	{rules}
                //
                """).format(msg=err_txt, rules="\n//\t".join(error_rules))
        # noinspection PyAugmentAssignment

        header = dedent("""\
            // Signatures last updated: {last_modified}
            // Signatures matching filter:
            //
            //	{query}
            // {error}
            // Number of rules in file:
            //
            """).format(query=query, error=error, last_modified=last_modified)

        rule_file_bin = header + YARA_PARSER().dump_rule_file(signature_list)
        rule_file_bin = rule_file_bin

        signature_cache.save(query_hash, rule_file_bin)

        return make_file_response(
            rule_file_bin, "al_yara_signatures.yar",
            len(rule_file_bin), content_type="text/yara"
        )