Beispiel #1
0
def parse_operator_and_operand(search_string: str) -> Union[Tuple[Any, Any], None]:
    """Parse a string in the format of "operator operand" and returns the callable and operand string.

    :param search_string: The search string to parse.
    :type search_string: str
    :return: The operator callable and operand parsed from the search string.
    :rtype: Union[Tuple[Any, Any], None]
    """
    NONE_TYPES = ["None", "none", "null", "''", '""', "NULL"]
    try:
        s = search_string.split(" ")
    except AttributeError:
        ERROR(
            "search string '{}' appears to be the wrong data type.".format(
                search_string
            )
        )
        return
    try:
        operator = OPERATOR_MAP(s[0])
        operand = " ".join(s[1:])
    except IndexError:
        ERROR("Did not receive a parseable string! '{}'".format(search_string))
        return
    if operand in NONE_TYPES:
        operand = ""
    return (operator, operand)
Beispiel #2
0
async def run(indicators: dict) -> None:
    """Accept a dict containing events indicators and writes out to the OUTPUT_DIR specified by chirp.common.

    :param indicators: A dict containing parsed network indicator files.
    :type indicators: dict
    """
    if not indicators:
        return

    hits = 0
    CONSOLE("[cyan][NETWORK][/cyan] Entered network plugin.")
    saved_ns = parse_netstat(grab_netstat())
    saved_dns = parse_dns(grab_dns())

    report = {
        indicator["name"]: build_report(indicator)
        for indicator in indicators
    }

    for indicator in indicators:
        try:
            for ioc in indicator["indicator"]["ips"].splitlines():
                if await hunter(saved_ns + ["\n"] + saved_dns, ioc):
                    report[indicator["name"]]["matches"].append(ioc)
                    hits += 1
        except KeyError:
            ERROR("{} appears to be malformed.".format(indicator))
    CONSOLE(
        "[cyan][NETWORK][/cyan] Read {} records, found {} IoC hits.".format(
            len(saved_dns) + len(saved_ns), hits))

    with open(os.path.join(OUTPUT_DIR, "network.json"), "w+") as writeout:
        writeout.write(
            json.dumps({r: report[r]
                        for r in report if report[r]["matches"]}))
Beispiel #3
0
def _str_load(name: str, pkg: Callable,
              discovered_plugins: Dict[str, Callable]) -> None:
    """Load a plugin given the REQUIRED_OS attribute is a string."""
    if OS.lower() in pkg.REQUIRED_OS.lower():
        if _verify_privilege(pkg):
            discovered_plugins[name] = pkg.entrypoint
    else:
        ERROR("{} must be ran on {}".format(name, pkg.REQUIRED_OS))
Beispiel #4
0
def _iter_load(name: str, pkg: Callable,
               discovered_plugins: Dict[str, Callable]) -> None:
    """Load a plugin given the REQUIRED_OS attribute is a list or tuple."""
    if any(OS.lower() in operating_system.lower()
           for operating_system in pkg.REQUIRED_OS):
        if _verify_privilege(pkg):
            discovered_plugins[name] = pkg.entrypoint
    else:
        ERROR("{} must be ran on {}".format(name,
                                            " or ".join(pkg.REQUIRED_OS)))
Beispiel #5
0
def _loader(name: str, discovered_plugins: Dict[str, Callable]) -> None:
    """Load discovered plugins in the ./plugins directory."""
    INFO("Found {}".format(name))
    pkg = importlib.import_module("chirp.plugins.{}".format(name))
    try:
        if not hasattr(pkg.entrypoint, "__call__"):
            raise AttributeError
        try:
            if isinstance(pkg.REQUIRED_OS, str):
                _str_load(name, pkg, discovered_plugins)
            elif isinstance(pkg.REQUIRED_OS, (tuple, list)):
                _iter_load(name, pkg, discovered_plugins)
            else:
                ERROR("Not sure how to interpret REQUIRED_OS for plugin {}".
                      format(name))
        except AttributeError:
            if _verify_privilege(pkg):
                discovered_plugins[name] = pkg.entrypoint
    except AttributeError:
        ERROR("{} does not have a valid entrypoint".format(name))
Beispiel #6
0
def _verify_privilege(plugin: Callable) -> bool:
    """Verify proper privilege for plugin."""
    try:
        admin = plugin.REQUIRED_ADMIN
        if ADMIN or not admin:
            INFO("Loaded {}".format(_parse_name(plugin)))
            return True
        else:
            ERROR("{} must be ran from an admin console.".format(
                _parse_name(plugin)))
            return False
    except AttributeError:
        INFO("Loaded {}".format(_parse_name(plugin)))
        return True
Beispiel #7
0
def OPERATOR_MAP(symbol: str) -> Union[Callable, None]:
    """Map a string to a function for an operator.

    :param symbol: The symbol for an operator.
    :type symbol: str
    :return: The function related to the symbol.
    :rtype: Callable
    """
    d = {
        "==": equals,
        "!=": notequals,
        "~=": regular_expression,
    }
    try:
        return d[symbol]
    except KeyError:
        ERROR("Unknown symbol '{}'.".format(symbol))
Beispiel #8
0
def check_valid_indicator_types(indicator_generator: Iterable[dict],
                                plugins: List[str]) -> Iterator[dict]:
    """Check that an indicator file has a matching plugin and if so yields the indicator.

    :param indicator_generator: A generator to yield parsed indicator files.
    :type indicator_generator: Iterable[dict]
    :param plugins: Names of valid plugins.
    :type plugins: List[str]
    :yield: Valid parsed indicators.
    :rtype: Iterator[dict]
    """
    failed_types = []
    for indicator in indicator_generator:
        if indicator["ioc_type"] in plugins:
            yield indicator
            DEBUG("Loaded {}".format(indicator["name"]))
        else:
            if indicator["ioc_type"] not in failed_types:
                ERROR(
                    """Can't locate plugin "{}". It is possible it has not loaded due to an error."""
                    .format(indicator["ioc_type"]))
            failed_types.append(indicator["ioc_type"])
            continue
Beispiel #9
0
"""Main method for CHIRP (Used when compiled)."""

# Standard Python Libraries
from multiprocessing import freeze_support
import os

# cisagov Libraries
from chirp.common import CONSOLE, ERROR, OUTPUT_DIR, save_log
import chirp.run

if __name__ == "__main__":
    try:
        freeze_support()
        chirp.run.run()
        CONSOLE(
            "[green][+][/green] DONE! Your results can be found in {}.".format(
                os.path.abspath(OUTPUT_DIR)
            )
        )
    except KeyboardInterrupt:
        ERROR("Received an escape sequence. Goodbye.")
    finally:
        save_log()
        input()