Exemple #1
0
def rules_to_highlighted_string(rules: List[Rule]):
    yb = YaraBuilder()
    for rule in rules:
        if rule.name not in yb.yara_rules.keys():
            rule.add_to_yarabuilder(yb)
    # As there is no yara lexer available in pygments, we're usign python here.
    return Syntax(yb.build_rules(), "python", background_color="default")
Exemple #2
0
def export(name: str, tag: str, single: bool, path: str):
    c, ec = Console(), Console(stderr=True, style="bold red")
    session = get_session()
    rules, count = filter_rules_by_name_and_tag(name, tag, session)

    if count == 0:
        ec.print(f"Found no matching rules.")
        exit(-1)

    if single and os.path.isdir(path):
        ec.print(f"Given path ({path}) is a directory.")
        exit(-1)

    yb = YaraBuilder()
    for rule in rules:
        rule.add_to_yarabuilder(yb)

        if not single:
            with io.open(os.path.join(path, rule.name + ".yar"), "w") as fh:
                fh.write(yb.build_rule(rule.name))

    if single:
        with io.open(path, "w") as fh:
            fh.write(yb.build_rules())

    c.print(f"Wrote {len(rules)} rules.")
Exemple #3
0
def get(raw: bool, identifier: str):
    c = Console()
    session = get_session()
    ruleset = get_ruleset_by_identifier(identifier, session)
    if not ruleset:
        c.print("Ruleset not found.")
        exit(-1)

    if not raw:
        c.print(rules_to_table(ruleset.rules))
    else:
        yb = YaraBuilder()
        for rule in ruleset.rules:
            rule.add_to_yarabuilder(yb)
        c.print(yb.build_rules())
Exemple #4
0
def edit(identifier: Union[int, str]):
    c, ec = Console(), Console(file=stderr, style="bold red")
    session = get_session()
    rule = get_rule_by_identifier(identifier, session)
    if len(rule) > 1:
        ec.print(f"Found more than one rule.")
        exit(-1)
    rule = rule[0]
    yb = YaraBuilder()
    rule.add_to_yarabuilder(yb)
    path, _ = write_ruleset_to_tmp_file(yb)
    hash = get_md5(path)
    open_file(path, f"{rule.name} opened in external editor...")
    edit_hash = get_md5(path)

    if hash == edit_hash:
        c.print(f"No change detected...")
    else:
        c.print(f"Change detected, updating rule...")
        edited_rule = read_rulefile(path)
        if not 0 < len(edited_rule) < 2:
            ec.print("Edited rule file must contain exactly one yara rule.")
            exit(-1)
        rule.name = edited_rule[0].get("rule_name", "Unnamed rule")
        rule.meta = plyara_object_to_meta(edited_rule[0])
        rule.imports = plyara_object_to_imports(edited_rule[0])
        rule.strings = plyara_object_to_strings(edited_rule[0])
        rule.tags = plyara_object_to_tags(edited_rule[0], session)
        rule.condition = plyara_object_to_condition(edited_rule[0])
        rule.ruleset = plyara_object_to_ruleset(edited_rule[0], session)
        session.commit()
    os.remove(path)
Exemple #5
0
def get(identifier, output):
    c = Console()
    rules = get_rule_by_identifier(identifier)
    if len(rules) == 0:
        c.print("Query returned empty list of Rules.")
        exit(-1)

    yb = YaraBuilder()
    _ = [rule.add_to_yarabuilder(yb) for rule in rules]

    if output and len(output) > 0:
        with io.open(output, "w") as fh:
            fh.write(yb.build_rules())
            exit(0)

    # Simple print because rich.Console adjusts to terminal size and might cut something or mess with the format for
    # readability
    print(yb.build_rules())
Exemple #6
0
def scan(tag: Tuple[str], exclude_tag: Tuple[str], name: str, timeout: int, no_progress: bool, csv: bool,
         recursive: bool, paths: List[str]):
    c, ec = Console(), Console(style="bold red", stderr=True)
    if len(paths) == 0:
        with click.Context(scan) as ctx:
            c.print(scan.get_help(ctx))
            exit(-1)
    session = get_session()
    rules, count = filter_rules_by_name_and_tag(name, tag, exclude_tag, session)
    if count == 0:
        ec.print("No rules matching your criteria.")
        exit(-1)

    yb = YaraBuilder()
    for rule in rules:
        rule.add_to_yarabuilder(yb)
    ruleset_path, _ = write_ruleset_to_tmp_file(yb)

    # Initialize external parameter filename as empty string. This will be filled during matching files.
    ruleset_compiled = yara.compile(ruleset_path, externals={
        "filename": ""
    })
    if not no_progress:
        c.print(f"Using ruleset {ruleset_path} for scanning. Check the rule file in case any error shows up.")
    if recursive:
        list_of_files = []
        for path in paths:
            list_of_files.extend(get_dir_recursive(path))
        paths = list_of_files
    with Progress() if not no_progress else c as prog:
        if isinstance(prog, Progress):
            t1 = prog.add_task("Scanning...", total=len(paths))
        for path in paths:
            if isinstance(prog, Progress):
                prog.update(t1, advance=1, description=f"Scanning {path}...")
            if os.path.isdir(path):
                continue
            try:
                # Check if file matches. This also adds the basename as filename parameter.
                matches = ruleset_compiled.match(path, timeout=timeout, externals={
                    "filename": os.path.basename(path)
                })
            except yara.TimeoutError:
                prog.print(Text("Timed out!", style="bold red"))
                if isinstance(prog, Progress):
                    prog.update(t1, description="Timed out!")
                exit(-1)
            for match in matches:
                if csv:
                    prog.print(f'"{match.rule}","{",".join(match.tags)}","{path}"')
                else:
                    prog.print(f"{match.rule} ({', '.join(match.tags)}): {path}", highlight=not no_progress)
        if isinstance(prog, Progress):
            prog.update(t1, description="Finished scanning!")
    os.remove(ruleset_path)
Exemple #7
0
def write_ruleset_to_file(yb: YaraBuilder, file: Union[int, str]) -> int:
    """Write a ruleset defined by yarabuilder to a given filedescriptor or filepath."""
    text = yb.build_rules()
    if isinstance(file, int):
        with os.fdopen(file, "w") as fh:
            b = fh.write(text)
    else:
        with io.open(file, "w") as fh:
            b = fh.write(text)
    if b <= 0:
        ec = Console(file=stderr)
        ec.print(
            f"ERR: Number of bytes written should be greater 0 but was {b}.")
    return b
Exemple #8
0
def string(raw, query_string):
    c = Console()
    session = get_session()
    strings = session.query(String).filter(String.type == "text").filter(
        String.value.like(query_string)).all()
    if not raw:
        c.print(f"Found {len(strings)} strings.")
        t = Table()
        t.add_column("String")
        t.add_column("ID")
        t.add_column("Rule")
        t.add_column("Tags")
        for string in strings:
            t.add_row(string.value, str(string.rule.id), string.rule.name,
                      ", ".join([tag.name for tag in string.rule.tags]))
        c.print(t)
    else:
        yb = YaraBuilder()
        for string in strings:
            if string.rule.name not in yb.yara_rules.keys():
                string.rule.add_to_yarabuilder(yb)
        syntax = Syntax(yb.build_rules(), "python", background_color="default")
        c.print(syntax)
Exemple #9
0
def scan(tag: str, name: str, timeout: int, no_progress: bool, csv: bool,
         file: List[str]):
    c, ec = Console(), Console(stderr=True)
    if len(file) == 0:
        with click.Context(scan) as ctx:
            c.print(scan.get_help(ctx))
            exit(-1)
    session = get_session()
    rules, count = filter_rules_by_name_and_tag(name, tag, session)
    if count == 0:
        ec.print("No rules matching your criteria.")
        exit(-1)

    yb = YaraBuilder()
    for rule in rules:
        rule.add_to_yarabuilder(yb)
    ruleset_path, _ = write_ruleset_to_tmp_file(yb)
    ruleset_compiled = yara.compile(ruleset_path)
    if not no_progress:
        c.print(
            f"Using ruleset {ruleset_path} for scanning. Check the rule file in case any error shows up."
        )
    with Progress() if not no_progress else c as prog:
        if isinstance(prog, Progress):
            t1 = prog.add_task("Scanning...", total=len(file))
        for path in file:
            if isinstance(prog, Progress):
                prog.update(t1, advance=1, description=f"Scanning {path}...")
            if os.path.isdir(path):
                continue
            try:
                matches = ruleset_compiled.match(path, timeout=timeout)
            except yara.TimeoutError:
                prog.print(Text("Timed out!", style="bold red"))
                if isinstance(prog, Progress):
                    prog.update(t1, description="Timed out!")
                exit(-1)
            for match in matches:
                if csv:
                    prog.print(
                        f'"{match.rule}","{",".join(match.tags)}","{path}"')
                else:
                    prog.print(
                        f"{match.rule} ({', '.join(match.tags)}): {path}",
                        highlight=not no_progress)
        if isinstance(prog, Progress):
            prog.update(t1, description="Finished scanning!")
    os.remove(ruleset_path)
Exemple #10
0
def print_rule(rules: Union[Dict, List]) -> str:
    yb = YaraBuilder()
    if isinstance(rules, dict):
        rules = [rules]
    for rule in rules:
        rn = rule["rule_name"]
        yb.create_rule(rn)
        for mdata in rule.get("metadata", []):
            for k, v in mdata.items():
                yb.add_meta(rn, k, v)
        for tag in rule["tags"]:
            yb.add_tag(rn, tag)
        for yara_string in rule["strings"]:
            s_type = yara_string["type"]
            s_name = yara_string["name"][1:]
            s_val = yara_string["value"]
            s_mod = yara_string.get("modifiers", [])
            if s_type == "text":
                yb.add_text_string(rn, s_val, s_name, s_mod)
            elif s_type == "regex":
                yb.add_regex_string(rn, s_val, s_name, s_mod)
            elif s_type == "byte":
                yb.add_hex_string(rn, s_val[1:-1].strip(), s_name)
        yb.add_condition(rn, " ".join(rule["condition_terms"]))
    return yb.build_rules()
Exemple #11
0
    def add_to_yarabuilder(self, yb: YaraBuilder) -> None:
        """Add the rule object to a given YaraBuilder instance

        >>> rule = Rule(...)
        >>> yb = YaraBuilder()
        >>> rule.add_to_yarabuilder(yb)
        >>> print(yb.build_rules())
        """
        yb.create_rule(self.name)
        key = load_config().get("ruleset_meta_key", "ruleset")
        if self.ruleset:
            yb.add_meta(self.name, key, self.ruleset.name)
        for meta in self.meta:
            yb.add_meta(self.name, meta.key, meta.value)
        for string in self.strings:
            s_name = string.name[1:]
            if string.type == "text":
                yb.add_text_string(self.name, string.value, s_name,
                                   string.modifier_list)
            elif string.type == "byte":
                yb.add_hex_string(
                    self.name,
                    string.value,
                    s_name,
                    string.
                    modifier_list  # Todo: Check hex string modifiers - this list should always be empty?
                )
            elif string.type == "regex":
                yb.add_regex_string(self.name, string.value, s_name,
                                    string.modifier_list)
            else:
                print(f"ERROR: Unknown string type \"{string.type}\".",
                      file=stderr)
        for tag in self.tags:
            yb.add_tag(self.name, tag.name)
        for imp in self.import_list:
            yb.add_import(self.name, imp)
        yb.add_condition(self.name, self.condition.strip())
Exemple #12
0
 def __str__(self):
     yb = YaraBuilder()
     self.add_to_yarabuilder(yb)
     return yb.build_rule(self.name)