Esempio n. 1
0
def decide_cwd(cwd=None, exists=False):
    """Decides and sets the CWD, optionally checks if it's a valid CWD."""
    if not cwd:
        cwd = os.environ.get("CUCKOO_CWD")

    if not cwd:
        cwd = os.environ.get("CUCKOO")

    if not cwd and os.path.exists(".cwd"):
        cwd = "."

    if not cwd:
        cwd = "~/.cuckoo"

    dirpath = os.path.abspath(os.path.expanduser(cwd))
    if exists:
        if not os.path.exists(dirpath):
            raise CuckooStartupError(
                "Unable to start this Cuckoo command as the provided CWD (%r) "
                "is not present!" % dirpath
            )

        if not os.path.exists(os.path.join(dirpath, ".cwd")):
            raise CuckooStartupError(
                "Unable to start this Cuckoo command as the provided CWD (%r) "
                "is not a proper CWD!" % dirpath
            )

    set_cwd(dirpath, raw=cwd)
    return dirpath
Esempio n. 2
0
    def create_mappings(cls):
        mappings = {
            cls.DIARY_INDEX: {
                "file": "massurl-diary.json",
                "name": cls.DIARY_MAPPING
            },
            cls.REQUEST_LOG_INDEX: {
                "file": "massurl-requestlog.json",
                "name": cls.REQUEST_LOG_MAPPING
            }
        }
        for indexname, info in mappings.iteritems():
            mapping_path = cwd("elasticsearch", info.get("file"))

            if elasticmassurl.client.indices.exists_type(
                    index=indexname, doc_type=info.get("name")):
                continue

            if not os.path.exists(mapping_path):
                raise CuckooStartupError(
                    "Missing required Elasticsearch mapping file: '%s'" %
                    mapping_path)

            try:
                with open(mapping_path, "rb") as fp:
                    mapping = json.loads(fp.read())
            except ValueError as e:
                raise CuckooStartupError(
                    "Failed to load Elasticsearch mapping '%s'."
                    " Invalid JSON. %s" % (mapping_path, e))

            log.info("Creating index and mapping for '%s'", indexname)
            elasticmassurl.client.indices.create(indexname, body=mapping)
Esempio n. 3
0
def init_yara(index):
    """Initialize & load/compile Yara rules."""
    if not HAVE_YARA:
        log.warning("Unable to import yara (please compile from sources)")
        return

    if index:
        index_yara()

    for category in ("binaries", "urls", "memory"):
        rulepath = cwd("yara", "index_%s.yar" % category)
        if not os.path.exists(rulepath) and not index:
            raise CuckooStartupError(
                "You must run the Cuckoo daemon before being able to run "
                "this utility, as otherwise any potentially available Yara "
                "rules will not be taken into account (yes, also if you "
                "didn't configure any Yara rules)!"
            )

        try:
            File.yara_rules[category] = yara.compile(rulepath)
        except yara.Error as e:
            raise CuckooStartupError(
                "There was a syntax error in one or more Yara rules: %s" % e
            )
Esempio n. 4
0
def init_rooter():
    """If required, check if the rooter is running and if we can connect
    to it. The default configuration doesn't require the rooter to be ran."""
    required = (
        config("routing:routing:route") != "none" or
        config("routing:routing:internet") != "none" or
        config("routing:routing:drop") or
        config("routing:inetsim:enabled") or
        config("routing:tor:enabled") or
        config("routing:vpn:enabled")
    )
    if not required:
        return

    s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)

    try:
        s.connect(config("cuckoo:cuckoo:rooter"))
    except socket.error as e:
        if e.strerror == "No such file or directory":
            raise CuckooStartupError(
                "The rooter is required but it is either not running or it "
                "has been configured to a different Unix socket path. Please "
                "refer to the documentation on working with the rooter."
            )

        if e.strerror == "Connection refused":
            raise CuckooStartupError(
                "The rooter is required but we can't connect to it as the "
                "rooter is not actually running. Please refer to the "
                "documentation on working with the rooter."
            )

        if e.strerror == "Permission denied":
            raise CuckooStartupError(
                "The rooter is required but we can't connect to it due to "
                "incorrect permissions. Did you assign it the correct group? "
                "Please refer to the documentation on working with the "
                "rooter."
            )

        raise CuckooStartupError("Unknown rooter error: %s" % e)

    # Do not forward any packets unless we have explicitly stated so.
    rooter("forward_drop")

    # Enable stateful connection tracking (but only once).
    rooter("state_disable")
    rooter("state_enable")
Esempio n. 5
0
 def throw():
     raise CuckooStartupError(
         "The binaries used for Windows analysis are updated regularly, "
         "independently from the release line. It appears that you're "
         "not up-to-date. This may happen when you've just installed the "
         "latest development version of Cuckoo or when you've updated "
         "to the latest Cuckoo. In order to get up-to-date, please run "
         "the following command: `cuckoo community`.")
Esempio n. 6
0
def check_configs():
    """Checks if config files exist.
    @raise CuckooStartupError: if config files do not exist.
    """
    configs = (
        "auxiliary", "cuckoo", "memory", "processing", "reporting", "routing",
    )

    for filename in configs:
        if not os.path.exists(cwd("conf", "%s.conf" % filename)):
            raise CuckooStartupError(
                "Config file does not exist at path: %s" %
                cwd("conf", "%s.conf" % filename)
            )

        check_specific_config(filename)

    # Also check the specific machinery handler for this instance.
    machinery = config("cuckoo:cuckoo:machinery")
    if machinery not in Config.configuration:
        raise CuckooStartupError(
            "An unknown machinery has been chosen (machinery=%s)!" % machinery
        )

    check_specific_config(machinery)

    # If Cuckoo Feedback is enabled, ensure its configuration is valid.
    feedback_enabled = (
        config("cuckoo:feedback:enabled") or
        config("reporting:feedback:enabled")
    )
    if feedback_enabled:
        try:
            CuckooFeedbackObject(
                name=config("cuckoo:feedback:name"),
                email=config("cuckoo:feedback:email"),
                company=config("cuckoo:feedback:company"),
                message="startup"
            ).validate()
        except CuckooFeedbackError as e:
            raise CuckooStartupError(
                "You have filled out the Cuckoo Feedback configuration, but "
                "there's an error in it: %s" % e
            )
    return True
Esempio n. 7
0
def init_yara():
    """Initialize & load/compile Yara rules."""
    log.debug("Initializing Yara...")
    for category in ("binaries", "urls", "memory", "scripts", "shellcode"):
        dirpath = cwd("yara", category)
        if not os.path.exists(dirpath):
            log.warning("Missing Yara directory: %s?", dirpath)
            continue

        rules, indexed = {}, []
        for dirpath, dirnames, filenames in os.walk(dirpath, followlinks=True):
            for filename in filenames:
                if not filename.endswith((".yar", ".yara")):
                    continue

                filepath = os.path.join(dirpath, filename)

                try:
                    # TODO Once Yara obtains proper Unicode filepath support we
                    # can remove this check. See also this Github issue:
                    # https://github.com/VirusTotal/yara-python/issues/48
                    assert len(str(filepath)) == len(filepath)
                except (UnicodeEncodeError, AssertionError):
                    log.warning(
                        "Can't load Yara rules at %r as Unicode filepaths are "
                        "currently not supported in combination with Yara!",
                        filepath)
                    continue

                rules["rule_%s_%d" % (category, len(rules))] = filepath
                indexed.append(filename)

        try:
            File.yara_rules[category] = yara.compile(filepaths=rules)
        except yara.Error as e:
            raise CuckooStartupError(
                "There was a syntax error in one or more Yara rules: %s" % e)

        indexed = sorted(indexed)
        for entry in indexed:
            if (category, entry) == indexed[-1]:
                log.debug("\t `-- %s %s", category, entry)
            else:
                log.debug("\t |-- %s %s", category, entry)
Esempio n. 8
0
def init_routing():
    """Initialize and check whether the routing information is correct."""
    interfaces = set()

    # Check if all configured VPNs exist and are up and enable NAT on
    # each VPN interface.
    if config("routing:vpn:enabled"):
        for name in config("routing:vpn:vpns"):
            entry = config2("routing", name)
            if not rooter("nic_available", entry.interface):
                raise CuckooStartupError(
                    "The network interface that has been configured for "
                    "VPN %s is not available." % entry.name)

            if not rooter("rt_available", entry.rt_table):
                raise CuckooStartupError(
                    "The routing table that has been configured for "
                    "VPN %s is not available." % entry.name)

            interfaces.add((entry.rt_table, entry.interface))

    standard_routes = "none", "drop", "internet", "inetsim", "tor"

    # Check whether the default VPN exists if specified.
    if config("routing:routing:route") not in standard_routes:
        if config("routing:routing:route") not in config("routing:vpn:vpns"):
            raise CuckooStartupError(
                "The default routing target (%s) has not been configured in "
                "routing.conf, is it supposed to be a VPN?" %
                config("routing:routing:route"))

        if not config("routing:vpn:enabled"):
            raise CuckooStartupError(
                "The default route configured is a VPN, but VPNs have "
                "not been enabled in routing.conf.")

    # Check whether the dirty line exists if it has been defined.
    if config("routing:routing:internet") != "none":
        if not rooter("nic_available", config("routing:routing:internet")):
            raise CuckooStartupError(
                "The network interface that has been configured as dirty "
                "line is not available.")

        if not rooter("rt_available", config("routing:routing:rt_table")):
            raise CuckooStartupError(
                "The routing table that has been configured for dirty "
                "line interface is not available.")

        interfaces.add((config("routing:routing:rt_table"),
                        config("routing:routing:internet")))

    for rt_table, interface in interfaces:
        # Disable & enable NAT on this network interface. Disable it just
        # in case we still had the same rule from a previous run.
        rooter("disable_nat", interface)
        rooter("enable_nat", interface)

        # Populate routing table with entries from main routing table.
        if config("routing:routing:auto_rt"):
            rooter("flush_rttable", rt_table)
            rooter("init_rttable", rt_table, interface)
Esempio n. 9
0
def init_yara():
    """Initialize & load/compile Yara rules."""
    categories = (
        "binaries",
        "urls",
        "memory",
        "scripts",
        "shellcode",
        "dumpmem",
        "office",
    )
    log.debug("Initializing Yara...")
    for category in categories:
        dirpath = cwd("yara", category)
        if not os.path.exists(dirpath):
            log.warning("Missing Yara directory: %s?", dirpath)

        rules, indexed = {}, []
        for dirpath, dirnames, filenames in os.walk(dirpath, followlinks=True):
            for filename in filenames:
                if not filename.endswith((".yar", ".yara")):
                    continue

                filepath = os.path.join(dirpath, filename)

                try:
                    # TODO Once Yara obtains proper Unicode filepath support we
                    # can remove this check. See also this Github issue:
                    # https://github.com/VirusTotal/yara-python/issues/48
                    assert len(str(filepath)) == len(filepath)
                except (UnicodeEncodeError, AssertionError):
                    log.warning(
                        "Can't load Yara rules at %r as Unicode filepaths are "
                        "currently not supported in combination with Yara!",
                        filepath)
                    continue

                rules["rule_%s_%d" % (category, len(rules))] = filepath
                indexed.append(filename)

        # Need to define each external variable that will be used in the
        # future. Otherwise Yara will complain.
        externals = {
            "filename": "",
        }

        try:
            File.yara_rules[category] = yara.compile(filepaths=rules,
                                                     externals=externals)
        except yara.Error as e:
            raise CuckooStartupError(
                "There was a syntax error in one or more Yara rules: %s" % e)

        # The memory.py processing module requires a yara file with all of its
        # rules embedded in it, so create this file to remain compatible.
        if category == "memory":
            f = open(cwd("stuff", "index_memory.yar"), "wb")
            for filename in sorted(indexed):
                f.write('include "%s"\n' % cwd("yara", "memory", filename))

        indexed = sorted(indexed)
        for entry in indexed:
            if (category, entry) == indexed[-1]:
                log.debug("\t `-- %s %s", category, entry)
            else:
                log.debug("\t |-- %s %s", category, entry)

    # Store the compiled Yara rules for the "dumpmem" category in
    # $CWD/stuff/ so that we may pass it along to zer0m0n during analysis.
    File.yara_rules["dumpmem"].save(cwd("stuff", "dumpmem.yarac"))
Esempio n. 10
0
    import volatility.obj as obj
    import volatility.exceptions as exc
    import volatility.plugins.filescan as filescan
    import volatility.protos as protos

    HAVE_VOLATILITY = True

    # Inherit Cuckoo debugging level for Volatility commands.
    rootlogger = logging.getLogger()
    logging.getLogger("volatility.debug").setLevel(rootlogger.level)
    logging.getLogger("volatility.obj").setLevel(rootlogger.level)
    logging.getLogger("volatility.utils").setLevel(rootlogger.level)
except ImportError as e:
    if e.message == "No module named Crypto.Hash":
        raise CuckooStartupError(
            "Could not load Volatility: the PyCrypto package is missing "
            "(install with `pip install pycrypto`)")

    if e.message.startswith("No module named volatility"):
        HAVE_VOLATILITY = False
    else:
        raise
except NameError as e:
    if "distorm3" in e.message:
        raise CuckooStartupError(
            "Could not load Volatility: the distorm3 package is missing "
            "(install with `pip install distorm3`)")
    raise


def s(o):