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
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)
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 )
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")
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`.")
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
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)
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)
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"))
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):